summaryrefslogtreecommitdiff
path: root/Build/source/libs/poppler/poppler-0.36.0/poppler
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/poppler/poppler-0.36.0/poppler')
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Annot.cc7276
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Annot.h1609
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Array.cc152
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Array.h84
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFont.cc65
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFont.h55
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFontTables.cc4284
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFontTables.h23
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CMap.cc598
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CMap.h145
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CachedFile.cc257
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CachedFile.h146
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CairoFontEngine.cc832
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CairoFontEngine.h129
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CairoOutputDev.cc3315
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CairoOutputDev.h517
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CairoRescaleBox.cc378
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CairoRescaleBox.h61
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Catalog.cc1142
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Catalog.h272
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CharCodeToUnicode.cc729
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CharCodeToUnicode.h146
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CharTypes.h24
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CompactFontTables.h480
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CurlCachedFile.cc99
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CurlCachedFile.h40
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CurlPDFDocBuilder.cc47
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/CurlPDFDocBuilder.h33
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/DCTStream.cc266
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/DCTStream.h91
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/DateInfo.cc118
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/DateInfo.h35
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Decrypt.cc1417
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Decrypt.h161
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Dict.cc300
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Dict.h112
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Error.cc98
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Error.h60
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/ErrorCodes.h36
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/FileSpec.cc295
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/FileSpec.h76
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/FlateStream.cc128
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/FlateStream.h77
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/FontEncodingTables.cc1824
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/FontEncodingTables.h20
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/FontInfo.cc245
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/FontInfo.h103
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Form.cc1612
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Form.h563
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Function.cc1788
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Function.h258
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Gfx.cc5501
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Gfx.h387
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/GfxFont.cc2620
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/GfxFont.h444
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState.cc7273
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState.h1651
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState_helpers.h82
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParams.cc2031
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParams.h336
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParamsWin.cc598
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Hints.cc452
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Hints.h95
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/JArithmeticDecoder.cc355
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/JArithmeticDecoder.h111
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/JBIG2Stream.cc4292
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/JBIG2Stream.h169
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/JPEG2000Stream.cc448
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/JPEG2000Stream.h55
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/JPXStream.cc3478
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/JPXStream.h338
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Lexer.cc645
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Lexer.h108
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Linearization.cc223
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Linearization.h45
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Link.cc951
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Link.h501
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/LocalPDFDocBuilder.cc46
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/LocalPDFDocBuilder.h33
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Makefile.am317
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/MarkedContentOutputDev.cc212
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/MarkedContentOutputDev.h130
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Movie.cc285
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Movie.h110
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/NameToCharCode.cc116
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/NameToCharCode.h40
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/NameToUnicodeTable.h4484
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Object.cc252
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Object.h373
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/OptionalContent.cc553
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/OptionalContent.h140
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Outline.cc188
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Outline.h89
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/OutputDev.cc201
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/OutputDev.h350
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDoc.cc1955
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDoc.h343
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocBuilder.h42
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocEncoding.cc69
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocEncoding.h34
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocFactory.cc72
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocFactory.h55
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PSOutputDev.cc7565
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PSOutputDev.h546
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PSTokenizer.cc159
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PSTokenizer.h54
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Page.cc860
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Page.h287
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo.cc230
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo.h51
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo_p.h153
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PageTransition.cc138
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PageTransition.h104
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Parser.cc325
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Parser.h82
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PopplerCache.cc163
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PopplerCache.h78
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PreScanOutputDev.cc369
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/PreScanOutputDev.h182
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/ProfileData.cc44
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/ProfileData.h41
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Rendition.cc401
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Rendition.h157
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/SecurityHandler.cc461
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/SecurityHandler.h183
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Sound.cc145
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Sound.h74
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/SplashOutputDev.cc4672
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/SplashOutputDev.h442
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/StdinCachedFile.cc47
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/StdinCachedFile.h27
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/StdinPDFDocBuilder.cc43
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/StdinPDFDocBuilder.h33
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Stream-CCITT.h478
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Stream.cc5388
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/Stream.h1258
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/StructElement.cc1409
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/StructElement.h310
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/StructTreeRoot.cc175
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/StructTreeRoot.h83
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/TextOutputDev.cc5818
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/TextOutputDev.h880
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UTF.cc116
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UTF.h39
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UTF8.h84
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeCClassTables.h1827
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeCompTables.h665
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeDecompTables.h8526
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMap.cc311
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMap.h122
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMapTables.h365
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeTypeTable.cc1223
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeTypeTable.h44
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/ViewerPreferences.cc117
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/ViewerPreferences.h76
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/XRef.cc1740
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/XRef.h281
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/XpdfPluginAPI.cc243
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/XpdfPluginAPI.h342
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/gen-unicode-tables.py38
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/poppler-config.h.cmake195
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/poppler-config.h.in195
-rw-r--r--Build/source/libs/poppler/poppler-0.36.0/poppler/strtok_r.cpp92
163 files changed, 126855 insertions, 0 deletions
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Annot.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Annot.cc
new file mode 100644
index 00000000000..85a8ac4a789
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Annot.cc
@@ -0,0 +1,7276 @@
+//========================================================================
+//
+// Annot.cc
+//
+// Copyright 2000-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
+// Copyright (C) 2007, 2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2007-2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007-2013 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2007, 2008 Iñigo Martínez <inigomartinez@gmail.com>
+// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2008, 2011 Pino Toscano <pino@kde.org>
+// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
+// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
+// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2011, 2013 José Aliste <jaliste@src.gnome.org>
+// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012, 2015 Tobias Koenig <tokoe@kdab.com>
+// Copyright (C) 2013 Peter Breitenlohner <peb@mppmu.mpg.de>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2014 Marek Kasik <mkasik@redhat.com>
+// Copyright (C) 2014 Jiri Slaby <jirislaby@gmail.com>
+// Copyright (C) 2014 Anuj Khare <khareanuj18@gmail.com>
+// Copyright (C) 2015 Petr Gajdos <pgajdos@suse.cz>
+// Copyright (C) 2015 Philipp Reinkemeier <philipp.reinkemeier@offis.de>
+// Copyright (C) 2015 Tamas Szekeres <szekerest@gmail.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+#include <assert.h>
+#include "goo/gmem.h"
+#include "goo/gstrtod.h"
+#include "GooList.h"
+#include "Error.h"
+#include "Object.h"
+#include "Catalog.h"
+#include "Gfx.h"
+#include "Lexer.h"
+#include "PDFDoc.h"
+#include "Page.h"
+#include "Annot.h"
+#include "GfxFont.h"
+#include "CharCodeToUnicode.h"
+#include "PDFDocEncoding.h"
+#include "Form.h"
+#include "Error.h"
+#include "XRef.h"
+#include "Movie.h"
+#include "OptionalContent.h"
+#include "Sound.h"
+#include "FileSpec.h"
+#include "DateInfo.h"
+#include "Link.h"
+#include <string.h>
+#include <algorithm>
+
+#if MULTITHREADED
+# define annotLocker() MutexLocker locker(&mutex)
+# define annotCondLocker(X) MutexLocker locker(&mutex, (X))
+#else
+# define annotLocker()
+# define annotCondLocker(X)
+#endif
+
+#define fieldFlagReadOnly 0x00000001
+#define fieldFlagRequired 0x00000002
+#define fieldFlagNoExport 0x00000004
+#define fieldFlagMultiline 0x00001000
+#define fieldFlagPassword 0x00002000
+#define fieldFlagNoToggleToOff 0x00004000
+#define fieldFlagRadio 0x00008000
+#define fieldFlagPushbutton 0x00010000
+#define fieldFlagCombo 0x00020000
+#define fieldFlagEdit 0x00040000
+#define fieldFlagSort 0x00080000
+#define fieldFlagFileSelect 0x00100000
+#define fieldFlagMultiSelect 0x00200000
+#define fieldFlagDoNotSpellCheck 0x00400000
+#define fieldFlagDoNotScroll 0x00800000
+#define fieldFlagComb 0x01000000
+#define fieldFlagRichText 0x02000000
+#define fieldFlagRadiosInUnison 0x02000000
+#define fieldFlagCommitOnSelChange 0x04000000
+
+#define fieldQuadLeft 0
+#define fieldQuadCenter 1
+#define fieldQuadRight 2
+
+// distance of Bezier control point from center for circle approximation
+// = (4 * (sqrt(2) - 1) / 3) * r
+#define bezierCircle 0.55228475
+
+AnnotLineEndingStyle parseAnnotLineEndingStyle(GooString *string) {
+ if (string != NULL) {
+ if (!string->cmp("Square")) {
+ return annotLineEndingSquare;
+ } else if (!string->cmp("Circle")) {
+ return annotLineEndingCircle;
+ } else if (!string->cmp("Diamond")) {
+ return annotLineEndingDiamond;
+ } else if (!string->cmp("OpenArrow")) {
+ return annotLineEndingOpenArrow;
+ } else if (!string->cmp("ClosedArrow")) {
+ return annotLineEndingClosedArrow;
+ } else if (!string->cmp("Butt")) {
+ return annotLineEndingButt;
+ } else if (!string->cmp("ROpenArrow")) {
+ return annotLineEndingROpenArrow;
+ } else if (!string->cmp("RClosedArrow")) {
+ return annotLineEndingRClosedArrow;
+ } else if (!string->cmp("Slash")) {
+ return annotLineEndingSlash;
+ } else {
+ return annotLineEndingNone;
+ }
+ } else {
+ return annotLineEndingNone;
+ }
+}
+
+const char* convertAnnotLineEndingStyle(AnnotLineEndingStyle style) {
+ switch (style) {
+ case annotLineEndingSquare:
+ return "Square";
+ case annotLineEndingCircle:
+ return "Circle";
+ case annotLineEndingDiamond:
+ return "Diamond";
+ case annotLineEndingOpenArrow:
+ return "OpenArrow";
+ case annotLineEndingClosedArrow:
+ return "ClosedArrow";
+ case annotLineEndingButt:
+ return "Butt";
+ case annotLineEndingROpenArrow:
+ return "ROpenArrow";
+ case annotLineEndingRClosedArrow:
+ return "RClosedArrow";
+ case annotLineEndingSlash:
+ return "Slash";
+ default:
+ return "None";
+ }
+}
+
+static AnnotExternalDataType parseAnnotExternalData(Dict* dict) {
+ Object obj1;
+ AnnotExternalDataType type;
+
+ if (dict->lookup("Subtype", &obj1)->isName()) {
+ const char *typeName = obj1.getName();
+
+ if (!strcmp(typeName, "Markup3D")) {
+ type = annotExternalDataMarkup3D;
+ } else {
+ type = annotExternalDataMarkupUnknown;
+ }
+ } else {
+ type = annotExternalDataMarkupUnknown;
+ }
+ obj1.free();
+
+ return type;
+}
+
+PDFRectangle *parseDiffRectangle(Array *array, PDFRectangle *rect) {
+ PDFRectangle *newRect = NULL;
+ if (array->getLength() == 4) {
+ // deltas
+ Object obj1;
+ double dx1 = (array->get(0, &obj1)->isNum() ? obj1.getNum() : 0);
+ obj1.free();
+ double dy1 = (array->get(1, &obj1)->isNum() ? obj1.getNum() : 0);
+ obj1.free();
+ double dx2 = (array->get(2, &obj1)->isNum() ? obj1.getNum() : 0);
+ obj1.free();
+ double dy2 = (array->get(3, &obj1)->isNum() ? obj1.getNum() : 0);
+ obj1.free();
+
+ // checking that the numbers are valid (i.e. >= 0),
+ // and that applying the differences still give us a valid rect
+ if (dx1 >= 0 && dy1 >= 0 && dx2 >= 0 && dy2
+ && (rect->x2 - rect->x1 - dx1 - dx2) >= 0
+ && (rect->y2 - rect->y1 - dy1 - dy2) >= 0) {
+ newRect = new PDFRectangle();
+ newRect->x1 = rect->x1 + dx1;
+ newRect->y1 = rect->y1 + dy1;
+ newRect->x2 = rect->x2 - dx2;
+ newRect->y2 = rect->y2 - dy2;
+ }
+ }
+ return newRect;
+}
+
+static LinkAction* getAdditionalAction(Annot::AdditionalActionsType type, Object *additionalActions, PDFDoc *doc) {
+ Object additionalActionsObject;
+ LinkAction *linkAction = NULL;
+
+ if (additionalActions->fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+ const char *key = (type == Annot::actionCursorEntering ? "E" :
+ type == Annot::actionCursorLeaving ? "X" :
+ type == Annot::actionMousePressed ? "D" :
+ type == Annot::actionMouseReleased ? "U" :
+ type == Annot::actionFocusIn ? "Fo" :
+ type == Annot::actionFocusOut ? "BI" :
+ type == Annot::actionPageOpening ? "PO" :
+ type == Annot::actionPageClosing ? "PC" :
+ type == Annot::actionPageVisible ? "PV" :
+ type == Annot::actionPageInvisible ? "PI" : NULL);
+
+ Object actionObject;
+
+ if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+ linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
+ actionObject.free();
+ }
+
+ additionalActionsObject.free();
+
+ return linkAction;
+}
+
+static LinkAction* getFormAdditionalAction(Annot::FormAdditionalActionsType type, Object *additionalActions, PDFDoc *doc) {
+ Object additionalActionsObject;
+ LinkAction *linkAction = NULL;
+
+ if (additionalActions->fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+ const char *key = (type == Annot::actionFieldModified ? "K" :
+ type == Annot::actionFormatField ? "F" :
+ type == Annot::actionValidateField ? "V" :
+ type == Annot::actionCalculateField ? "C" : NULL);
+
+ Object actionObject;
+
+ if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+ linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
+ actionObject.free();
+ }
+
+ additionalActionsObject.free();
+
+ return linkAction;
+}
+
+//------------------------------------------------------------------------
+// AnnotBorderEffect
+//------------------------------------------------------------------------
+
+AnnotBorderEffect::AnnotBorderEffect(Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("S", &obj1)->isName()) {
+ const char *effectName = obj1.getName();
+
+ if (!strcmp(effectName, "C"))
+ effectType = borderEffectCloudy;
+ else
+ effectType = borderEffectNoEffect;
+ } else {
+ effectType = borderEffectNoEffect;
+ }
+ obj1.free();
+
+ if ((dict->lookup("I", &obj1)->isNum()) && effectType == borderEffectCloudy) {
+ intensity = obj1.getNum();
+ } else {
+ intensity = 0;
+ }
+ obj1.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotPath
+//------------------------------------------------------------------------
+
+AnnotPath::AnnotPath() {
+ coords = NULL;
+ coordsLength = 0;
+}
+
+AnnotPath::AnnotPath(Array *array) {
+ coords = NULL;
+ coordsLength = 0;
+ parsePathArray(array);
+}
+
+AnnotPath::AnnotPath(AnnotCoord **coords, int coordsLength) {
+ this->coords = coords;
+ this->coordsLength = coordsLength;
+}
+
+AnnotPath::~AnnotPath() {
+ if (coords) {
+ for (int i = 0; i < coordsLength; ++i)
+ delete coords[i];
+ gfree(coords);
+ }
+}
+
+double AnnotPath::getX(int coord) const {
+ if (coord >= 0 && coord < coordsLength)
+ return coords[coord]->getX();
+ return 0;
+}
+
+double AnnotPath::getY(int coord) const {
+ if (coord >= 0 && coord < coordsLength)
+ return coords[coord]->getY();
+ return 0;
+}
+
+AnnotCoord *AnnotPath::getCoord(int coord) const {
+ if (coord >= 0 && coord < coordsLength)
+ return coords[coord];
+ return NULL;
+}
+
+void AnnotPath::parsePathArray(Array *array) {
+ int tempLength;
+ AnnotCoord **tempCoords;
+ GBool correct = gTrue;
+
+ if (array->getLength() % 2) {
+ error(errSyntaxError, -1, "Bad Annot Path");
+ return;
+ }
+
+ tempLength = array->getLength() / 2;
+ tempCoords = (AnnotCoord **) gmallocn (tempLength, sizeof(AnnotCoord *));
+ memset(tempCoords, 0, tempLength * sizeof(AnnotCoord *));
+ for (int i = 0; i < tempLength && correct; i++) {
+ Object obj1;
+ double x = 0, y = 0;
+
+ if (array->get(i * 2, &obj1)->isNum()) {
+ x = obj1.getNum();
+ } else {
+ correct = gFalse;
+ }
+ obj1.free();
+
+ if (array->get((i * 2) + 1, &obj1)->isNum()) {
+ y = obj1.getNum();
+ } else {
+ correct = gFalse;
+ }
+ obj1.free();
+
+ if (!correct) {
+ for (int j = i - 1; j >= 0; j--)
+ delete tempCoords[j];
+ gfree (tempCoords);
+ return;
+ }
+
+ tempCoords[i] = new AnnotCoord(x, y);
+ }
+
+ coords = tempCoords;
+ coordsLength = tempLength;
+}
+
+//------------------------------------------------------------------------
+// AnnotCalloutLine
+//------------------------------------------------------------------------
+
+AnnotCalloutLine::AnnotCalloutLine(double x1, double y1, double x2, double y2)
+ : coord1(x1, y1), coord2(x2, y2) {
+}
+
+//------------------------------------------------------------------------
+// AnnotCalloutMultiLine
+//------------------------------------------------------------------------
+
+AnnotCalloutMultiLine::AnnotCalloutMultiLine(double x1, double y1, double x2,
+ double y2, double x3, double y3)
+ : AnnotCalloutLine(x1, y1, x2, y2), coord3(x3, y3) {
+}
+
+//------------------------------------------------------------------------
+// AnnotQuadrilateral
+//------------------------------------------------------------------------
+
+AnnotQuadrilaterals::AnnotQuadrilaterals(Array *array, PDFRectangle *rect) {
+ int arrayLength = array->getLength();
+ GBool correct = gTrue;
+ int quadsLength = 0;
+ AnnotQuadrilateral **quads;
+ double quadArray[8];
+
+ // default values
+ quadrilaterals = NULL;
+ quadrilateralsLength = 0;
+
+ if ((arrayLength % 8) == 0) {
+ int i;
+
+ quadsLength = arrayLength / 8;
+ quads = (AnnotQuadrilateral **) gmallocn
+ ((quadsLength), sizeof(AnnotQuadrilateral *));
+ memset(quads, 0, quadsLength * sizeof(AnnotQuadrilateral *));
+
+ for (i = 0; i < quadsLength; i++) {
+ for (int j = 0; j < 8; j++) {
+ Object obj;
+ if (array->get(i * 8 + j, &obj)->isNum()) {
+ quadArray[j] = obj.getNum();
+ } else {
+ correct = gFalse;
+ obj.free();
+ error (errSyntaxError, -1, "Invalid QuadPoint in annot");
+ break;
+ }
+ obj.free();
+ }
+
+ if (!correct)
+ break;
+
+ quads[i] = new AnnotQuadrilateral(quadArray[0], quadArray[1],
+ quadArray[2], quadArray[3],
+ quadArray[4], quadArray[5],
+ quadArray[6], quadArray[7]);
+ }
+
+ if (correct) {
+ quadrilateralsLength = quadsLength;
+ quadrilaterals = quads;
+ } else {
+ for (int j = 0; j < i; j++)
+ delete quads[j];
+ gfree (quads);
+ }
+ }
+}
+
+AnnotQuadrilaterals::AnnotQuadrilaterals(AnnotQuadrilaterals::AnnotQuadrilateral **quads, int quadsLength) {
+ quadrilaterals = quads;
+ quadrilateralsLength = quadsLength;
+}
+
+AnnotQuadrilaterals::~AnnotQuadrilaterals() {
+ if (quadrilaterals) {
+ for(int i = 0; i < quadrilateralsLength; i++)
+ delete quadrilaterals[i];
+
+ gfree (quadrilaterals);
+ }
+}
+
+double AnnotQuadrilaterals::getX1(int quadrilateral) {
+ if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
+ return quadrilaterals[quadrilateral]->coord1.getX();
+ return 0;
+}
+
+double AnnotQuadrilaterals::getY1(int quadrilateral) {
+ if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
+ return quadrilaterals[quadrilateral]->coord1.getY();
+ return 0;
+}
+
+double AnnotQuadrilaterals::getX2(int quadrilateral) {
+ if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
+ return quadrilaterals[quadrilateral]->coord2.getX();
+ return 0;
+}
+
+double AnnotQuadrilaterals::getY2(int quadrilateral) {
+ if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
+ return quadrilaterals[quadrilateral]->coord2.getY();
+ return 0;
+}
+
+double AnnotQuadrilaterals::getX3(int quadrilateral) {
+ if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
+ return quadrilaterals[quadrilateral]->coord3.getX();
+ return 0;
+}
+
+double AnnotQuadrilaterals::getY3(int quadrilateral) {
+ if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
+ return quadrilaterals[quadrilateral]->coord3.getY();
+ return 0;
+}
+
+double AnnotQuadrilaterals::getX4(int quadrilateral) {
+ if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
+ return quadrilaterals[quadrilateral]->coord4.getX();
+ return 0;
+}
+
+double AnnotQuadrilaterals::getY4(int quadrilateral) {
+ if (quadrilateral >= 0 && quadrilateral < quadrilateralsLength)
+ return quadrilaterals[quadrilateral]->coord4.getY();
+ return 0;
+}
+
+AnnotQuadrilaterals::AnnotQuadrilateral::AnnotQuadrilateral(double x1, double y1,
+ double x2, double y2, double x3, double y3, double x4, double y4)
+ : coord1(x1, y1), coord2(x2, y2), coord3(x3, y3), coord4(x4, y4) {
+}
+
+//------------------------------------------------------------------------
+// AnnotBorder
+//------------------------------------------------------------------------
+AnnotBorder::AnnotBorder() {
+ width = 1;
+ dashLength = 0;
+ dash = NULL;
+ style = borderSolid;
+}
+
+GBool AnnotBorder::parseDashArray(Object *dashObj) {
+ GBool correct = gTrue;
+ int tempLength = dashObj->arrayGetLength();
+ double *tempDash = (double *) gmallocn (tempLength, sizeof (double));
+
+ // TODO: check not all zero (Line Dash Pattern Page 217 PDF 8.1)
+ for (int i = 0; i < tempLength && i < DASH_LIMIT && correct; i++) {
+ Object obj1;
+
+ if (dashObj->arrayGet(i, &obj1)->isNum()) {
+ tempDash[i] = obj1.getNum();
+
+ correct = tempDash[i] >= 0;
+ obj1.free();
+ }
+ }
+
+ if (correct) {
+ dashLength = tempLength;
+ dash = tempDash;
+ style = borderDashed;
+ } else {
+ gfree (tempDash);
+ }
+
+ return correct;
+}
+
+AnnotBorder::~AnnotBorder() {
+ if (dash)
+ gfree (dash);
+}
+
+//------------------------------------------------------------------------
+// AnnotBorderArray
+//------------------------------------------------------------------------
+
+AnnotBorderArray::AnnotBorderArray() {
+ horizontalCorner = 0;
+ verticalCorner = 0;
+}
+
+AnnotBorderArray::AnnotBorderArray(Array *array) {
+ Object obj1;
+ int arrayLength = array->getLength();
+
+ GBool correct = gTrue;
+ if (arrayLength == 3 || arrayLength == 4) {
+ // implementation note 81 in Appendix H.
+
+ if (array->get(0, &obj1)->isNum())
+ horizontalCorner = obj1.getNum();
+ else
+ correct = gFalse;
+ obj1.free();
+
+ if (array->get(1, &obj1)->isNum())
+ verticalCorner = obj1.getNum();
+ else
+ correct = gFalse;
+ obj1.free();
+
+ if (array->get(2, &obj1)->isNum())
+ width = obj1.getNum();
+ else
+ correct = gFalse;
+ obj1.free();
+
+ if (arrayLength == 4) {
+ if (array->get(3, &obj1)->isArray())
+ correct = parseDashArray(&obj1);
+ else
+ correct = gFalse;
+ obj1.free();
+ }
+ } else {
+ correct = gFalse;
+ }
+
+ if (!correct) {
+ width = 0;
+ }
+}
+
+void AnnotBorderArray::writeToObject(XRef *xref, Object *obj1) const {
+ Object obj2;
+
+ obj1->initArray(xref);
+ obj1->arrayAdd(obj2.initReal(horizontalCorner));
+ obj1->arrayAdd(obj2.initReal(verticalCorner));
+ obj1->arrayAdd(obj2.initReal(width));
+
+ if (dashLength > 0) {
+ Object obj3;
+
+ obj1->arrayAdd(obj3.initArray(xref));
+ for (int i = 0; i < dashLength; i++)
+ obj3.arrayAdd(obj2.initReal(dash[i]));
+ }
+}
+
+//------------------------------------------------------------------------
+// AnnotBorderBS
+//------------------------------------------------------------------------
+
+AnnotBorderBS::AnnotBorderBS() {
+}
+
+AnnotBorderBS::AnnotBorderBS(Dict *dict) {
+ Object obj1, obj2;
+
+ // acroread 8 seems to need both W and S entries for
+ // any border to be drawn, even though the spec
+ // doesn't claim anything of that sort. We follow
+ // that behaviour by veryifying both entries exist
+ // otherwise we set the borderWidth to 0
+ // --jrmuizel
+ dict->lookup("W", &obj1);
+ dict->lookup("S", &obj2);
+ if (obj1.isNum() && obj2.isName()) {
+ const char *styleName = obj2.getName();
+
+ width = obj1.getNum();
+
+ if (!strcmp(styleName, "S")) {
+ style = borderSolid;
+ } else if (!strcmp(styleName, "D")) {
+ style = borderDashed;
+ } else if (!strcmp(styleName, "B")) {
+ style = borderBeveled;
+ } else if (!strcmp(styleName, "I")) {
+ style = borderInset;
+ } else if (!strcmp(styleName, "U")) {
+ style = borderUnderlined;
+ } else {
+ style = borderSolid;
+ }
+ } else {
+ width = 0;
+ }
+ obj2.free();
+ obj1.free();
+
+ if (style == borderDashed) {
+ if (dict->lookup("D", &obj1)->isArray())
+ parseDashArray(&obj1);
+ obj1.free();
+
+ if (!dash) {
+ dashLength = 1;
+ dash = (double *) gmallocn (dashLength, sizeof (double));
+ dash[0] = 3;
+ }
+ }
+}
+
+const char *AnnotBorderBS::getStyleName() const {
+ switch (style) {
+ case borderSolid:
+ return "S";
+ case borderDashed:
+ return "D";
+ case borderBeveled:
+ return "B";
+ case borderInset:
+ return "I";
+ case borderUnderlined:
+ return "U";
+ }
+
+ return "S";
+}
+
+void AnnotBorderBS::writeToObject(XRef *xref, Object *obj1) const {
+ Object obj2;
+
+ obj1->initDict(xref);
+ obj1->dictSet("W", obj2.initReal(width));
+ obj1->dictSet("S", obj2.initName(getStyleName()));
+ if (style == borderDashed && dashLength > 0) {
+ Object obj3;
+
+ obj1->dictSet("D", obj3.initArray(xref));
+ for (int i = 0; i < dashLength; i++)
+ obj3.arrayAdd(obj2.initReal(dash[i]));
+ }
+}
+
+//------------------------------------------------------------------------
+// AnnotColor
+//------------------------------------------------------------------------
+
+AnnotColor::AnnotColor() {
+ length = 0;
+}
+
+AnnotColor::AnnotColor(double gray) {
+ length = 1;
+
+ values[0] = gray;
+}
+
+AnnotColor::AnnotColor(double r, double g, double b) {
+ length = 3;
+
+ values[0] = r;
+ values[1] = g;
+ values[2] = b;
+}
+
+AnnotColor::AnnotColor(double c, double m, double y, double k) {
+ length = 4;
+
+ values[0] = c;
+ values[1] = m;
+ values[2] = y;
+ values[3] = k;
+}
+
+// If <adjust> is +1, color is brightened;
+// if <adjust> is -1, color is darkened;
+// otherwise color is not modified.
+AnnotColor::AnnotColor(Array *array, int adjust) {
+ int i;
+
+ length = array->getLength();
+ if (length > 4)
+ length = 4;
+
+ for (i = 0; i < length; i++) {
+ Object obj1;
+
+ if (array->get(i, &obj1)->isNum()) {
+ values[i] = obj1.getNum();
+
+ if (values[i] < 0 || values[i] > 1)
+ values[i] = 0;
+ } else {
+ values[i] = 0;
+ }
+ obj1.free();
+ }
+
+ if (adjust != 0)
+ adjustColor(adjust);
+}
+
+void AnnotColor::adjustColor(int adjust) {
+ int i;
+
+ if (length == 4) {
+ adjust = -adjust;
+ }
+ if (adjust > 0) {
+ for (i = 0; i < length; ++i) {
+ values[i] = 0.5 * values[i] + 0.5;
+ }
+ } else if (adjust < 0) {
+ for (i = 0; i < length; ++i) {
+ values[i] = 0.5 * values[i];
+ }
+ }
+}
+
+void AnnotColor::writeToObject(XRef *xref, Object *obj1) const {
+ Object obj2;
+ int i;
+
+ if (length == 0) {
+ obj1->initNull(); // Transparent (no color)
+ } else {
+ obj1->initArray(xref);
+ for (i = 0; i < length; ++i)
+ obj1->arrayAdd( obj2.initReal( values[i] ) );
+ }
+}
+
+//------------------------------------------------------------------------
+// AnnotIconFit
+//------------------------------------------------------------------------
+
+AnnotIconFit::AnnotIconFit(Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("SW", &obj1)->isName()) {
+ const char *scaleName = obj1.getName();
+
+ if(!strcmp(scaleName, "B")) {
+ scaleWhen = scaleBigger;
+ } else if(!strcmp(scaleName, "S")) {
+ scaleWhen = scaleSmaller;
+ } else if(!strcmp(scaleName, "N")) {
+ scaleWhen = scaleNever;
+ } else {
+ scaleWhen = scaleAlways;
+ }
+ } else {
+ scaleWhen = scaleAlways;
+ }
+ obj1.free();
+
+ if (dict->lookup("S", &obj1)->isName()) {
+ const char *scaleName = obj1.getName();
+
+ if(!strcmp(scaleName, "A")) {
+ scale = scaleAnamorphic;
+ } else {
+ scale = scaleProportional;
+ }
+ } else {
+ scale = scaleProportional;
+ }
+ obj1.free();
+
+ if (dict->lookup("A", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
+ Object obj2;
+ (obj1.arrayGet(0, &obj2)->isNum() ? left = obj2.getNum() : left = 0);
+ obj2.free();
+ (obj1.arrayGet(1, &obj2)->isNum() ? bottom = obj2.getNum() : bottom = 0);
+ obj2.free();
+
+ if (left < 0 || left > 1)
+ left = 0.5;
+
+ if (bottom < 0 || bottom > 1)
+ bottom = 0.5;
+
+ } else {
+ left = bottom = 0.5;
+ }
+ obj1.free();
+
+ if (dict->lookup("FB", &obj1)->isBool()) {
+ fullyBounds = obj1.getBool();
+ } else {
+ fullyBounds = gFalse;
+ }
+ obj1.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotAppearance
+//------------------------------------------------------------------------
+
+AnnotAppearance::AnnotAppearance(PDFDoc *docA, Object *dict) {
+ assert(dict->isDict());
+ doc = docA;
+ xref = docA->getXRef();
+ dict->copy(&appearDict);
+}
+
+AnnotAppearance::~AnnotAppearance() {
+ appearDict.free();
+}
+
+void AnnotAppearance::getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest) {
+ Object apData, stream;
+ apData.initNull();
+
+ // Obtain dictionary or stream associated to appearance type
+ switch (type) {
+ case appearRollover:
+ if (appearDict.dictLookupNF("R", &apData)->isNull())
+ appearDict.dictLookupNF("N", &apData);
+ break;
+ case appearDown:
+ if (appearDict.dictLookupNF("D", &apData)->isNull())
+ appearDict.dictLookupNF("N", &apData);
+ break;
+ case appearNormal:
+ appearDict.dictLookupNF("N", &apData);
+ break;
+ }
+
+ dest->initNull();
+ if (apData.isDict() && state)
+ apData.dictLookupNF(state, dest);
+ else if (apData.isRef())
+ apData.copy(dest);
+ apData.free();
+}
+
+GooString * AnnotAppearance::getStateKey(int i) {
+ Object obj1;
+ GooString * res = NULL;
+ if (appearDict.dictLookupNF("N", &obj1)->isDict())
+ res = new GooString(obj1.dictGetKey(i));
+ obj1.free();
+ return res;
+}
+
+int AnnotAppearance::getNumStates() {
+ Object obj1;
+ int res = 0;
+ if (appearDict.dictLookupNF("N", &obj1)->isDict())
+ res = obj1.dictGetLength();
+ obj1.free();
+ return res;
+}
+
+// Test if stateObj (a Ref or a Dict) points to the specified stream
+GBool AnnotAppearance::referencesStream(Object *stateObj, Ref refToStream) {
+ if (stateObj->isRef()) {
+ Ref r = stateObj->getRef();
+ if (r.num == refToStream.num && r.gen == refToStream.gen) {
+ return gTrue;
+ }
+ } else if (stateObj->isDict()) { // Test each value
+ const int size = stateObj->dictGetLength();
+ for (int i = 0; i < size; ++i) {
+ Object obj1;
+ stateObj->dictGetValNF(i, &obj1);
+ if (obj1.isRef()) {
+ Ref r = obj1.getRef();
+ if (r.num == refToStream.num && r.gen == refToStream.gen) {
+ return gTrue;
+ }
+ }
+ obj1.free();
+ }
+ }
+ return gFalse; // Not found
+}
+
+// Test if this AnnotAppearance references the specified stream
+GBool AnnotAppearance::referencesStream(Ref refToStream) {
+ Object obj1;
+ GBool found;
+
+ // Scan each state's ref/subdictionary
+ appearDict.dictLookupNF("N", &obj1);
+ found = referencesStream(&obj1, refToStream);
+ obj1.free();
+ if (found)
+ return gTrue;
+
+ appearDict.dictLookupNF("R", &obj1);
+ found = referencesStream(&obj1, refToStream);
+ obj1.free();
+ if (found)
+ return gTrue;
+
+ appearDict.dictLookupNF("D", &obj1);
+ found = referencesStream(&obj1, refToStream);
+ obj1.free();
+ return found;
+}
+
+// If this is the only annotation in the document that references the
+// specified appearance stream, remove the appearance stream
+void AnnotAppearance::removeStream(Ref refToStream) {
+ const int lastpage = doc->getNumPages();
+ for (int pg = 1; pg <= lastpage; ++pg) { // Scan all annotations in the document
+ Page *page = doc->getPage(pg);
+ if (!page) {
+ error(errSyntaxError, -1, "Failed check for shared annotation stream at page {0:d}", pg);
+ continue;
+ }
+ Annots *annots = page->getAnnots();
+ for (int i = 0; i < annots->getNumAnnots(); ++i) {
+ AnnotAppearance *annotAp = annots->getAnnot(i)->getAppearStreams();
+ if (annotAp && annotAp != this && annotAp->referencesStream(refToStream)) {
+ return; // Another annotation points to the stream -> Don't delete it
+ }
+ }
+ }
+
+ // TODO: stream resources (e.g. font), AP name tree
+ xref->removeIndirectObject(refToStream);
+}
+
+// Removes stream if obj is a Ref, or removes pointed streams if obj is a Dict
+void AnnotAppearance::removeStateStreams(Object *obj1) {
+ if (obj1->isRef()) {
+ removeStream(obj1->getRef());
+ } else if (obj1->isDict()) {
+ const int size = obj1->dictGetLength();
+ for (int i = 0; i < size; ++i) {
+ Object obj2;
+ obj1->dictGetValNF(i, &obj2);
+ if (obj2.isRef()) {
+ removeStream(obj2.getRef());
+ }
+ obj2.free();
+ }
+ }
+}
+
+void AnnotAppearance::removeAllStreams() {
+ Object obj1;
+ appearDict.dictLookupNF("N", &obj1);
+ removeStateStreams(&obj1);
+ obj1.free();
+ appearDict.dictLookupNF("R", &obj1);
+ removeStateStreams(&obj1);
+ obj1.free();
+ appearDict.dictLookupNF("D", &obj1);
+ removeStateStreams(&obj1);
+ obj1.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotAppearanceCharacs
+//------------------------------------------------------------------------
+
+AnnotAppearanceCharacs::AnnotAppearanceCharacs(Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("R", &obj1)->isInt()) {
+ rotation = obj1.getInt();
+ } else {
+ rotation = 0;
+ }
+ obj1.free();
+
+ if (dict->lookup("BC", &obj1)->isArray()) {
+ Array *colorComponents = obj1.getArray();
+ if (colorComponents->getLength() > 0) {
+ borderColor = new AnnotColor(colorComponents);
+ } else {
+ borderColor = NULL;
+ }
+ } else {
+ borderColor = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("BG", &obj1)->isArray()) {
+ Array *colorComponents = obj1.getArray();
+ if (colorComponents->getLength() > 0) {
+ backColor = new AnnotColor(colorComponents);
+ } else {
+ backColor = NULL;
+ }
+ } else {
+ backColor = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("CA", &obj1)->isString()) {
+ normalCaption = new GooString(obj1.getString());
+ } else {
+ normalCaption = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("RC", &obj1)->isString()) {
+ rolloverCaption = new GooString(obj1.getString());
+ } else {
+ rolloverCaption = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("AC", &obj1)->isString()) {
+ alternateCaption = new GooString(obj1.getString());
+ } else {
+ alternateCaption = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("IF", &obj1)->isDict()) {
+ iconFit = new AnnotIconFit(obj1.getDict());
+ } else {
+ iconFit = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("TP", &obj1)->isInt()) {
+ position = (AnnotAppearanceCharacsTextPos) obj1.getInt();
+ } else {
+ position = captionNoIcon;
+ }
+ obj1.free();
+}
+
+AnnotAppearanceCharacs::~AnnotAppearanceCharacs() {
+ if (borderColor)
+ delete borderColor;
+
+ if (backColor)
+ delete backColor;
+
+ if (normalCaption)
+ delete normalCaption;
+
+ if (rolloverCaption)
+ delete rolloverCaption;
+
+ if (alternateCaption)
+ delete alternateCaption;
+
+ if (iconFit)
+ delete iconFit;
+}
+
+//------------------------------------------------------------------------
+// AnnotAppearanceBBox
+//------------------------------------------------------------------------
+
+AnnotAppearanceBBox::AnnotAppearanceBBox(PDFRectangle *rect) {
+ origX = rect->x1;
+ origY = rect->y1;
+ borderWidth = 0;
+
+ // Initially set the same size as rect
+ minX = 0;
+ minY = 0;
+ maxX = rect->x2 - rect->x1;
+ maxY = rect->y2 - rect->y1;
+}
+
+void AnnotAppearanceBBox::extendTo(double x, double y) {
+ if (x < minX) {
+ minX = x;
+ } else if (x > maxX) {
+ maxX = x;
+ }
+ if (y < minY) {
+ minY = y;
+ } else if (y > maxY) {
+ maxY = y;
+ }
+}
+
+void AnnotAppearanceBBox::getBBoxRect(double bbox[4]) const {
+ bbox[0] = minX - borderWidth;
+ bbox[1] = minY - borderWidth;
+ bbox[2] = maxX + borderWidth;
+ bbox[3] = maxY + borderWidth;
+}
+
+double AnnotAppearanceBBox::getPageXMin() const {
+ return origX + minX - borderWidth;
+}
+
+double AnnotAppearanceBBox::getPageYMin() const {
+ return origY + minY - borderWidth;
+}
+
+double AnnotAppearanceBBox::getPageXMax() const {
+ return origX + maxX + borderWidth;
+}
+
+double AnnotAppearanceBBox::getPageYMax() const {
+ return origY + maxY + borderWidth;
+}
+
+//------------------------------------------------------------------------
+// Annot
+//------------------------------------------------------------------------
+
+Annot::Annot(PDFDoc *docA, PDFRectangle *rectA) {
+ Object obj1;
+
+ refCnt = 1;
+ flags = flagUnknown;
+ type = typeUnknown;
+
+ obj1.initArray (docA->getXRef());
+ Object obj2;
+ obj1.arrayAdd (obj2.initReal (rectA->x1));
+ obj1.arrayAdd (obj2.initReal (rectA->y1));
+ obj1.arrayAdd (obj2.initReal (rectA->x2));
+ obj1.arrayAdd (obj2.initReal (rectA->y2));
+ obj2.free ();
+
+ annotObj.initDict (docA->getXRef());
+ annotObj.dictSet ("Type", obj2.initName ("Annot"));
+ annotObj.dictSet ("Rect", &obj1);
+ // obj1 is owned by the dict
+
+ ref = docA->getXRef()->addIndirectObject (&annotObj);
+
+ initialize (docA, annotObj.getDict());
+}
+
+Annot::Annot(PDFDoc *docA, Dict *dict) {
+ refCnt = 1;
+ hasRef = false;
+ flags = flagUnknown;
+ type = typeUnknown;
+ annotObj.initDict (dict);
+ initialize (docA, dict);
+}
+
+Annot::Annot(PDFDoc *docA, Dict *dict, Object *obj) {
+ refCnt = 1;
+ if (obj->isRef()) {
+ hasRef = gTrue;
+ ref = obj->getRef();
+ } else {
+ hasRef = gFalse;
+ }
+ flags = flagUnknown;
+ type = typeUnknown;
+ annotObj.initDict (dict);
+ initialize (docA, dict);
+}
+
+void Annot::initialize(PDFDoc *docA, Dict *dict) {
+ Object apObj, asObj, obj1, obj2;
+
+ ok = gTrue;
+ doc = docA;
+ xref = doc->getXRef();
+ appearStreams = NULL;
+ appearBBox = NULL;
+ appearState = NULL;
+ appearBuf = NULL;
+ fontSize = 0;
+
+ appearance.initNull();
+
+ //----- parse the rectangle
+ rect = new PDFRectangle();
+ if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
+ Object obj2;
+ (obj1.arrayGet(0, &obj2)->isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0);
+ obj2.free();
+ (obj1.arrayGet(1, &obj2)->isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0);
+ obj2.free();
+ (obj1.arrayGet(2, &obj2)->isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1);
+ obj2.free();
+ (obj1.arrayGet(3, &obj2)->isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1);
+ obj2.free();
+
+ if (rect->x1 > rect->x2) {
+ double t = rect->x1;
+ rect->x1 = rect->x2;
+ rect->x2 = t;
+ }
+
+ if (rect->y1 > rect->y2) {
+ double t = rect->y1;
+ rect->y1 = rect->y2;
+ rect->y2 = t;
+ }
+ } else {
+ rect->x1 = rect->y1 = 0;
+ rect->x2 = rect->y2 = 1;
+ error(errSyntaxError, -1, "Bad bounding box for annotation");
+ ok = gFalse;
+ }
+ obj1.free();
+
+ if (dict->lookup("Contents", &obj1)->isString()) {
+ contents = obj1.getString()->copy();
+ } else {
+ contents = new GooString();
+ }
+ obj1.free();
+
+ // Note: This value is overwritten by Annots ctor
+ if (dict->lookupNF("P", &obj1)->isRef()) {
+ Ref ref = obj1.getRef();
+
+ page = doc->getCatalog()->findPage (ref.num, ref.gen);
+ } else {
+ page = 0;
+ }
+ obj1.free();
+
+ if (dict->lookup("NM", &obj1)->isString()) {
+ name = obj1.getString()->copy();
+ } else {
+ name = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("M", &obj1)->isString()) {
+ modified = obj1.getString()->copy();
+ } else {
+ modified = NULL;
+ }
+ obj1.free();
+
+ //----- get the flags
+ if (dict->lookup("F", &obj1)->isInt()) {
+ flags |= obj1.getInt();
+ } else {
+ flags = flagUnknown;
+ }
+ obj1.free();
+
+ //----- get the annotation appearance dictionary
+ dict->lookup("AP", &apObj);
+ if (apObj.isDict()) {
+ appearStreams = new AnnotAppearance(doc, &apObj);
+ }
+ apObj.free();
+
+ //----- get the appearance state
+ dict->lookup("AS", &asObj);
+ if (asObj.isName()) {
+ appearState = new GooString(asObj.getName());
+ } else if (appearStreams && appearStreams->getNumStates() != 0) {
+ error (errSyntaxError, -1, "Invalid or missing AS value in annotation containing one or more appearance subdictionaries");
+ // AS value is required in this case, but if the
+ // N dictionary contains only one entry
+ // take it as default appearance.
+ if (appearStreams->getNumStates() == 1) {
+ appearState = appearStreams->getStateKey(0);
+ }
+ }
+ if (!appearState) {
+ appearState = new GooString("Off");
+ }
+ asObj.free();
+
+ //----- get the annotation appearance
+ if (appearStreams) {
+ appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
+ }
+
+ //----- parse the border style
+ // According to the spec if neither the Border nor the BS entry is present,
+ // the border shall be drawn as a solid line with a width of 1 point. But acroread
+ // seems to ignore the Border entry for annots that can't have a BS entry. So, we only
+ // follow this rule for annots tha can have a BS entry.
+ if (dict->lookup("Border", &obj1)->isArray())
+ border = new AnnotBorderArray(obj1.getArray());
+ else
+ border = NULL;
+ obj1.free();
+
+ if (dict->lookup("C", &obj1)->isArray()) {
+ color = new AnnotColor(obj1.getArray());
+ } else {
+ color = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("StructParent", &obj1)->isInt()) {
+ treeKey = obj1.getInt();
+ } else {
+ treeKey = 0;
+ }
+ obj1.free();
+
+ dict->lookupNF("OC", &oc);
+
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+void Annot::getRect(double *x1, double *y1, double *x2, double *y2) const {
+ *x1 = rect->x1;
+ *y1 = rect->y1;
+ *x2 = rect->x2;
+ *y2 = rect->y2;
+}
+
+void Annot::setRect(PDFRectangle *rect) {
+ setRect(rect->x1, rect->y1, rect->x2, rect->y2);
+}
+
+void Annot::setRect(double x1, double y1, double x2, double y2) {
+ Object obj1, obj2;
+
+ if (x1 < x2) {
+ rect->x1 = x1;
+ rect->x2 = x2;
+ } else {
+ rect->x1 = x2;
+ rect->x2 = x1;
+ }
+
+ if (y1 < y2) {
+ rect->y1 = y1;
+ rect->y2 = y2;
+ } else {
+ rect->y1 = y2;
+ rect->y2 = y1;
+ }
+
+ obj1.initArray (xref);
+ obj1.arrayAdd (obj2.initReal (rect->x1));
+ obj1.arrayAdd (obj2.initReal (rect->y1));
+ obj1.arrayAdd (obj2.initReal (rect->x2));
+ obj1.arrayAdd (obj2.initReal (rect->y2));
+
+ update("Rect", &obj1);
+ invalidateAppearance();
+}
+
+GBool Annot::inRect(double x, double y) const {
+ return rect->contains(x, y);
+}
+
+void Annot::update(const char *key, Object *value) {
+ annotLocker();
+ /* Set M to current time, unless we are updating M itself */
+ if (strcmp(key, "M") != 0) {
+ delete modified;
+ modified = timeToDateString(NULL);
+
+ Object obj1;
+ obj1.initString (modified->copy());
+ annotObj.dictSet("M", &obj1);
+ }
+
+ annotObj.dictSet(const_cast<char*>(key), value);
+
+ xref->setModifiedObject(&annotObj, ref);
+}
+
+void Annot::setContents(GooString *new_content) {
+ annotLocker();
+ delete contents;
+
+ if (new_content) {
+ contents = new GooString(new_content);
+ //append the unicode marker <FE FF> if needed
+ if (!contents->hasUnicodeMarker()) {
+ contents->insert(0, 0xff);
+ contents->insert(0, 0xfe);
+ }
+ } else {
+ contents = new GooString();
+ }
+
+ Object obj1;
+ obj1.initString(contents->copy());
+ update ("Contents", &obj1);
+}
+
+void Annot::setName(GooString *new_name) {
+ annotLocker();
+ delete name;
+
+ if (new_name) {
+ name = new GooString(new_name);
+ } else {
+ name = new GooString();
+ }
+
+ Object obj1;
+ obj1.initString(name->copy());
+ update ("NM", &obj1);
+}
+
+void Annot::setModified(GooString *new_modified) {
+ annotLocker();
+ delete modified;
+
+ if (new_modified)
+ modified = new GooString(new_modified);
+ else
+ modified = new GooString();
+
+ Object obj1;
+ obj1.initString(modified->copy());
+ update ("M", &obj1);
+}
+
+void Annot::setFlags(Guint new_flags) {
+ annotLocker();
+ Object obj1;
+ flags = new_flags;
+ obj1.initInt(flags);
+ update ("F", &obj1);
+}
+
+void Annot::setBorder(AnnotBorder *new_border) {
+ annotLocker();
+ delete border;
+
+ if (new_border) {
+ Object obj1;
+ new_border->writeToObject(xref, &obj1);
+ update(new_border->getType() == AnnotBorder::typeArray ? "Border" : "BS", &obj1);
+ border = new_border;
+ } else {
+ border = NULL;
+ }
+ invalidateAppearance();
+}
+
+void Annot::setColor(AnnotColor *new_color) {
+ annotLocker();
+ delete color;
+
+ if (new_color) {
+ Object obj1;
+ new_color->writeToObject(xref, &obj1);
+ update ("C", &obj1);
+ color = new_color;
+ } else {
+ color = NULL;
+ }
+ invalidateAppearance();
+}
+
+void Annot::setPage(int pageIndex, GBool updateP) {
+ annotLocker();
+ Page *pageobj = doc->getPage(pageIndex);
+ Object obj1;
+
+ if (pageobj) {
+ Ref pageRef = pageobj->getRef();
+ obj1.initRef(pageRef.num, pageRef.gen);
+ page = pageIndex;
+ } else {
+ obj1.initNull();
+ page = 0;
+ }
+
+ if (updateP) {
+ update("P", &obj1);
+ }
+}
+
+void Annot::setAppearanceState(const char *state) {
+ annotLocker();
+ if (!state)
+ return;
+
+ delete appearState;
+ appearState = new GooString(state);
+
+ delete appearBBox;
+ appearBBox = NULL;
+
+ Object obj1;
+ obj1.initName(state);
+ update ("AS", &obj1);
+
+ // The appearance state determines the current appearance stream
+ appearance.free();
+ if (appearStreams) {
+ appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
+ } else {
+ appearance.initNull();
+ }
+}
+
+void Annot::invalidateAppearance() {
+ annotLocker();
+ if (appearStreams) { // Remove existing appearance streams
+ appearStreams->removeAllStreams();
+ }
+ delete appearStreams;
+ appearStreams = NULL;
+
+ delete appearState;
+ appearState = NULL;
+
+ delete appearBBox;
+ appearBBox = NULL;
+
+ appearance.free();
+ appearance.initNull();
+
+ Object obj1, obj2;
+ obj1.initNull();
+ if (!annotObj.dictLookup("AP", &obj2)->isNull())
+ update ("AP", &obj1); // Remove AP
+ obj2.free();
+
+ if (!annotObj.dictLookup("AS", &obj2)->isNull())
+ update ("AS", &obj1); // Remove AS
+ obj2.free();
+}
+
+double Annot::getXMin() {
+ return rect->x1;
+}
+
+double Annot::getYMin() {
+ return rect->y1;
+}
+
+double Annot::getXMax() {
+ return rect->x2;
+}
+
+double Annot::getYMax() {
+ return rect->y2;
+}
+
+void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
+ Object valueObject;
+
+ pdfArray->arrayGet(key, &valueObject);
+ if (valueObject.isNum()) {
+ *value = valueObject.getNum();
+ } else {
+ *value = 0;
+ ok = gFalse;
+ }
+ valueObject.free();
+}
+
+void Annot::removeReferencedObjects() {
+ // Remove appearance streams (if any)
+ invalidateAppearance();
+}
+
+void Annot::incRefCnt() {
+ annotLocker();
+ refCnt++;
+}
+
+void Annot::decRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ if (--refCnt == 0) {
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ delete this;
+ return;
+ }
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+}
+
+Annot::~Annot() {
+ annotObj.free();
+
+ delete rect;
+ delete contents;
+
+ if (name)
+ delete name;
+
+ if (modified)
+ delete modified;
+
+ delete appearStreams;
+ delete appearBBox;
+ appearance.free();
+
+ if (appearState)
+ delete appearState;
+
+ if (border)
+ delete border;
+
+ if (color)
+ delete color;
+
+ oc.free();
+
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+void Annot::setColor(AnnotColor *color, GBool fill) {
+ const double *values = color->getValues();
+
+ switch (color->getSpace()) {
+ case AnnotColor::colorCMYK:
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:c}\n",
+ values[0], values[1], values[2], values[3],
+ fill ? 'k' : 'K');
+ break;
+ case AnnotColor::colorRGB:
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:s}\n",
+ values[0], values[1], values[2],
+ fill ? "rg" : "RG");
+ break;
+ case AnnotColor::colorGray:
+ appearBuf->appendf("{0:.2f} {1:c}\n",
+ values[0],
+ fill ? 'g' : 'G');
+ break;
+ case AnnotColor::colorTransparent:
+ default:
+ break;
+ }
+}
+
+void Annot::setLineStyleForBorder(AnnotBorder *border) {
+ int i, dashLength;
+ double *dash;
+
+ switch (border->getStyle()) {
+ case AnnotBorder::borderDashed:
+ appearBuf->append("[");
+ dashLength = border->getDashLength();
+ dash = border->getDash();
+ for (i = 0; i < dashLength; ++i)
+ appearBuf->appendf(" {0:.2f}", dash[i]);
+ appearBuf->append(" ] 0 d\n");
+ break;
+ default:
+ appearBuf->append("[] 0 d\n");
+ break;
+ }
+ appearBuf->appendf("{0:.2f} w\n", border->getWidth());
+}
+
+// Draw an (approximate) circle of radius <r> centered at (<cx>, <cy>).
+// If <fill> is true, the circle is filled; otherwise it is stroked.
+void Annot::drawCircle(double cx, double cy, double r, GBool fill) {
+ appearBuf->appendf("{0:.2f} {1:.2f} m\n",
+ cx + r, cy);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx + r, cy + bezierCircle * r,
+ cx + bezierCircle * r, cy + r,
+ cx, cy + r);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx - bezierCircle * r, cy + r,
+ cx - r, cy + bezierCircle * r,
+ cx - r, cy);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx - r, cy - bezierCircle * r,
+ cx - bezierCircle * r, cy - r,
+ cx, cy - r);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx + bezierCircle * r, cy - r,
+ cx + r, cy - bezierCircle * r,
+ cx + r, cy);
+ appearBuf->append(fill ? "f\n" : "s\n");
+}
+
+// Draw the top-left half of an (approximate) circle of radius <r>
+// centered at (<cx>, <cy>).
+void Annot::drawCircleTopLeft(double cx, double cy, double r) {
+ double r2;
+
+ r2 = r / sqrt(2.0);
+ appearBuf->appendf("{0:.2f} {1:.2f} m\n",
+ cx + r2, cy + r2);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx + (1 - bezierCircle) * r2,
+ cy + (1 + bezierCircle) * r2,
+ cx - (1 - bezierCircle) * r2,
+ cy + (1 + bezierCircle) * r2,
+ cx - r2,
+ cy + r2);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx - (1 + bezierCircle) * r2,
+ cy + (1 - bezierCircle) * r2,
+ cx - (1 + bezierCircle) * r2,
+ cy - (1 - bezierCircle) * r2,
+ cx - r2,
+ cy - r2);
+ appearBuf->append("S\n");
+}
+
+// Draw the bottom-right half of an (approximate) circle of radius <r>
+// centered at (<cx>, <cy>).
+void Annot::drawCircleBottomRight(double cx, double cy, double r) {
+ double r2;
+
+ r2 = r / sqrt(2.0);
+ appearBuf->appendf("{0:.2f} {1:.2f} m\n",
+ cx - r2, cy - r2);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx - (1 - bezierCircle) * r2,
+ cy - (1 + bezierCircle) * r2,
+ cx + (1 - bezierCircle) * r2,
+ cy - (1 + bezierCircle) * r2,
+ cx + r2,
+ cy - r2);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx + (1 + bezierCircle) * r2,
+ cy - (1 - bezierCircle) * r2,
+ cx + (1 + bezierCircle) * r2,
+ cy + (1 - bezierCircle) * r2,
+ cx + r2,
+ cy + r2);
+ appearBuf->append("S\n");
+}
+
+void Annot::createForm(double *bbox, GBool transparencyGroup, Object *resDict, Object *aStream) {
+ Object obj1, obj2;
+ Object appearDict;
+
+ appearDict.initDict(xref);
+ appearDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
+ appearDict.dictSet("Subtype", obj1.initName("Form"));
+ obj1.initArray(xref);
+ obj1.arrayAdd(obj2.initReal(bbox[0]));
+ obj1.arrayAdd(obj2.initReal(bbox[1]));
+ obj1.arrayAdd(obj2.initReal(bbox[2]));
+ obj1.arrayAdd(obj2.initReal(bbox[3]));
+ appearDict.dictSet("BBox", &obj1);
+ if (transparencyGroup) {
+ Object transDict;
+ transDict.initDict(xref);
+ transDict.dictSet("S", obj1.initName("Transparency"));
+ appearDict.dictSet("Group", &transDict);
+ }
+ if (resDict)
+ appearDict.dictSet("Resources", resDict);
+
+ MemStream *mStream = new MemStream(copyString(appearBuf->getCString()), 0,
+ appearBuf->getLength(), &appearDict);
+ mStream->setNeedFree(gTrue);
+ aStream->initStream(mStream);
+}
+
+void Annot::createResourcesDict(const char *formName, Object *formStream,
+ const char *stateName,
+ double opacity, const char *blendMode,
+ Object *resDict) {
+ Object gsDict, stateDict, formDict, obj1;
+
+ gsDict.initDict(xref);
+ if (opacity != 1) {
+ gsDict.dictSet("CA", obj1.initReal(opacity));
+ gsDict.dictSet("ca", obj1.initReal(opacity));
+ }
+ if (blendMode)
+ gsDict.dictSet("BM", obj1.initName(blendMode));
+ stateDict.initDict(xref);
+ stateDict.dictSet(stateName, &gsDict);
+ formDict.initDict(xref);
+ formDict.dictSet(formName, formStream);
+
+ resDict->initDict(xref);
+ resDict->dictSet("ExtGState", &stateDict);
+ resDict->dictSet("XObject", &formDict);
+}
+
+Object *Annot::getAppearanceResDict(Object *dest) {
+ Object obj1, obj2;
+
+ dest->initNull(); // Default value
+
+ // Fetch appearance's resource dict (if any)
+ appearance.fetch(xref, &obj1);
+ if (obj1.isStream()) {
+ obj1.streamGetDict()->lookup("Resources", &obj2);
+ if (obj2.isDict()) {
+ obj2.copy(dest);
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ return dest;
+}
+
+GBool Annot::isVisible(GBool printing) {
+ // check the flags
+ if ((flags & flagHidden) ||
+ (printing && !(flags & flagPrint)) ||
+ (!printing && (flags & flagNoView))) {
+ return gFalse;
+ }
+
+ // check the OC
+ OCGs *optContentConfig = doc->getCatalog()->getOptContentConfig();
+ if (optContentConfig) {
+ if (! optContentConfig->optContentIsVisible(&oc))
+ return gFalse;
+ }
+
+ return gTrue;
+}
+
+int Annot::getRotation() const
+{
+ Page *pageobj = doc->getPage(page);
+ assert(pageobj != NULL);
+
+ if (flags & flagNoRotate) {
+ return (360 - pageobj->getRotate()) % 360;
+ } else {
+ return 0;
+ }
+}
+
+void Annot::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+
+ annotLocker();
+ if (!isVisible (printing))
+ return;
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotPopup
+//------------------------------------------------------------------------
+
+AnnotPopup::AnnotPopup(PDFDoc *docA, PDFRectangle *rect) :
+ Annot(docA, rect) {
+ Object obj1;
+
+ type = typePopup;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("Popup"));
+ initialize (docA, annotObj.getDict());
+}
+
+AnnotPopup::AnnotPopup(PDFDoc *docA, Dict *dict, Object *obj) :
+ Annot(docA, dict, obj) {
+ type = typePopup;
+ initialize(docA, dict);
+}
+
+AnnotPopup::~AnnotPopup() {
+ parent.free();
+}
+
+void AnnotPopup::initialize(PDFDoc *docA, Dict *dict) {
+ Object obj1;
+
+ if (!dict->lookupNF("Parent", &parent)->isRef()) {
+ parent.initNull();
+ }
+
+ if (dict->lookup("Open", &obj1)->isBool()) {
+ open = obj1.getBool();
+ } else {
+ open = gFalse;
+ }
+ obj1.free();
+}
+
+void AnnotPopup::setParent(Object *parentA) {
+ parentA->copy(&parent);
+ update ("Parent", &parent);
+}
+
+void AnnotPopup::setParent(Annot *parentA) {
+ Ref parentRef = parentA->getRef();
+ parent.initRef(parentRef.num, parentRef.gen);
+ update ("Parent", &parent);
+}
+
+void AnnotPopup::setOpen(GBool openA) {
+ Object obj1;
+
+ open = openA;
+ obj1.initBool(open);
+ update ("Open", &obj1);
+}
+
+//------------------------------------------------------------------------
+// AnnotMarkup
+//------------------------------------------------------------------------
+AnnotMarkup::AnnotMarkup(PDFDoc *docA, PDFRectangle *rect) :
+ Annot(docA, rect) {
+ initialize(docA, annotObj.getDict(), &annotObj);
+}
+
+AnnotMarkup::AnnotMarkup(PDFDoc *docA, Dict *dict, Object *obj) :
+ Annot(docA, dict, obj) {
+ initialize(docA, dict, obj);
+}
+
+AnnotMarkup::~AnnotMarkup() {
+ if (label)
+ delete label;
+
+ if (popup)
+ delete popup;
+
+ if (date)
+ delete date;
+
+ if (subject)
+ delete subject;
+}
+
+void AnnotMarkup::initialize(PDFDoc *docA, Dict *dict, Object *obj) {
+ Object obj1, obj2;
+
+ if (dict->lookup("T", &obj1)->isString()) {
+ label = obj1.getString()->copy();
+ } else {
+ label = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("Popup", &obj1)->isDict() && dict->lookupNF("Popup", &obj2)->isRef()) {
+ popup = new AnnotPopup(docA, obj1.getDict(), &obj2);
+ } else {
+ popup = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("CA", &obj1)->isNum()) {
+ opacity = obj1.getNum();
+ } else {
+ opacity = 1.0;
+ }
+ obj1.free();
+
+ if (dict->lookup("CreationDate", &obj1)->isString()) {
+ date = obj1.getString()->copy();
+ } else {
+ date = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookupNF("IRT", &obj1)->isRef()) {
+ inReplyTo = obj1.getRef();
+ } else {
+ inReplyTo.num = 0;
+ inReplyTo.gen = 0;
+ }
+ obj1.free();
+
+ if (dict->lookup("Subj", &obj1)->isString()) {
+ subject = obj1.getString()->copy();
+ } else {
+ subject = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("RT", &obj1)->isName()) {
+ const char *replyName = obj1.getName();
+
+ if (!strcmp(replyName, "R")) {
+ replyTo = replyTypeR;
+ } else if (!strcmp(replyName, "Group")) {
+ replyTo = replyTypeGroup;
+ } else {
+ replyTo = replyTypeR;
+ }
+ } else {
+ replyTo = replyTypeR;
+ }
+ obj1.free();
+
+ if (dict->lookup("ExData", &obj1)->isDict()) {
+ exData = parseAnnotExternalData(obj1.getDict());
+ } else {
+ exData = annotExternalDataMarkupUnknown;
+ }
+ obj1.free();
+}
+
+void AnnotMarkup::setLabel(GooString *new_label) {
+ delete label;
+
+ if (new_label) {
+ label = new GooString(new_label);
+ //append the unicode marker <FE FF> if needed
+ if (!label->hasUnicodeMarker()) {
+ label->insert(0, 0xff);
+ label->insert(0, 0xfe);
+ }
+ } else {
+ label = new GooString();
+ }
+
+ Object obj1;
+ obj1.initString(label->copy());
+ update ("T", &obj1);
+}
+
+void AnnotMarkup::setPopup(AnnotPopup *new_popup) {
+ // If there exists an old popup annotation that is already
+ // associated with a page, then we need to remove that
+ // popup annotation from the page. Otherwise we would have
+ // dangling references to it.
+ if (popup != NULL && popup->getPageNum() != 0) {
+ Page *pageobj = doc->getPage(popup->getPageNum());
+ if (pageobj) {
+ pageobj->removeAnnot(popup);
+ }
+ }
+ delete popup;
+
+ if (new_popup) {
+ Object obj1;
+ Ref popupRef = new_popup->getRef();
+
+ obj1.initRef (popupRef.num, popupRef.gen);
+ update ("Popup", &obj1);
+
+ new_popup->setParent(this);
+ popup = new_popup;
+
+ // If this annotation is already added to a page, then we
+ // add the new popup annotation to the same page.
+ if (page != 0) {
+ Page *pageobj = doc->getPage(page);
+ assert(pageobj != NULL); // pageobj should exist in doc (see setPage())
+
+ pageobj->addAnnot(popup);
+ }
+ } else {
+ popup = NULL;
+ }
+}
+
+void AnnotMarkup::setOpacity(double opacityA) {
+ Object obj1;
+
+ opacity = opacityA;
+ obj1.initReal(opacity);
+ update ("CA", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotMarkup::setDate(GooString *new_date) {
+ delete date;
+
+ if (new_date)
+ date = new GooString(new_date);
+ else
+ date = new GooString();
+
+ Object obj1;
+ obj1.initString(date->copy());
+ update ("CreationDate", &obj1);
+}
+
+void AnnotMarkup::removeReferencedObjects() {
+ Page *pageobj = doc->getPage(page);
+ assert(pageobj != NULL); // We're called when removing an annot from a page
+
+ // Remove popup
+ if (popup) {
+ pageobj->removeAnnot(popup);
+ }
+
+ Annot::removeReferencedObjects();
+}
+
+//------------------------------------------------------------------------
+// AnnotText
+//------------------------------------------------------------------------
+
+AnnotText::AnnotText(PDFDoc *docA, PDFRectangle *rect) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ type = typeText;
+ flags |= flagNoZoom | flagNoRotate;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("Text"));
+ initialize (docA, annotObj.getDict());
+}
+
+AnnotText::AnnotText(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+
+ type = typeText;
+ flags |= flagNoZoom | flagNoRotate;
+ initialize (docA, dict);
+}
+
+AnnotText::~AnnotText() {
+ delete icon;
+}
+
+void AnnotText::initialize(PDFDoc *docA, Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("Open", &obj1)->isBool())
+ open = obj1.getBool();
+ else
+ open = gFalse;
+ obj1.free();
+
+ if (dict->lookup("Name", &obj1)->isName()) {
+ icon = new GooString(obj1.getName());
+ } else {
+ icon = new GooString("Note");
+ }
+ obj1.free();
+
+ if (dict->lookup("StateModel", &obj1)->isString()) {
+ Object obj2;
+ GooString *modelName = obj1.getString();
+
+ if (dict->lookup("State", &obj2)->isString()) {
+ GooString *stateName = obj2.getString();
+
+ if (!stateName->cmp("Marked")) {
+ state = stateMarked;
+ } else if (!stateName->cmp("Unmarked")) {
+ state = stateUnmarked;
+ } else if (!stateName->cmp("Accepted")) {
+ state = stateAccepted;
+ } else if (!stateName->cmp("Rejected")) {
+ state = stateRejected;
+ } else if (!stateName->cmp("Cancelled")) {
+ state = stateCancelled;
+ } else if (!stateName->cmp("Completed")) {
+ state = stateCompleted;
+ } else if (!stateName->cmp("None")) {
+ state = stateNone;
+ } else {
+ state = stateUnknown;
+ }
+ } else {
+ state = stateUnknown;
+ }
+ obj2.free();
+
+ if (!modelName->cmp("Marked")) {
+ switch (state) {
+ case stateUnknown:
+ state = stateMarked;
+ break;
+ case stateAccepted:
+ case stateRejected:
+ case stateCancelled:
+ case stateCompleted:
+ case stateNone:
+ state = stateUnknown;
+ break;
+ default:
+ break;
+ }
+ } else if (!modelName->cmp("Review")) {
+ switch (state) {
+ case stateUnknown:
+ state = stateNone;
+ break;
+ case stateMarked:
+ case stateUnmarked:
+ state = stateUnknown;
+ break;
+ default:
+ break;
+ }
+ } else {
+ state = stateUnknown;
+ }
+ } else {
+ state = stateUnknown;
+ }
+ obj1.free();
+}
+
+void AnnotText::setOpen(GBool openA) {
+ Object obj1;
+
+ open = openA;
+ obj1.initBool(open);
+ update ("Open", &obj1);
+}
+
+void AnnotText::setIcon(GooString *new_icon) {
+ if (new_icon && icon->cmp(new_icon) == 0)
+ return;
+
+ delete icon;
+
+ if (new_icon) {
+ icon = new GooString (new_icon);
+ } else {
+ icon = new GooString("Note");
+ }
+
+ Object obj1;
+ obj1.initName (icon->getCString());
+ update("Name", &obj1);
+ invalidateAppearance();
+}
+
+#define ANNOT_TEXT_AP_NOTE \
+ "3.602 24 m 20.398 24 l 22.387 24 24 22.387 24 20.398 c 24 3.602 l 24\n" \
+ "1.613 22.387 0 20.398 0 c 3.602 0 l 1.613 0 0 1.613 0 3.602 c 0 20.398\n" \
+ "l 0 22.387 1.613 24 3.602 24 c h\n" \
+ "3.602 24 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 9 18 m 4 18 l 4 7 4 4 6 3 c 20 3 l 18 4 18 7 18 18 c 17 18 l S\n" \
+ "1.5 w\n" \
+ "0 j\n" \
+ "10 16 m 14 21 l S\n" \
+ "1.85625 w\n" \
+ "1 j\n" \
+ "15.07 20.523 m 15.07 19.672 14.379 18.977 13.523 18.977 c 12.672 18.977\n" \
+ "11.977 19.672 11.977 20.523 c 11.977 21.379 12.672 22.07 13.523 22.07 c\n" \
+ "14.379 22.07 15.07 21.379 15.07 20.523 c h\n" \
+ "15.07 20.523 m S\n" \
+ "1 w\n" \
+ "0 j\n" \
+ "6.5 13.5 m 15.5 13.5 l S\n" \
+ "6.5 10.5 m 13.5 10.5 l S\n" \
+ "6.801 7.5 m 15.5 7.5 l S\n" \
+ "0.729412 0.741176 0.713725 RG 2 w\n" \
+ "1 j\n" \
+ "9 19 m 4 19 l 4 8 4 5 6 4 c 20 4 l 18 5 18 8 18 19 c 17 19 l S\n" \
+ "1.5 w\n" \
+ "0 j\n" \
+ "10 17 m 14 22 l S\n" \
+ "1.85625 w\n" \
+ "1 j\n" \
+ "15.07 21.523 m 15.07 20.672 14.379 19.977 13.523 19.977 c 12.672 19.977\n" \
+ "11.977 20.672 11.977 21.523 c 11.977 22.379 12.672 23.07 13.523 23.07 c\n" \
+ "14.379 23.07 15.07 22.379 15.07 21.523 c h\n" \
+ "15.07 21.523 m S\n" \
+ "1 w\n" \
+ "0 j\n" \
+ "6.5 14.5 m 15.5 14.5 l S\n" \
+ "6.5 11.5 m 13.5 11.5 l S\n" \
+ "6.801 8.5 m 15.5 8.5 l S\n"
+
+#define ANNOT_TEXT_AP_COMMENT \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "0 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 8 20 m 16 20 l 18.363 20 20 18.215 20 16 c 20 13 l 20 10.785 18.363 9\n" \
+ "16 9 c 13 9 l 8 3 l 8 9 l 8 9 l 5.637 9 4 10.785 4 13 c 4 16 l 4 18.215\n" \
+ "5.637 20 8 20 c h\n" \
+ "8 20 m S\n" \
+ "0.729412 0.741176 0.713725 RG 8 21 m 16 21 l 18.363 21 20 19.215 20 17\n" \
+ "c 20 14 l 20 11.785 18.363 10\n" \
+ "16 10 c 13 10 l 8 4 l 8 10 l 8 10 l 5.637 10 4 11.785 4 14 c 4 17 l 4\n" \
+ "19.215 5.637 21 8 21 c h\n" \
+ "8 21 m S\n"
+
+#define ANNOT_TEXT_AP_KEY \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "1 J\n" \
+ "0 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 11.895 18.754 m 13.926 20.625 17.09 20.496 18.961 18.465 c 20.832\n" \
+ "16.434 20.699 13.27 18.668 11.398 c 17.164 10.016 15.043 9.746 13.281\n" \
+ "10.516 c 12.473 9.324 l 11.281 10.078 l 9.547 8.664 l 9.008 6.496 l\n" \
+ "7.059 6.059 l 6.34 4.121 l 5.543 3.668 l 3.375 4.207 l 2.938 6.156 l\n" \
+ "10.57 13.457 l 9.949 15.277 10.391 17.367 11.895 18.754 c h\n" \
+ "11.895 18.754 m S\n" \
+ "1.5 w\n" \
+ "16.059 15.586 m 16.523 15.078 17.316 15.043 17.824 15.512 c 18.332\n" \
+ "15.98 18.363 16.77 17.895 17.277 c 17.43 17.785 16.637 17.816 16.129\n" \
+ "17.352 c 15.621 16.883 15.59 16.094 16.059 15.586 c h\n" \
+ "16.059 15.586 m S\n" \
+ "0.729412 0.741176 0.713725 RG 2 w\n" \
+ "11.895 19.754 m 13.926 21.625 17.09 21.496 18.961 19.465 c 20.832\n" \
+ "17.434 20.699 14.27 18.668 12.398 c 17.164 11.016 15.043 10.746 13.281\n" \
+ "11.516 c 12.473 10.324 l 11.281 11.078 l 9.547 9.664 l 9.008 7.496 l\n" \
+ "7.059 7.059 l 6.34 5.121 l 5.543 4.668 l 3.375 5.207 l 2.938 7.156 l\n" \
+ "10.57 14.457 l 9.949 16.277 10.391 18.367 11.895 19.754 c h\n" \
+ "11.895 19.754 m S\n" \
+ "1.5 w\n" \
+ "16.059 16.586 m 16.523 16.078 17.316 16.043 17.824 16.512 c 18.332\n" \
+ "16.98 18.363 17.77 17.895 18.277 c 17.43 18.785 16.637 18.816 16.129\n" \
+ "18.352 c 15.621 17.883 15.59 17.094 16.059 16.586 c h\n" \
+ "16.059 16.586 m S\n"
+
+#define ANNOT_TEXT_AP_HELP \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2.5 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 8.289 16.488 m 8.824 17.828 10.043 18.773 11.473 18.965 c 12.902 19.156\n" \
+ "14.328 18.559 15.195 17.406 c 16.062 16.254 16.242 14.723 15.664 13.398\n" \
+ "c S\n" \
+ "0 j\n" \
+ "12 8 m 12 12 16 11 16 15 c S\n" \
+ "1.539286 w\n" \
+ "1 j\n" \
+ "q 1 0 0 -0.999991 0 24 cm\n" \
+ "12.684 20.891 m 12.473 21.258 12.004 21.395 11.629 21.196 c 11.254\n" \
+ "20.992 11.105 20.531 11.297 20.149 c 11.488 19.77 11.945 19.61 12.332\n" \
+ "19.789 c 12.719 19.969 12.891 20.426 12.719 20.817 c S Q\n" \
+ "0.729412 0.741176 0.713725 RG 2.5 w\n" \
+ "8.289 17.488 m 9.109 19.539 11.438 20.535 13.488 19.711 c 15.539 18.891\n" \
+ "16.535 16.562 15.711 14.512 c 15.699 14.473 15.684 14.438 15.664 14.398\n" \
+ "c S\n" \
+ "0 j\n" \
+ "12 9 m 12 13 16 12 16 16 c S\n" \
+ "1.539286 w\n" \
+ "1 j\n" \
+ "q 1 0 0 -0.999991 0 24 cm\n" \
+ "12.684 19.891 m 12.473 20.258 12.004 20.395 11.629 20.195 c 11.254\n" \
+ "19.992 11.105 19.531 11.297 19.149 c 11.488 18.77 11.945 18.61 12.332\n" \
+ "18.789 c 12.719 18.969 12.891 19.426 12.719 19.817 c S Q\n"
+
+#define ANNOT_TEXT_AP_NEW_PARAGRAPH \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 4 w\n" \
+ "0 J\n" \
+ "2 j\n" \
+ "[] 0.0 d\n" \
+ "4 M q 1 0 0 -1 0 24 cm\n" \
+ "9.211 11.988 m 8.449 12.07 7.711 11.707 7.305 11.059 c 6.898 10.41\n" \
+ "6.898 9.59 7.305 8.941 c 7.711 8.293 8.449 7.93 9.211 8.012 c S Q\n" \
+ "1.004413 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "q 1 0 0 -0.991232 0 24 cm\n" \
+ "18.07 11.511 m 15.113 10.014 l 12.199 11.602 l 12.711 8.323 l 10.301\n" \
+ "6.045 l 13.574 5.517 l 14.996 2.522 l 16.512 5.474 l 19.801 5.899 l\n" \
+ "17.461 8.252 l 18.07 11.511 l h\n" \
+ "18.07 11.511 m S Q\n" \
+ "2 w\n" \
+ "0 j\n" \
+ "11 17 m 10 17 l 10 3 l S\n" \
+ "14 3 m 14 13 l S\n" \
+ "0.729412 0.741176 0.713725 RG 4 w\n" \
+ "0 J\n" \
+ "2 j\n" \
+ "q 1 0 0 -1 0 24 cm\n" \
+ "9.211 10.988 m 8.109 11.105 7.125 10.309 7.012 9.211 c 6.895 8.109\n" \
+ "7.691 7.125 8.789 7.012 c 8.93 6.996 9.07 6.996 9.211 7.012 c S Q\n" \
+ "1.004413 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "q 1 0 0 -0.991232 0 24 cm\n" \
+ "18.07 10.502 m 15.113 9.005 l 12.199 10.593 l 12.711 7.314 l 10.301\n" \
+ "5.036 l 13.574 4.508 l 14.996 1.513 l 16.512 4.465 l 19.801 4.891 l\n" \
+ "17.461 7.243 l 18.07 10.502 l h\n" \
+ "18.07 10.502 m S Q\n" \
+ "2 w\n" \
+ "0 j\n" \
+ "11 18 m 10 18 l 10 4 l S\n" \
+ "14 4 m 14 14 l S\n"
+
+#define ANNOT_TEXT_AP_PARAGRAPH \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 15 3 m 15 18 l 11 18 l 11 3 l S\n" \
+ "4 w\n" \
+ "q 1 0 0 -1 0 24 cm\n" \
+ "9.777 10.988 m 8.746 10.871 7.973 9.988 8 8.949 c 8.027 7.91 8.844\n" \
+ "7.066 9.879 7.004 c S Q\n" \
+ "0.729412 0.741176 0.713725 RG 2 w\n" \
+ "15 4 m 15 19 l 11 19 l 11 4 l S\n" \
+ "4 w\n" \
+ "q 1 0 0 -1 0 24 cm\n" \
+ "9.777 9.988 m 8.746 9.871 7.973 8.988 8 7.949 c 8.027 6.91 8.844 6.066\n" \
+ "9.879 6.004 c S Q\n"
+
+#define ANNOT_TEXT_AP_INSERT \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "1 J\n" \
+ "0 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 12 18.012 m 20 18 l S\n" \
+ "9 10 m 17 10 l S\n" \
+ "12 14.012 m 20 14 l S\n" \
+ "12 6.012 m 20 6.012 l S\n" \
+ "4 12 m 6 10 l 4 8 l S\n" \
+ "4 12 m 4 8 l S\n" \
+ "0.729412 0.741176 0.713725 RG 12 19.012 m 20 19 l S\n" \
+ "9 11 m 17 11 l S\n" \
+ "12 15.012 m 20 15 l S\n" \
+ "12 7.012 m 20 7.012 l S\n" \
+ "4 13 m 6 11 l 4 9 l S\n" \
+ "4 13 m 4 9 l S\n"
+
+#define ANNOT_TEXT_AP_CROSS \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2.5 w\n" \
+ "1 J\n" \
+ "0 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 18 5 m 6 17 l S\n" \
+ "6 5 m 18 17 l S\n" \
+ "0.729412 0.741176 0.713725 RG 18 6 m 6 18 l S\n" \
+ "6 6 m 18 18 l S\n"
+
+#define ANNOT_TEXT_AP_CIRCLE \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2.5 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 19.5 11.5 m 19.5 7.359 16.141 4 12 4 c 7.859 4 4.5 7.359 4.5 11.5 c 4.5\n" \
+ "15.641 7.859 19 12 19 c 16.141 19 19.5 15.641 19.5 11.5 c h\n" \
+ "19.5 11.5 m S\n" \
+ "0.729412 0.741176 0.713725 RG 19.5 12.5 m 19.5 8.359 16.141 5 12 5 c\n" \
+ "7.859 5 4.5 8.359 4.5 12.5 c 4.5\n" \
+ "16.641 7.859 20 12 20 c 16.141 20 19.5 16.641 19.5 12.5 c h\n" \
+ "19.5 12.5 m S\n"
+
+void AnnotText::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+ double ca = 1;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull()) {
+ ca = opacity;
+
+ appearBuf = new GooString ();
+
+ appearBuf->append ("q\n");
+ if (color)
+ setColor(color, gTrue);
+ else
+ appearBuf->append ("1 1 1 rg\n");
+ if (!icon->cmp("Note"))
+ appearBuf->append (ANNOT_TEXT_AP_NOTE);
+ else if (!icon->cmp("Comment"))
+ appearBuf->append (ANNOT_TEXT_AP_COMMENT);
+ else if (!icon->cmp("Key"))
+ appearBuf->append (ANNOT_TEXT_AP_KEY);
+ else if (!icon->cmp("Help"))
+ appearBuf->append (ANNOT_TEXT_AP_HELP);
+ else if (!icon->cmp("NewParagraph"))
+ appearBuf->append (ANNOT_TEXT_AP_NEW_PARAGRAPH);
+ else if (!icon->cmp("Paragraph"))
+ appearBuf->append (ANNOT_TEXT_AP_PARAGRAPH);
+ else if (!icon->cmp("Insert"))
+ appearBuf->append (ANNOT_TEXT_AP_INSERT);
+ else if (!icon->cmp("Cross"))
+ appearBuf->append (ANNOT_TEXT_AP_CROSS);
+ else if (!icon->cmp("Circle"))
+ appearBuf->append (ANNOT_TEXT_AP_CIRCLE);
+ appearBuf->append ("Q\n");
+
+ // Force 24x24 rectangle
+ PDFRectangle fixedRect(rect->x1, rect->y2 - 24, rect->x1 + 24, rect->y2);
+ appearBBox = new AnnotAppearanceBBox(&fixedRect);
+ double bbox[4];
+ appearBBox->getBBoxRect(bbox);
+ if (ca == 1) {
+ createForm(bbox, gFalse, NULL, &appearance);
+ } else {
+ Object aStream, resDict;
+
+ createForm(bbox, gTrue, NULL, &aStream);
+ delete appearBuf;
+
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ if (appearBBox) {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ appearBBox->getPageXMin(), appearBBox->getPageYMin(),
+ appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+ getRotation());
+ } else {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ }
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotLink
+//------------------------------------------------------------------------
+AnnotLink::AnnotLink(PDFDoc *docA, PDFRectangle *rect) :
+ Annot(docA, rect) {
+ Object obj1;
+
+ type = typeLink;
+ annotObj.dictSet ("Subtype", obj1.initName ("Link"));
+ initialize (docA, annotObj.getDict());
+}
+
+AnnotLink::AnnotLink(PDFDoc *docA, Dict *dict, Object *obj) :
+ Annot(docA, dict, obj) {
+
+ type = typeLink;
+ initialize (docA, dict);
+}
+
+AnnotLink::~AnnotLink() {
+ delete action;
+ /*
+ if (uriAction)
+ delete uriAction;
+ */
+ if (quadrilaterals)
+ delete quadrilaterals;
+}
+
+void AnnotLink::initialize(PDFDoc *docA, Dict *dict) {
+ Object obj1;
+
+ action = NULL;
+
+ // look for destination
+ if (!dict->lookup("Dest", &obj1)->isNull()) {
+ action = LinkAction::parseDest(&obj1);
+ // look for action
+ } else {
+ obj1.free();
+ if (dict->lookup("A", &obj1)->isDict()) {
+ action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
+ }
+ }
+ obj1.free();
+
+ if (dict->lookup("H", &obj1)->isName()) {
+ const char *effect = obj1.getName();
+
+ if (!strcmp(effect, "N")) {
+ linkEffect = effectNone;
+ } else if (!strcmp(effect, "I")) {
+ linkEffect = effectInvert;
+ } else if (!strcmp(effect, "O")) {
+ linkEffect = effectOutline;
+ } else if (!strcmp(effect, "P")) {
+ linkEffect = effectPush;
+ } else {
+ linkEffect = effectInvert;
+ }
+ } else {
+ linkEffect = effectInvert;
+ }
+ obj1.free();
+ /*
+ if (dict->lookup("PA", &obj1)->isDict()) {
+ uriAction = NULL;
+ } else {
+ uriAction = NULL;
+ }
+ obj1.free();
+ */
+ if (dict->lookup("QuadPoints", &obj1)->isArray()) {
+ quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
+ } else {
+ quadrilaterals = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ delete border;
+ border = new AnnotBorderBS(obj1.getDict());
+ } else if (!border) {
+ border = new AnnotBorderBS();
+ }
+ obj1.free();
+}
+
+void AnnotLink::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ gfx->drawAnnot(&obj, border, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotFreeText
+//------------------------------------------------------------------------
+AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ type = typeFreeText;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("FreeText"));
+
+ Object obj2;
+ obj2.initString (da->copy());
+ annotObj.dictSet("DA", &obj2);
+
+ initialize (docA, annotObj.getDict());
+}
+
+AnnotFreeText::AnnotFreeText(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ type = typeFreeText;
+ initialize(docA, dict);
+}
+
+AnnotFreeText::~AnnotFreeText() {
+ delete appearanceString;
+
+ if (styleString)
+ delete styleString;
+
+ if (calloutLine)
+ delete calloutLine;
+
+ if (borderEffect)
+ delete borderEffect;
+
+ if (rectangle)
+ delete rectangle;
+}
+
+void AnnotFreeText::initialize(PDFDoc *docA, Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("DA", &obj1)->isString()) {
+ appearanceString = obj1.getString()->copy();
+ } else {
+ appearanceString = new GooString();
+ error(errSyntaxError, -1, "Bad appearance for annotation");
+ ok = gFalse;
+ }
+ obj1.free();
+
+ if (dict->lookup("Q", &obj1)->isInt()) {
+ quadding = (AnnotFreeTextQuadding) obj1.getInt();
+ } else {
+ quadding = quaddingLeftJustified;
+ }
+ obj1.free();
+
+ if (dict->lookup("DS", &obj1)->isString()) {
+ styleString = obj1.getString()->copy();
+ } else {
+ styleString = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("CL", &obj1)->isArray() && obj1.arrayGetLength() >= 4) {
+ double x1, y1, x2, y2;
+ Object obj2;
+
+ (obj1.arrayGet(0, &obj2)->isNum() ? x1 = obj2.getNum() : x1 = 0);
+ obj2.free();
+ (obj1.arrayGet(1, &obj2)->isNum() ? y1 = obj2.getNum() : y1 = 0);
+ obj2.free();
+ (obj1.arrayGet(2, &obj2)->isNum() ? x2 = obj2.getNum() : x2 = 0);
+ obj2.free();
+ (obj1.arrayGet(3, &obj2)->isNum() ? y2 = obj2.getNum() : y2 = 0);
+ obj2.free();
+
+ if (obj1.arrayGetLength() == 6) {
+ double x3, y3;
+ (obj1.arrayGet(4, &obj2)->isNum() ? x3 = obj2.getNum() : x3 = 0);
+ obj2.free();
+ (obj1.arrayGet(5, &obj2)->isNum() ? y3 = obj2.getNum() : y3 = 0);
+ obj2.free();
+ calloutLine = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
+ } else {
+ calloutLine = new AnnotCalloutLine(x1, y1, x2, y2);
+ }
+ } else {
+ calloutLine = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("IT", &obj1)->isName()) {
+ const char *intentName = obj1.getName();
+
+ if (!strcmp(intentName, "FreeText")) {
+ intent = intentFreeText;
+ } else if (!strcmp(intentName, "FreeTextCallout")) {
+ intent = intentFreeTextCallout;
+ } else if (!strcmp(intentName, "FreeTextTypeWriter")) {
+ intent = intentFreeTextTypeWriter;
+ } else {
+ intent = intentFreeText;
+ }
+ } else {
+ intent = intentFreeText;
+ }
+ obj1.free();
+
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ delete border;
+ border = new AnnotBorderBS(obj1.getDict());
+ } else if (!border) {
+ border = new AnnotBorderBS();
+ }
+ obj1.free();
+
+ if (dict->lookup("BE", &obj1)->isDict()) {
+ borderEffect = new AnnotBorderEffect(obj1.getDict());
+ } else {
+ borderEffect = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("RD", &obj1)->isArray()) {
+ rectangle = parseDiffRectangle(obj1.getArray(), rect);
+ } else {
+ rectangle = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("LE", &obj1)->isName()) {
+ GooString styleName(obj1.getName());
+ endStyle = parseAnnotLineEndingStyle(&styleName);
+ } else {
+ endStyle = annotLineEndingNone;
+ }
+ obj1.free();
+}
+
+void AnnotFreeText::setContents(GooString *new_content) {
+ Annot::setContents(new_content);
+ invalidateAppearance();
+}
+
+void AnnotFreeText::setAppearanceString(GooString *new_string) {
+ delete appearanceString;
+
+ if (new_string) {
+ appearanceString = new GooString(new_string);
+ } else {
+ appearanceString = new GooString();
+ }
+
+ Object obj1;
+ obj1.initString(appearanceString->copy());
+ update ("DA", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotFreeText::setQuadding(AnnotFreeTextQuadding new_quadding) {
+ Object obj1;
+ quadding = new_quadding;
+ obj1.initInt((int)quadding);
+ update ("Q", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotFreeText::setStyleString(GooString *new_string) {
+ delete styleString;
+
+ if (new_string) {
+ styleString = new GooString(new_string);
+ //append the unicode marker <FE FF> if needed
+ if (!styleString->hasUnicodeMarker()) {
+ styleString->insert(0, 0xff);
+ styleString->insert(0, 0xfe);
+ }
+ } else {
+ styleString = new GooString();
+ }
+
+ Object obj1;
+ obj1.initString(styleString->copy());
+ update ("DS", &obj1);
+}
+
+void AnnotFreeText::setCalloutLine(AnnotCalloutLine *line) {
+ delete calloutLine;
+
+ Object obj1;
+ if (line == NULL) {
+ obj1.initNull();
+ calloutLine = NULL;
+ } else {
+ double x1 = line->getX1(), y1 = line->getY1();
+ double x2 = line->getX2(), y2 = line->getY2();
+ Object obj2;
+ obj1.initArray(xref);
+ obj1.arrayAdd( obj2.initReal(x1) );
+ obj1.arrayAdd( obj2.initReal(y1) );
+ obj1.arrayAdd( obj2.initReal(x2) );
+ obj1.arrayAdd( obj2.initReal(y2) );
+
+ AnnotCalloutMultiLine *mline = dynamic_cast<AnnotCalloutMultiLine*>(line);
+ if (mline) {
+ double x3 = mline->getX3(), y3 = mline->getY3();
+ obj1.arrayAdd( obj2.initReal(x3) );
+ obj1.arrayAdd( obj2.initReal(y3) );
+ calloutLine = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
+ } else {
+ calloutLine = new AnnotCalloutLine(x1, y1, x2, y2);
+ }
+ }
+
+ update("CL", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent) {
+ Object obj1;
+
+ intent = new_intent;
+ if (new_intent == intentFreeText)
+ obj1.initName("FreeText");
+ else if (new_intent == intentFreeTextCallout)
+ obj1.initName("FreeTextCallout");
+ else // intentFreeTextTypeWriter
+ obj1.initName("FreeTextTypeWriter");
+ update ("IT", &obj1);
+}
+
+static GfxFont * createAnnotDrawFont(XRef * xref, Object *fontResDict)
+{
+ Ref dummyRef = { -1, -1 };
+
+ Object baseFontObj, subtypeObj, encodingObj;
+ baseFontObj.initName("Helvetica");
+ subtypeObj.initName("Type0");
+ encodingObj.initName("WinAnsiEncoding");
+
+ Object fontDictObj;
+ Dict *fontDict = new Dict(xref);
+ fontDict->decRef();
+ fontDict->add(copyString("BaseFont"), &baseFontObj);
+ fontDict->add(copyString("Subtype"), &subtypeObj);
+ fontDict->add(copyString("Encoding"), &encodingObj);
+ fontDictObj.initDict(fontDict);
+
+ Object fontsDictObj;
+ Dict *fontsDict = new Dict(xref);
+ fontsDict->decRef();
+ fontsDict->add(copyString("AnnotDrawFont"), &fontDictObj);
+ fontsDictObj.initDict(fontsDict);
+
+ Dict *dict = new Dict(xref);
+ dict->add(copyString("Font"), &fontsDictObj);
+
+ fontResDict->initDict(dict);
+ return GfxFont::makeFont(xref, "AnnotDrawFont", dummyRef, fontDict);
+}
+
+void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor) {
+ fontsize = -1;
+ fontcolor = NULL;
+ if (da) {
+ GooList * daToks = new GooList();
+ int j, i = 0;
+
+ // Tokenize
+ while (i < da->getLength()) {
+ while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
+ ++i;
+ }
+ if (i < da->getLength()) {
+ for (j = i + 1; j < da->getLength() && !Lexer::isSpace(da->getChar(j)); ++j) {
+ }
+ daToks->append(new GooString(da, i, j - i));
+ i = j;
+ }
+ }
+
+ // Scan backwards: we are looking for the last set value
+ for (i = daToks->getLength()-1; i >= 0; --i) {
+ if (fontsize == -1) {
+ if (!((GooString *)daToks->get(i))->cmp("Tf") && i >= 2) {
+ // TODO: Font name
+ fontsize = gatof(( (GooString *)daToks->get(i-1) )->getCString());
+ }
+ }
+ if (fontcolor == NULL) {
+ if (!((GooString *)daToks->get(i))->cmp("g") && i >= 1) {
+ fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+ } else if (!((GooString *)daToks->get(i))->cmp("rg") && i >= 3) {
+ fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-3) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-2) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+ } else if (!((GooString *)daToks->get(i))->cmp("k") && i >= 4) {
+ fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-4) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-3) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-2) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+ }
+ }
+ }
+ deleteGooList(daToks, GooString);
+ }
+}
+
+void AnnotFreeText::generateFreeTextAppearance()
+{
+ double borderWidth, ca = opacity;
+
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+
+ borderWidth = border->getWidth();
+ if (borderWidth > 0)
+ setLineStyleForBorder(border);
+
+ // Box size
+ const double width = rect->x2 - rect->x1;
+ const double height = rect->y2 - rect->y1;
+
+ // Parse some properties from the appearance string
+ double fontsize;
+ AnnotColor *fontcolor;
+ parseAppearanceString(appearanceString, fontsize, fontcolor);
+ // Default values
+ if (fontsize <= 0)
+ fontsize = 10;
+ if (fontcolor == NULL)
+ fontcolor = new AnnotColor(0, 0, 0); // Black
+ if (!contents)
+ contents = new GooString ();
+
+ // Draw box
+ GBool doFill = (color && color->getSpace() != AnnotColor::colorTransparent);
+ GBool doStroke = (borderWidth != 0);
+ if (doFill || doStroke) {
+ if (doStroke) {
+ setColor(fontcolor, gFalse); // Border color: same as font color
+ }
+ appearBuf->appendf ("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re\n", borderWidth/2, width-borderWidth, height-borderWidth);
+ if (doFill) {
+ setColor(color, gTrue);
+ appearBuf->append(doStroke ? "B\n" : "f\n");
+ } else {
+ appearBuf->append("S\n");
+ }
+ }
+
+ // Setup text clipping
+ const double textmargin = borderWidth * 2;
+ const double textwidth = width - 2*textmargin;
+ appearBuf->appendf ("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", textmargin, textwidth, height - 2*textmargin);
+
+ Object fontResDict;
+ GfxFont *font = createAnnotDrawFont(xref, &fontResDict);
+
+ // Set font state
+ setColor(fontcolor, gTrue);
+ appearBuf->appendf ("BT 1 0 0 1 {0:.2f} {1:.2f} Tm\n", textmargin, height - textmargin - fontsize * font->getDescent());
+ appearBuf->appendf ("/AnnotDrawFont {0:.2f} Tf\n", fontsize);
+
+ int i = 0;
+ double xposPrev = 0;
+ while (i < contents->getLength()) {
+ GooString out;
+ double linewidth, xpos;
+ layoutText(contents, &out, &i, font, &linewidth, textwidth/fontsize, NULL, gFalse);
+ linewidth *= fontsize;
+ switch (quadding) {
+ case quaddingCentered:
+ xpos = (textwidth - linewidth) / 2;
+ break;
+ case quaddingRightJustified:
+ xpos = textwidth - linewidth;
+ break;
+ default: // quaddingLeftJustified:
+ xpos = 0;
+ break;
+ }
+ appearBuf->appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -fontsize);
+ writeString(&out, appearBuf);
+ appearBuf->append("Tj\n");
+ xposPrev = xpos;
+ }
+
+ font->decRefCnt();
+ delete fontcolor;
+ appearBuf->append ("ET Q\n");
+
+ double bbox[4];
+ bbox[0] = bbox[1] = 0;
+ bbox[2] = rect->x2 - rect->x1;
+ bbox[3] = rect->y2 - rect->y1;
+
+ if (ca == 1) {
+ createForm(bbox, gFalse, &fontResDict, &appearance);
+ } else {
+ Object aStream, resDict;
+
+ createForm(bbox, gTrue, &fontResDict, &aStream);
+ delete appearBuf;
+
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+}
+
+void AnnotFreeText::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull()) {
+ generateFreeTextAppearance();
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ obj.free();
+}
+
+// Before retrieving the res dict, regenerate the appearance stream if needed,
+// because AnnotFreeText::draw needs to store font info in the res dict
+Object *AnnotFreeText::getAppearanceResDict(Object *dest) {
+ if (appearance.isNull()) {
+ generateFreeTextAppearance();
+ }
+ return Annot::getAppearanceResDict(dest);
+}
+
+//------------------------------------------------------------------------
+// AnnotLine
+//------------------------------------------------------------------------
+
+AnnotLine::AnnotLine(PDFDoc *docA, PDFRectangle *rect) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ type = typeLine;
+ annotObj.dictSet ("Subtype", obj1.initName ("Line"));
+
+ initialize (docA, annotObj.getDict());
+}
+
+AnnotLine::AnnotLine(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ type = typeLine;
+ initialize(docA, dict);
+}
+
+AnnotLine::~AnnotLine() {
+ delete coord1;
+ delete coord2;
+
+ if (interiorColor)
+ delete interiorColor;
+
+ if (measure)
+ delete measure;
+}
+
+void AnnotLine::initialize(PDFDoc *docA, Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("L", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
+ Object obj2;
+ double x1, y1, x2, y2;
+
+ (obj1.arrayGet(0, &obj2)->isNum() ? x1 = obj2.getNum() : x1 = 0);
+ obj2.free();
+ (obj1.arrayGet(1, &obj2)->isNum() ? y1 = obj2.getNum() : y1 = 0);
+ obj2.free();
+ (obj1.arrayGet(2, &obj2)->isNum() ? x2 = obj2.getNum() : x2 = 0);
+ obj2.free();
+ (obj1.arrayGet(3, &obj2)->isNum() ? y2 = obj2.getNum() : y2 = 0);
+ obj2.free();
+
+ coord1 = new AnnotCoord(x1, y1);
+ coord2 = new AnnotCoord(x2, y2);
+ } else {
+ coord1 = new AnnotCoord();
+ coord2 = new AnnotCoord();
+ }
+ obj1.free();
+
+ if (dict->lookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
+ Object obj2;
+
+ if(obj1.arrayGet(0, &obj2)->isString())
+ startStyle = parseAnnotLineEndingStyle(obj2.getString());
+ else
+ startStyle = annotLineEndingNone;
+ obj2.free();
+
+ if(obj1.arrayGet(1, &obj2)->isString())
+ endStyle = parseAnnotLineEndingStyle(obj2.getString());
+ else
+ endStyle = annotLineEndingNone;
+ obj2.free();
+
+ } else {
+ startStyle = endStyle = annotLineEndingNone;
+ }
+ obj1.free();
+
+ if (dict->lookup("IC", &obj1)->isArray()) {
+ interiorColor = new AnnotColor(obj1.getArray());
+ } else {
+ interiorColor = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("LL", &obj1)->isNum()) {
+ leaderLineLength = obj1.getNum();
+ } else {
+ leaderLineLength = 0;
+ }
+ obj1.free();
+
+ if (dict->lookup("LLE", &obj1)->isNum()) {
+ leaderLineExtension = obj1.getNum();
+
+ if (leaderLineExtension < 0)
+ leaderLineExtension = 0;
+ } else {
+ leaderLineExtension = 0;
+ }
+ obj1.free();
+
+ if (dict->lookup("Cap", &obj1)->isBool()) {
+ caption = obj1.getBool();
+ } else {
+ caption = gFalse;
+ }
+ obj1.free();
+
+ if (dict->lookup("IT", &obj1)->isName()) {
+ const char *intentName = obj1.getName();
+
+ if(!strcmp(intentName, "LineArrow")) {
+ intent = intentLineArrow;
+ } else if(!strcmp(intentName, "LineDimension")) {
+ intent = intentLineDimension;
+ } else {
+ intent = intentLineArrow;
+ }
+ } else {
+ intent = intentLineArrow;
+ }
+ obj1.free();
+
+ if (dict->lookup("LLO", &obj1)->isNum()) {
+ leaderLineOffset = obj1.getNum();
+
+ if (leaderLineOffset < 0)
+ leaderLineOffset = 0;
+ } else {
+ leaderLineOffset = 0;
+ }
+ obj1.free();
+
+ if (dict->lookup("CP", &obj1)->isName()) {
+ const char *captionName = obj1.getName();
+
+ if(!strcmp(captionName, "Inline")) {
+ captionPos = captionPosInline;
+ } else if(!strcmp(captionName, "Top")) {
+ captionPos = captionPosTop;
+ } else {
+ captionPos = captionPosInline;
+ }
+ } else {
+ captionPos = captionPosInline;
+ }
+ obj1.free();
+
+ if (dict->lookup("Measure", &obj1)->isDict()) {
+ measure = NULL;
+ } else {
+ measure = NULL;
+ }
+ obj1.free();
+
+ if ((dict->lookup("CO", &obj1)->isArray()) && (obj1.arrayGetLength() == 2)) {
+ Object obj2;
+
+ (obj1.arrayGet(0, &obj2)->isNum() ? captionTextHorizontal = obj2.getNum() :
+ captionTextHorizontal = 0);
+ obj2.free();
+ (obj1.arrayGet(1, &obj2)->isNum() ? captionTextVertical = obj2.getNum() :
+ captionTextVertical = 0);
+ obj2.free();
+ } else {
+ captionTextHorizontal = captionTextVertical = 0;
+ }
+ obj1.free();
+
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ delete border;
+ border = new AnnotBorderBS(obj1.getDict());
+ } else if (!border) {
+ border = new AnnotBorderBS();
+ }
+ obj1.free();
+}
+
+void AnnotLine::setContents(GooString *new_content) {
+ Annot::setContents(new_content);
+ if (caption)
+ invalidateAppearance();
+}
+
+void AnnotLine::setVertices(double x1, double y1, double x2, double y2) {
+ Object obj1, obj2;
+
+ delete coord1;
+ coord1 = new AnnotCoord(x1, y1);
+ delete coord2;
+ coord2 = new AnnotCoord(x2, y2);
+
+ obj1.initArray(xref);
+ obj1.arrayAdd( obj2.initReal(x1) );
+ obj1.arrayAdd( obj2.initReal(y1) );
+ obj1.arrayAdd( obj2.initReal(x2) );
+ obj1.arrayAdd( obj2.initReal(y2) );
+
+ update("L", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotLine::setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end) {
+ Object obj1, obj2;
+
+ startStyle = start;
+ endStyle = end;
+
+ obj1.initArray(xref);
+ obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( startStyle )) );
+ obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( endStyle )) );
+
+ update("LE", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotLine::setInteriorColor(AnnotColor *new_color) {
+ delete interiorColor;
+
+ if (new_color) {
+ Object obj1;
+ new_color->writeToObject(xref, &obj1);
+ update ("IC", &obj1);
+ interiorColor = new_color;
+ } else {
+ interiorColor = NULL;
+ }
+ invalidateAppearance();
+}
+
+void AnnotLine::setLeaderLineLength(double len) {
+ Object obj1;
+
+ leaderLineLength = len;
+ obj1.initReal(len);
+ update ("LL", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotLine::setLeaderLineExtension(double len) {
+ Object obj1;
+
+ leaderLineExtension = len;
+ obj1.initReal(len);
+ update ("LLE", &obj1);
+
+ // LL is required if LLE is present
+ obj1.initReal(leaderLineLength);
+ update ("LL", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotLine::setCaption(bool new_cap) {
+ Object obj1;
+
+ caption = new_cap;
+ obj1.initBool(new_cap);
+ update ("Cap", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotLine::setIntent(AnnotLineIntent new_intent) {
+ Object obj1;
+
+ intent = new_intent;
+ if (new_intent == intentLineArrow)
+ obj1.initName("LineArrow");
+ else // intentLineDimension
+ obj1.initName("LineDimension");
+ update ("IT", &obj1);
+}
+
+void AnnotLine::generateLineAppearance()
+{
+ double borderWidth, ca = opacity;
+
+ appearBBox = new AnnotAppearanceBBox(rect);
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+ if (color) {
+ setColor(color, gFalse);
+ }
+
+ setLineStyleForBorder(border);
+ borderWidth = border->getWidth();
+ appearBBox->setBorderWidth(std::max(1., borderWidth));
+
+ const double x1 = coord1->getX();
+ const double y1 = coord1->getY();
+ const double x2 = coord2->getX();
+ const double y2 = coord2->getY();
+
+ // Main segment length
+ const double main_len = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
+
+ // Main segment becomes positive x direction, coord1 becomes (0,0)
+ Matrix matr;
+ const double angle = atan2(y2 - y1, x2 - x1);
+ matr.m[0] = matr.m[3] = cos(angle);
+ matr.m[1] = sin(angle);
+ matr.m[2] = -matr.m[1];
+ matr.m[4] = x1-rect->x1;
+ matr.m[5] = y1-rect->y1;
+
+ double tx, ty, captionwidth = 0, captionheight = 0;
+ AnnotLineCaptionPos actualCaptionPos = captionPos;
+ const double fontsize = 9;
+ const double captionhmargin = 2; // Left and right margin (inline caption only)
+ const double captionmaxwidth = main_len - 2 * captionhmargin;
+
+ Object fontResDict;
+ GfxFont *font;
+
+ // Calculate caption width and height
+ if (caption) {
+ font = createAnnotDrawFont(xref, &fontResDict);
+ int lines = 0;
+ int i = 0;
+ while (i < contents->getLength()) {
+ GooString out;
+ double linewidth;
+ layoutText(contents, &out, &i, font, &linewidth, 0, NULL, gFalse);
+ linewidth *= fontsize;
+ if (linewidth > captionwidth) {
+ captionwidth = linewidth;
+ }
+ ++lines;
+ }
+ captionheight = lines * fontsize;
+ // If text is longer than available space, turn into captionPosTop
+ if (captionwidth > captionmaxwidth) {
+ actualCaptionPos = captionPosTop;
+ }
+ } else {
+ fontResDict.initNull();
+ font = NULL;
+ }
+
+ // Draw main segment
+ matr.transform (0, leaderLineLength, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+
+ if (captionwidth != 0 && actualCaptionPos == captionPosInline) { // Break in the middle
+ matr.transform ((main_len-captionwidth)/2 - captionhmargin, leaderLineLength, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
+
+ matr.transform ((main_len+captionwidth)/2 + captionhmargin, leaderLineLength, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ }
+
+ matr.transform (main_len, leaderLineLength, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+
+ // TODO: Line endings
+
+ // Draw caption text
+ if (caption) {
+ double tlx = (main_len - captionwidth) / 2, tly; // Top-left coords
+ if (actualCaptionPos == captionPosInline) {
+ tly = leaderLineLength + captionheight / 2;
+ } else {
+ tly = leaderLineLength + captionheight + 2*borderWidth;
+ }
+
+ tlx += captionTextHorizontal;
+ tly += captionTextVertical;
+
+ // Adjust bounding box
+ matr.transform (tlx, tly-captionheight, &tx, &ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (tlx+captionwidth, tly-captionheight, &tx, &ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (tlx+captionwidth, tly, &tx, &ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (tlx, tly, &tx, &ty);
+ appearBBox->extendTo (tx, ty);
+
+ // Setup text state (reusing transformed top-left coord)
+ appearBuf->appendf ("0 g BT /AnnotDrawFont {0:.2f} Tf\n", fontsize); // Font color: black
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} Tm\n",
+ matr.m[0], matr.m[1], matr.m[2], matr.m[3], tx, ty);
+ appearBuf->appendf ("0 {0:.2f} Td\n", -fontsize * font->getDescent());
+ // Draw text
+ int i = 0;
+ double xposPrev = 0;
+ while (i < contents->getLength()) {
+ GooString out;
+ double linewidth, xpos;
+ layoutText(contents, &out, &i, font, &linewidth, 0, NULL, gFalse);
+ linewidth *= fontsize;
+ xpos = (captionwidth - linewidth) / 2;
+ appearBuf->appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -fontsize);
+ writeString(&out, appearBuf);
+ appearBuf->append ("Tj\n");
+ xposPrev = xpos;
+ }
+ appearBuf->append ("ET\n");
+ font->decRefCnt();
+ }
+
+ // Draw leader lines
+ double ll_len = fabs(leaderLineLength) + leaderLineExtension;
+ double sign = leaderLineLength >= 0 ? 1 : -1;
+ if (ll_len != 0) {
+ matr.transform (0, 0, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (0, sign*ll_len, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+
+ matr.transform (main_len, 0, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (main_len, sign*ll_len, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+ }
+
+ appearBuf->append ("Q\n");
+
+ double bbox[4];
+ appearBBox->getBBoxRect(bbox);
+ if (ca == 1) {
+ createForm(bbox, gFalse, &fontResDict, &appearance);
+ } else {
+ Object aStream, resDict;
+
+ createForm(bbox, gTrue, &fontResDict, &aStream);
+ delete appearBuf;
+
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+}
+
+void AnnotLine::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull()) {
+ generateLineAppearance();
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ if (appearBBox) {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ appearBBox->getPageXMin(), appearBBox->getPageYMin(),
+ appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+ getRotation());
+ } else {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ }
+ obj.free();
+}
+
+// Before retrieving the res dict, regenerate the appearance stream if needed,
+// because AnnotLine::draw may need to store font info in the res dict
+Object *AnnotLine::getAppearanceResDict(Object *dest) {
+ if (appearance.isNull()) {
+ generateLineAppearance();
+ }
+ return Annot::getAppearanceResDict(dest);
+}
+
+//------------------------------------------------------------------------
+// AnnotTextMarkup
+//------------------------------------------------------------------------
+AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ switch (subType) {
+ case typeHighlight:
+ annotObj.dictSet ("Subtype", obj1.initName ("Highlight"));
+ break;
+ case typeUnderline:
+ annotObj.dictSet ("Subtype", obj1.initName ("Underline"));
+ break;
+ case typeSquiggly:
+ annotObj.dictSet ("Subtype", obj1.initName ("Squiggly"));
+ break;
+ case typeStrikeOut:
+ annotObj.dictSet ("Subtype", obj1.initName ("StrikeOut"));
+ break;
+ default:
+ assert (0 && "Invalid subtype for AnnotTextMarkup\n");
+ }
+
+ // Store dummy quadrilateral with null coordinates
+ Object obj2, obj3;
+ obj2.initArray (doc->getXRef());
+ for (int i = 0; i < 4*2; ++i) {
+ obj2.arrayAdd (obj3.initReal (0));
+ }
+ annotObj.dictSet ("QuadPoints", &obj2);
+
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ // the real type will be read in initialize()
+ type = typeHighlight;
+ initialize(docA, dict);
+}
+
+void AnnotTextMarkup::initialize(PDFDoc *docA, Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("Subtype", &obj1)->isName()) {
+ GooString typeName(obj1.getName());
+ if (!typeName.cmp("Highlight")) {
+ type = typeHighlight;
+ } else if (!typeName.cmp("Underline")) {
+ type = typeUnderline;
+ } else if (!typeName.cmp("Squiggly")) {
+ type = typeSquiggly;
+ } else if (!typeName.cmp("StrikeOut")) {
+ type = typeStrikeOut;
+ }
+ }
+ obj1.free();
+
+ if(dict->lookup("QuadPoints", &obj1)->isArray()) {
+ quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
+ } else {
+ error(errSyntaxError, -1, "Bad Annot Text Markup QuadPoints");
+ quadrilaterals = NULL;
+ ok = gFalse;
+ }
+ obj1.free();
+}
+
+AnnotTextMarkup::~AnnotTextMarkup() {
+ if(quadrilaterals) {
+ delete quadrilaterals;
+ }
+}
+
+void AnnotTextMarkup::setType(AnnotSubtype new_type) {
+ Object obj1;
+
+ switch (new_type) {
+ case typeHighlight:
+ obj1.initName("Highlight");
+ break;
+ case typeUnderline:
+ obj1.initName("Underline");
+ break;
+ case typeSquiggly:
+ obj1.initName("Squiggly");
+ break;
+ case typeStrikeOut:
+ obj1.initName("StrikeOut");
+ break;
+ default:
+ assert(!"Invalid subtype");
+ }
+
+ type = new_type;
+ update("Subtype", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotTextMarkup::setQuadrilaterals(AnnotQuadrilaterals *quadPoints) {
+ Object obj1, obj2;
+ obj1.initArray (xref);
+
+ for (int i = 0; i < quadPoints->getQuadrilateralsLength(); ++i) {
+ obj1.arrayAdd (obj2.initReal (quadPoints->getX1(i)));
+ obj1.arrayAdd (obj2.initReal (quadPoints->getY1(i)));
+ obj1.arrayAdd (obj2.initReal (quadPoints->getX2(i)));
+ obj1.arrayAdd (obj2.initReal (quadPoints->getY2(i)));
+ obj1.arrayAdd (obj2.initReal (quadPoints->getX3(i)));
+ obj1.arrayAdd (obj2.initReal (quadPoints->getY3(i)));
+ obj1.arrayAdd (obj2.initReal (quadPoints->getX4(i)));
+ obj1.arrayAdd (obj2.initReal (quadPoints->getY4(i)));
+ }
+
+ delete quadrilaterals;
+ quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
+
+ annotObj.dictSet ("QuadPoints", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+ double ca = 1;
+ int i;
+ Object obj1, obj2;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull() || type == typeHighlight) {
+ GBool blendMultiply = gTrue;
+ ca = opacity;
+
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+
+ /* Adjust BBox */
+ delete appearBBox;
+ appearBBox = new AnnotAppearanceBBox(rect);
+ for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
+ appearBBox->extendTo (quadrilaterals->getX1(i) - rect->x1, quadrilaterals->getY1(i) - rect->y1);
+ appearBBox->extendTo (quadrilaterals->getX2(i) - rect->x1, quadrilaterals->getY2(i) - rect->y1);
+ appearBBox->extendTo (quadrilaterals->getX3(i) - rect->x1, quadrilaterals->getY3(i) - rect->y1);
+ appearBBox->extendTo (quadrilaterals->getX4(i) - rect->x1, quadrilaterals->getY4(i) - rect->y1);
+ }
+
+ switch (type) {
+ case typeUnderline:
+ if (color) {
+ setColor(color, gFalse);
+ }
+ appearBuf->append ("[] 0 d 1 w\n");
+
+ for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
+ double x3, y3, x4, y4;
+
+ x3 = quadrilaterals->getX3(i);
+ y3 = quadrilaterals->getY3(i);
+ x4 = quadrilaterals->getX4(i);
+ y4 = quadrilaterals->getY4(i);
+
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", x3, y3);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l\n", x4, y4);
+ appearBuf->append ("S\n");
+ }
+ break;
+ case typeStrikeOut:
+ if (color) {
+ setColor(color, gFalse);
+ }
+ blendMultiply = gFalse;
+ appearBuf->append ("[] 0 d 1 w\n");
+
+ for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
+ double x1, y1, x2, y2;
+ double x3, y3, x4, y4;
+
+ x1 = quadrilaterals->getX1(i);
+ y1 = quadrilaterals->getY1(i);
+ x2 = quadrilaterals->getX2(i);
+ y2 = quadrilaterals->getY2(i);
+
+ x3 = quadrilaterals->getX3(i);
+ y3 = quadrilaterals->getY3(i);
+ x4 = quadrilaterals->getX4(i);
+ y4 = quadrilaterals->getY4(i);
+
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", (x1+x3)/2., (y1+y3)/2.);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l\n", (x2+x4)/2., (y2+y4)/2.);
+ appearBuf->append ("S\n");
+ }
+ break;
+ case typeSquiggly:
+ if (color) {
+ setColor(color, gFalse);
+ }
+ appearBuf->append ("[] 0 d 1 w\n");
+
+ for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
+ double x1, y1, x2, y3;
+ double h6;
+
+ x1 = quadrilaterals->getX1(i);
+ y1 = quadrilaterals->getY1(i);
+ x2 = quadrilaterals->getX2(i);
+ y3 = quadrilaterals->getY3(i);
+ h6 = (y1 - y3) / 6.0;
+
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", x1, y3+h6);
+ bool down = false;
+ do {
+ down = !down; // Zigzag line
+ x1 += 2;
+ appearBuf->appendf ("{0:.2f} {1:.2f} l\n", x1, y3 + (down ? 0 : h6));
+ } while (x1 < x2);
+ appearBuf->append ("S\n");
+ }
+ break;
+ default:
+ case typeHighlight:
+ appearance.free();
+
+ if (color)
+ setColor(color, gTrue);
+
+ double biggestBorder = 0;
+ for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) {
+ double x1, y1, x2, y2, x3, y3, x4, y4;
+ double h4;
+
+ x1 = quadrilaterals->getX1(i);
+ y1 = quadrilaterals->getY1(i);
+ x2 = quadrilaterals->getX2(i);
+ y2 = quadrilaterals->getY2(i);
+ x3 = quadrilaterals->getX3(i);
+ y3 = quadrilaterals->getY3(i);
+ x4 = quadrilaterals->getX4(i);
+ y4 = quadrilaterals->getY4(i);
+ h4 = fabs(y1 - y3) / 4.0;
+
+ if (h4 > biggestBorder) {
+ biggestBorder = h4;
+ }
+
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", x3, y3);
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ x3 - h4, y3 + h4, x1 - h4, y1 - h4, x1, y1);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l\n", x2, y2);
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ x2 + h4, y2 - h4, x4 + h4, y4 + h4, x4, y4);
+ appearBuf->append ("f\n");
+ }
+ appearBBox->setBorderWidth(biggestBorder);
+ break;
+ }
+ appearBuf->append ("Q\n");
+
+ Object aStream, resDict;
+ double bbox[4];
+ bbox[0] = appearBBox->getPageXMin();
+ bbox[1] = appearBBox->getPageYMin();
+ bbox[2] = appearBBox->getPageXMax();
+ bbox[3] = appearBBox->getPageYMax();
+ createForm(bbox, gTrue, NULL, &aStream);
+ delete appearBuf;
+
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", 1, blendMultiply ? "Multiply" : NULL, &resDict);
+ if (ca == 1) {
+ createForm(bbox, gFalse, &resDict, &appearance);
+ } else {
+ createForm(bbox, gTrue, &resDict, &aStream);
+ delete appearBuf;
+
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ if (appearBBox) {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ appearBBox->getPageXMin(), appearBBox->getPageYMin(),
+ appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+ getRotation());
+ } else {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ }
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotWidget
+//------------------------------------------------------------------------
+
+AnnotWidget::AnnotWidget(PDFDoc *docA, Dict *dict, Object *obj) :
+ Annot(docA, dict, obj) {
+ type = typeWidget;
+ field = NULL;
+ initialize(docA, dict);
+}
+
+AnnotWidget::AnnotWidget(PDFDoc *docA, Dict *dict, Object *obj, FormField *fieldA) :
+ Annot(docA, dict, obj) {
+ type = typeWidget;
+ field = fieldA;
+ initialize(docA, dict);
+}
+
+AnnotWidget::~AnnotWidget() {
+ if (appearCharacs)
+ delete appearCharacs;
+
+ if (action)
+ delete action;
+
+ additionalActions.free();
+
+ if (parent)
+ delete parent;
+}
+
+void AnnotWidget::initialize(PDFDoc *docA, Dict *dict) {
+ Object obj1;
+
+ form = doc->getCatalog()->getForm();
+
+ if(dict->lookup("H", &obj1)->isName()) {
+ const char *modeName = obj1.getName();
+
+ if(!strcmp(modeName, "N")) {
+ mode = highlightModeNone;
+ } else if(!strcmp(modeName, "O")) {
+ mode = highlightModeOutline;
+ } else if(!strcmp(modeName, "P") || !strcmp(modeName, "T")) {
+ mode = highlightModePush;
+ } else {
+ mode = highlightModeInvert;
+ }
+ } else {
+ mode = highlightModeInvert;
+ }
+ obj1.free();
+
+ if(dict->lookup("MK", &obj1)->isDict()) {
+ appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
+ } else {
+ appearCharacs = NULL;
+ }
+ obj1.free();
+
+ action = NULL;
+ if(dict->lookup("A", &obj1)->isDict()) {
+ action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
+ }
+ obj1.free();
+
+ dict->lookupNF("AA", &additionalActions);
+
+ if(dict->lookup("Parent", &obj1)->isDict()) {
+ parent = NULL;
+ } else {
+ parent = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ delete border;
+ border = new AnnotBorderBS(obj1.getDict());
+ }
+ obj1.free();
+
+ updatedAppearanceStream.num = updatedAppearanceStream.gen = -1;
+}
+
+LinkAction* AnnotWidget::getAdditionalAction(AdditionalActionsType type)
+{
+ return ::getAdditionalAction(type, &additionalActions, doc);
+}
+
+LinkAction* AnnotWidget::getFormAdditionalAction(FormAdditionalActionsType type)
+{
+ return ::getFormAdditionalAction(type, &additionalActions, doc);
+}
+
+// Grand unified handler for preparing text strings to be drawn into form
+// fields. Takes as input a text string (in PDFDocEncoding or UTF-16).
+// Converts some or all of this string to the appropriate encoding for the
+// specified font, and computes the width of the text. Can optionally stop
+// converting when a specified width has been reached, to perform line-breaking
+// for multi-line fields.
+//
+// Parameters:
+// text: input text string to convert
+// outBuf: buffer for writing re-encoded string
+// i: index at which to start converting; will be updated to point just after
+// last character processed
+// font: the font which will be used for display
+// width: computed width (unscaled by font size) will be stored here
+// widthLimit: if non-zero, stop converting to keep width under this value
+// (should be scaled down by font size)
+// charCount: count of number of characters will be stored here
+// noReencode: if set, do not try to translate the character encoding
+// (useful for Zapf Dingbats or other unusual encodings)
+// can only be used with simple fonts, not CID-keyed fonts
+//
+// TODO: Handle surrogate pairs in UTF-16.
+// Should be able to generate output for any CID-keyed font.
+// Doesn't handle vertical fonts--should it?
+void Annot::layoutText(GooString *text, GooString *outBuf, int *i,
+ GfxFont *font, double *width, double widthLimit,
+ int *charCount, GBool noReencode)
+{
+ CharCode c;
+ Unicode uChar, *uAux;
+ double w = 0.0;
+ int uLen, n;
+ double dx, dy, ox, oy;
+ GBool unicode = text->hasUnicodeMarker();
+ GBool spacePrev; // previous character was a space
+
+ // State for backtracking when more text has been processed than fits within
+ // widthLimit. We track for both input (text) and output (outBuf) the offset
+ // to the first character to discard.
+ //
+ // We keep track of several points:
+ // 1 - end of previous completed word which fits
+ // 2 - previous character which fit
+ int last_i1, last_i2, last_o1, last_o2;
+
+ if (unicode && text->getLength() % 2 != 0) {
+ error(errSyntaxError, -1, "AnnotWidget::layoutText, bad unicode string");
+ return;
+ }
+
+ // skip Unicode marker on string if needed
+ if (unicode && *i == 0)
+ *i = 2;
+
+ // Start decoding and copying characters, until either:
+ // we reach the end of the string
+ // we reach the maximum width
+ // we reach a newline character
+ // As we copy characters, keep track of the last full word to fit, so that we
+ // can backtrack if we exceed the maximum width.
+ last_i1 = last_i2 = *i;
+ last_o1 = last_o2 = 0;
+ spacePrev = gFalse;
+ outBuf->clear();
+
+ while (*i < text->getLength()) {
+ last_i2 = *i;
+ last_o2 = outBuf->getLength();
+
+ if (unicode) {
+ uChar = (unsigned char)(text->getChar(*i)) << 8;
+ uChar += (unsigned char)(text->getChar(*i + 1));
+ *i += 2;
+ } else {
+ if (noReencode)
+ uChar = text->getChar(*i) & 0xff;
+ else
+ uChar = pdfDocEncoding[text->getChar(*i) & 0xff];
+ *i += 1;
+ }
+
+ // Explicit line break?
+ if (uChar == '\r' || uChar == '\n') {
+ // Treat a <CR><LF> sequence as a single line break
+ if (uChar == '\r' && *i < text->getLength()) {
+ if (unicode && text->getChar(*i) == '\0'
+ && text->getChar(*i + 1) == '\n')
+ *i += 2;
+ else if (!unicode && text->getChar(*i) == '\n')
+ *i += 1;
+ }
+
+ break;
+ }
+
+ if (noReencode) {
+ outBuf->append(uChar);
+ } else {
+ CharCodeToUnicode *ccToUnicode = font->getToUnicode();
+ if (!ccToUnicode) {
+ // This assumes an identity CMap.
+ outBuf->append((uChar >> 8) & 0xff);
+ outBuf->append(uChar & 0xff);
+ } else if (ccToUnicode->mapToCharCode(&uChar, &c, 2)) {
+ ccToUnicode->decRefCnt();
+ if (font->isCIDFont()) {
+ // TODO: This assumes an identity CMap. It should be extended to
+ // handle the general case.
+ outBuf->append((c >> 8) & 0xff);
+ outBuf->append(c & 0xff);
+ } else {
+ // 8-bit font
+ outBuf->append(c);
+ }
+ } else {
+ ccToUnicode->decRefCnt();
+ error(errSyntaxError, -1, "AnnotWidget::layoutText, cannot convert U+{0:04uX}", uChar);
+ }
+ }
+
+ // If we see a space, then we have a linebreak opportunity.
+ if (uChar == ' ') {
+ last_i1 = *i;
+ if (!spacePrev)
+ last_o1 = last_o2;
+ spacePrev = gTrue;
+ } else {
+ spacePrev = gFalse;
+ }
+
+ // Compute width of character just output
+ if (outBuf->getLength() > last_o2) {
+ dx = 0.0;
+ font->getNextChar(outBuf->getCString() + last_o2,
+ outBuf->getLength() - last_o2,
+ &c, &uAux, &uLen, &dx, &dy, &ox, &oy);
+ w += dx;
+ }
+
+ // Current line over-full now?
+ if (widthLimit > 0.0 && w > widthLimit) {
+ if (last_o1 > 0) {
+ // Back up to the previous word which fit, if there was a previous
+ // word.
+ *i = last_i1;
+ outBuf->del(last_o1, outBuf->getLength() - last_o1);
+ } else if (last_o2 > 0) {
+ // Otherwise, back up to the previous character (in the only word on
+ // this line)
+ *i = last_i2;
+ outBuf->del(last_o2, outBuf->getLength() - last_o2);
+ } else {
+ // Otherwise, we were trying to fit the first character; include it
+ // anyway even if it overflows the space--no updates to make.
+ }
+ break;
+ }
+ }
+
+ // If splitting input into lines because we reached the width limit, then
+ // consume any remaining trailing spaces that would go on this line from the
+ // input. If in doing so we reach a newline, consume that also. This code
+ // won't run if we stopped at a newline above, since in that case w <=
+ // widthLimit still.
+ if (widthLimit > 0.0 && w > widthLimit) {
+ if (unicode) {
+ while (*i < text->getLength()
+ && text->getChar(*i) == '\0' && text->getChar(*i + 1) == ' ')
+ *i += 2;
+ if (*i < text->getLength()
+ && text->getChar(*i) == '\0' && text->getChar(*i + 1) == '\r')
+ *i += 2;
+ if (*i < text->getLength()
+ && text->getChar(*i) == '\0' && text->getChar(*i + 1) == '\n')
+ *i += 2;
+ } else {
+ while (*i < text->getLength() && text->getChar(*i) == ' ')
+ *i += 1;
+ if (*i < text->getLength() && text->getChar(*i) == '\r')
+ *i += 1;
+ if (*i < text->getLength() && text->getChar(*i) == '\n')
+ *i += 1;
+ }
+ }
+
+ // Compute the actual width and character count of the final string, based on
+ // breakpoint, if this information is requested by the caller.
+ if (width != NULL || charCount != NULL) {
+ char *s = outBuf->getCString();
+ int len = outBuf->getLength();
+
+ if (width != NULL)
+ *width = 0.0;
+ if (charCount != NULL)
+ *charCount = 0;
+
+ while (len > 0) {
+ dx = 0.0;
+ n = font->getNextChar(s, len, &c, &uAux, &uLen, &dx, &dy, &ox, &oy);
+
+ if (n == 0) {
+ break;
+ }
+
+ if (width != NULL)
+ *width += dx;
+ if (charCount != NULL)
+ *charCount += 1;
+
+ s += n;
+ len -= n;
+ }
+ }
+}
+
+// Copy the given string to appearBuf, adding parentheses around it and
+// escaping characters as appropriate.
+void Annot::writeString(GooString *str, GooString *appearBuf)
+{
+ char c;
+ int i;
+
+ appearBuf->append('(');
+
+ for (i = 0; i < str->getLength(); ++i) {
+ c = str->getChar(i);
+ if (c == '(' || c == ')' || c == '\\') {
+ appearBuf->append('\\');
+ appearBuf->append(c);
+ } else if (c < 0x20) {
+ appearBuf->appendf("\\{0:03o}", (unsigned char)c);
+ } else {
+ appearBuf->append(c);
+ }
+ }
+
+ appearBuf->append(')');
+}
+
+// Draw the variable text or caption for a field.
+void AnnotWidget::drawText(GooString *text, GooString *da, GfxResources *resources,
+ GBool multiline, int comb, int quadding,
+ GBool txField, GBool forceZapfDingbats,
+ GBool password) {
+ GooList *daToks;
+ GooString *tok, *convertedText;
+ GfxFont *font;
+ double dx, dy;
+ double fontSize, fontSize2, borderWidth, x, xPrev, y, w, wMax;
+ int tfPos, tmPos, i, j;
+ int rot;
+ GBool freeText = gFalse; // true if text should be freed before return
+ GBool freeFont = gFalse;
+
+ //~ if there is no MK entry, this should use the existing content stream,
+ //~ and only replace the marked content portion of it
+ //~ (this is only relevant for Tx fields)
+
+ // parse the default appearance string
+ tfPos = tmPos = -1;
+ if (da) {
+ daToks = new GooList();
+ i = 0;
+ while (i < da->getLength()) {
+ while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
+ ++i;
+ }
+ if (i < da->getLength()) {
+ for (j = i + 1;
+ j < da->getLength() && !Lexer::isSpace(da->getChar(j));
+ ++j) ;
+ daToks->append(new GooString(da, i, j - i));
+ i = j;
+ }
+ }
+ for (i = 2; i < daToks->getLength(); ++i) {
+ if (i >= 2 && !((GooString *)daToks->get(i))->cmp("Tf")) {
+ tfPos = i - 2;
+ } else if (i >= 6 && !((GooString *)daToks->get(i))->cmp("Tm")) {
+ tmPos = i - 6;
+ }
+ }
+ } else {
+ daToks = NULL;
+ }
+
+ // force ZapfDingbats
+ if (forceZapfDingbats) {
+ if (tfPos >= 0) {
+ tok = (GooString *)daToks->get(tfPos);
+ if (tok->cmp("/ZaDb")) {
+ tok->clear();
+ tok->append("/ZaDb");
+ }
+ }
+ }
+ // get the font and font size
+ font = NULL;
+ fontSize = 0;
+ if (tfPos >= 0) {
+ tok = (GooString *)daToks->get(tfPos);
+ if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
+ if (!resources || !(font = resources->lookupFont(tok->getCString() + 1))) {
+ if (forceZapfDingbats) {
+ // We are forcing ZaDb but the font does not exist
+ // so create a fake one
+ Ref r; // dummy Ref, it's not used at all in this codepath
+ r.num = -1;
+ r.gen = -1;
+ Dict *d = new Dict(xref);
+ font = new Gfx8BitFont(xref, "ZaDb", r, new GooString("ZapfDingbats"), fontType1, r, d);
+ delete d;
+ freeFont = gTrue;
+ addDingbatsResource = gTrue;
+ } else {
+ error(errSyntaxError, -1, "Unknown font in field's DA string");
+ }
+ }
+ } else {
+ error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string");
+ }
+ tok = (GooString *)daToks->get(tfPos + 1);
+ fontSize = gatof(tok->getCString());
+ } else {
+ error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string");
+ }
+ if (!font) {
+ if (daToks) {
+ deleteGooList(daToks, GooString);
+ }
+ return;
+ }
+
+ // get the border width
+ borderWidth = border ? border->getWidth() : 0;
+
+ // for a password field, replace all characters with asterisks
+ if (password) {
+ int len;
+ if (text->hasUnicodeMarker())
+ len = (text->getLength() - 2) / 2;
+ else
+ len = text->getLength();
+
+ text = new GooString;
+ for (i = 0; i < len; ++i)
+ text->append('*');
+ freeText = gTrue;
+ }
+
+ convertedText = new GooString;
+
+ // setup
+ if (txField) {
+ appearBuf->append("/Tx BMC\n");
+ }
+ appearBuf->append("q\n");
+ rot = appearCharacs ? appearCharacs->getRotation() : 0;
+ switch (rot) {
+ case 90:
+ appearBuf->appendf("0 1 -1 0 {0:.2f} 0 cm\n", rect->x2 - rect->x1);
+ dx = rect->y2 - rect->y1;
+ dy = rect->x2 - rect->x1;
+ break;
+ case 180:
+ appearBuf->appendf("-1 0 0 -1 {0:.2f} {1:.2f} cm\n",
+ rect->x2 - rect->x1, rect->y2 - rect->y1);
+ dx = rect->x2 - rect->y2;
+ dy = rect->y2 - rect->y1;
+ break;
+ case 270:
+ appearBuf->appendf("0 -1 1 0 0 {0:.2f} cm\n", rect->y2 - rect->y1);
+ dx = rect->y2 - rect->y1;
+ dy = rect->x2 - rect->x1;
+ break;
+ default: // assume rot == 0
+ dx = rect->x2 - rect->x1;
+ dy = rect->y2 - rect->y1;
+ break;
+ }
+ appearBuf->append("BT\n");
+ // multi-line text
+ if (multiline) {
+ // note: the comb flag is ignored in multiline mode
+
+ wMax = dx - 2 * borderWidth - 4;
+
+ // compute font autosize
+ if (fontSize == 0) {
+ for (fontSize = 20; fontSize > 1; --fontSize) {
+ y = dy - 3;
+ i = 0;
+ while (i < text->getLength()) {
+ layoutText(text, convertedText, &i, font, &w, wMax / fontSize, NULL,
+ forceZapfDingbats);
+ y -= fontSize;
+ }
+ // approximate the descender for the last line
+ if (y >= 0.33 * fontSize) {
+ break;
+ }
+ }
+ if (tfPos >= 0) {
+ tok = (GooString *)daToks->get(tfPos + 1);
+ tok->clear();
+ tok->appendf("{0:.2f}", fontSize);
+ }
+ }
+
+ // starting y coordinate
+ // (note: each line of text starts with a Td operator that moves
+ // down a line)
+ y = dy - 3;
+
+ // set the font matrix
+ if (tmPos >= 0) {
+ tok = (GooString *)daToks->get(tmPos + 4);
+ tok->clear();
+ tok->append('0');
+ tok = (GooString *)daToks->get(tmPos + 5);
+ tok->clear();
+ tok->appendf("{0:.2f}", y);
+ }
+
+ // write the DA string
+ if (daToks) {
+ for (i = 0; i < daToks->getLength(); ++i) {
+ appearBuf->append((GooString *)daToks->get(i))->append(' ');
+ }
+ }
+
+ // write the font matrix (if not part of the DA string)
+ if (tmPos < 0) {
+ appearBuf->appendf("1 0 0 1 0 {0:.2f} Tm\n", y);
+ }
+
+ // write a series of lines of text
+ i = 0;
+ xPrev = 0;
+ while (i < text->getLength()) {
+ layoutText(text, convertedText, &i, font, &w, wMax / fontSize, NULL,
+ forceZapfDingbats);
+ w *= fontSize;
+
+ // compute text start position
+ switch (quadding) {
+ case quaddingLeftJustified:
+ default:
+ x = borderWidth + 2;
+ break;
+ case quaddingCentered:
+ x = (dx - w) / 2;
+ break;
+ case quaddingRightJustified:
+ x = dx - borderWidth - 2 - w;
+ break;
+ }
+
+ // draw the line
+ appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize);
+ writeString(convertedText, appearBuf);
+ appearBuf->append(" Tj\n");
+
+ // next line
+ xPrev = x;
+ }
+
+ // single-line text
+ } else {
+ //~ replace newlines with spaces? - what does Acrobat do?
+
+ // comb formatting
+ if (comb > 0) {
+ int charCount;
+
+ // compute comb spacing
+ w = (dx - 2 * borderWidth) / comb;
+
+ // compute font autosize
+ if (fontSize == 0) {
+ fontSize = dy - 2 * borderWidth;
+ if (w < fontSize) {
+ fontSize = w;
+ }
+ fontSize = floor(fontSize);
+ if (tfPos >= 0) {
+ tok = (GooString *)daToks->get(tfPos + 1);
+ tok->clear();
+ tok->appendf("{0:.2f}", fontSize);
+ }
+ }
+
+ i = 0;
+ layoutText(text, convertedText, &i, font, NULL, 0.0, &charCount,
+ forceZapfDingbats);
+ if (charCount > comb)
+ charCount = comb;
+
+ // compute starting text cell
+ switch (quadding) {
+ case quaddingLeftJustified:
+ default:
+ x = borderWidth;
+ break;
+ case quaddingCentered:
+ x = borderWidth + (comb - charCount) / 2 * w;
+ break;
+ case quaddingRightJustified:
+ x = borderWidth + (comb - charCount) * w;
+ break;
+ }
+ y = 0.5 * dy - 0.4 * fontSize;
+
+ // set the font matrix
+ if (tmPos >= 0) {
+ tok = (GooString *)daToks->get(tmPos + 4);
+ tok->clear();
+ tok->appendf("{0:.2f}", x);
+ tok = (GooString *)daToks->get(tmPos + 5);
+ tok->clear();
+ tok->appendf("{0:.2f}", y);
+ }
+
+ // write the DA string
+ if (daToks) {
+ for (i = 0; i < daToks->getLength(); ++i) {
+ appearBuf->append((GooString *)daToks->get(i))->append(' ');
+ }
+ }
+
+ // write the font matrix (if not part of the DA string)
+ if (tmPos < 0) {
+ appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
+ }
+
+ // write the text string
+ char *s = convertedText->getCString();
+ int len = convertedText->getLength();
+ i = 0;
+ xPrev = w; // so that first character is placed properly
+ while (i < comb && len > 0) {
+ CharCode code;
+ Unicode *uAux;
+ int uLen, n;
+ double dx, dy, ox, oy;
+
+ dx = 0.0;
+ n = font->getNextChar(s, len, &code, &uAux, &uLen, &dx, &dy, &ox, &oy);
+ dx *= fontSize;
+
+ // center each character within its cell, by advancing the text
+ // position the appropriate amount relative to the start of the
+ // previous character
+ x = 0.5 * (w - dx);
+ appearBuf->appendf("{0:.2f} 0 Td\n", x - xPrev + w);
+
+ GooString *charBuf = new GooString(s, n);
+ writeString(charBuf, appearBuf);
+ appearBuf->append(" Tj\n");
+ delete charBuf;
+
+ i++;
+ s += n;
+ len -= n;
+ xPrev = x;
+ }
+
+ // regular (non-comb) formatting
+ } else {
+ i = 0;
+ layoutText(text, convertedText, &i, font, &w, 0.0, NULL,
+ forceZapfDingbats);
+
+ // compute font autosize
+ if (fontSize == 0) {
+ fontSize = dy - 2 * borderWidth;
+ fontSize2 = (dx - 4 - 2 * borderWidth) / w;
+ if (fontSize2 < fontSize) {
+ fontSize = fontSize2;
+ }
+ fontSize = floor(fontSize);
+ if (tfPos >= 0) {
+ tok = (GooString *)daToks->get(tfPos + 1);
+ tok->clear();
+ tok->appendf("{0:.2f}", fontSize);
+ }
+ }
+
+ // compute text start position
+ w *= fontSize;
+ switch (quadding) {
+ case quaddingLeftJustified:
+ default:
+ x = borderWidth + 2;
+ break;
+ case quaddingCentered:
+ x = (dx - w) / 2;
+ break;
+ case quaddingRightJustified:
+ x = dx - borderWidth - 2 - w;
+ break;
+ }
+ y = 0.5 * dy - 0.4 * fontSize;
+
+ // set the font matrix
+ if (tmPos >= 0) {
+ tok = (GooString *)daToks->get(tmPos + 4);
+ tok->clear();
+ tok->appendf("{0:.2f}", x);
+ tok = (GooString *)daToks->get(tmPos + 5);
+ tok->clear();
+ tok->appendf("{0:.2f}", y);
+ }
+
+ // write the DA string
+ if (daToks) {
+ for (i = 0; i < daToks->getLength(); ++i) {
+ appearBuf->append((GooString *)daToks->get(i))->append(' ');
+ }
+ }
+
+ // write the font matrix (if not part of the DA string)
+ if (tmPos < 0) {
+ appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
+ }
+
+ // write the text string
+ writeString(convertedText, appearBuf);
+ appearBuf->append(" Tj\n");
+ }
+ }
+ // cleanup
+ appearBuf->append("ET\n");
+ appearBuf->append("Q\n");
+ if (txField) {
+ appearBuf->append("EMC\n");
+ }
+ if (daToks) {
+ deleteGooList(daToks, GooString);
+ }
+ if (freeText) {
+ delete text;
+ }
+ delete convertedText;
+ if (freeFont) {
+ font->decRefCnt();
+ }
+}
+
+// Draw the variable text or caption for a field.
+void AnnotWidget::drawListBox(FormFieldChoice *fieldChoice,
+ GooString *da, GfxResources *resources, int quadding) {
+ GooList *daToks;
+ GooString *tok, *convertedText;
+ GfxFont *font;
+ double fontSize, fontSize2, borderWidth, x, y, w, wMax;
+ int tfPos, tmPos, i, j;
+
+ //~ if there is no MK entry, this should use the existing content stream,
+ //~ and only replace the marked content portion of it
+ //~ (this is only relevant for Tx fields)
+
+ // parse the default appearance string
+ tfPos = tmPos = -1;
+ if (da) {
+ daToks = new GooList();
+ i = 0;
+ while (i < da->getLength()) {
+ while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
+ ++i;
+ }
+ if (i < da->getLength()) {
+ for (j = i + 1;
+ j < da->getLength() && !Lexer::isSpace(da->getChar(j));
+ ++j) ;
+ daToks->append(new GooString(da, i, j - i));
+ i = j;
+ }
+ }
+ for (i = 2; i < daToks->getLength(); ++i) {
+ if (i >= 2 && !((GooString *)daToks->get(i))->cmp("Tf")) {
+ tfPos = i - 2;
+ } else if (i >= 6 && !((GooString *)daToks->get(i))->cmp("Tm")) {
+ tmPos = i - 6;
+ }
+ }
+ } else {
+ daToks = NULL;
+ }
+
+ // get the font and font size
+ font = NULL;
+ fontSize = 0;
+ if (tfPos >= 0) {
+ tok = (GooString *)daToks->get(tfPos);
+ if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
+ if (!resources || !(font = resources->lookupFont(tok->getCString() + 1))) {
+ error(errSyntaxError, -1, "Unknown font in field's DA string");
+ }
+ } else {
+ error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string");
+ }
+ tok = (GooString *)daToks->get(tfPos + 1);
+ fontSize = gatof(tok->getCString());
+ } else {
+ error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string");
+ }
+ if (!font) {
+ if (daToks) {
+ deleteGooList(daToks, GooString);
+ }
+ return;
+ }
+
+ convertedText = new GooString;
+
+ // get the border width
+ borderWidth = border ? border->getWidth() : 0;
+
+ // compute font autosize
+ if (fontSize == 0) {
+ wMax = 0;
+ for (i = 0; i < fieldChoice->getNumChoices(); ++i) {
+ j = 0;
+ if (fieldChoice->getChoice(i) == NULL) {
+ error(errSyntaxError, -1, "Invalid annotation listbox");
+ if (daToks) {
+ deleteGooList(daToks, GooString);
+ }
+ delete convertedText;
+ return;
+ }
+ layoutText(fieldChoice->getChoice(i), convertedText, &j, font, &w, 0.0, NULL, gFalse);
+ if (w > wMax) {
+ wMax = w;
+ }
+ }
+ fontSize = rect->y2 - rect->y1 - 2 * borderWidth;
+ fontSize2 = (rect->x2 - rect->x1 - 4 - 2 * borderWidth) / wMax;
+ if (fontSize2 < fontSize) {
+ fontSize = fontSize2;
+ }
+ fontSize = floor(fontSize);
+ if (tfPos >= 0) {
+ tok = (GooString *)daToks->get(tfPos + 1);
+ tok->clear();
+ tok->appendf("{0:.2f}", fontSize);
+ }
+ }
+ // draw the text
+ y = rect->y2 - rect->y1 - 1.1 * fontSize;
+ for (i = fieldChoice->getTopIndex(); i < fieldChoice->getNumChoices(); ++i) {
+ // setup
+ appearBuf->append("q\n");
+
+ // draw the background if selected
+ if (fieldChoice->isSelected(i)) {
+ appearBuf->append("0 g f\n");
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n",
+ borderWidth,
+ y - 0.2 * fontSize,
+ rect->x2 - rect->x1 - 2 * borderWidth,
+ 1.1 * fontSize);
+ }
+
+ // setup
+ appearBuf->append("BT\n");
+
+ // compute text width and start position
+ j = 0;
+ layoutText(fieldChoice->getChoice(i), convertedText, &j, font, &w, 0.0, NULL, gFalse);
+ w *= fontSize;
+ switch (quadding) {
+ case quaddingLeftJustified:
+ default:
+ x = borderWidth + 2;
+ break;
+ case quaddingCentered:
+ x = (rect->x2 - rect->x1 - w) / 2;
+ break;
+ case quaddingRightJustified:
+ x = rect->x2 - rect->x1 - borderWidth - 2 - w;
+ break;
+ }
+
+ // set the font matrix
+ if (tmPos >= 0) {
+ tok = (GooString *)daToks->get(tmPos + 4);
+ tok->clear();
+ tok->appendf("{0:.2f}", x);
+ tok = (GooString *)daToks->get(tmPos + 5);
+ tok->clear();
+ tok->appendf("{0:.2f}", y);
+ }
+
+ // write the DA string
+ if (daToks) {
+ for (j = 0; j < daToks->getLength(); ++j) {
+ appearBuf->append((GooString *)daToks->get(j))->append(' ');
+ }
+ }
+
+ // write the font matrix (if not part of the DA string)
+ if (tmPos < 0) {
+ appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
+ }
+
+ // change the text color if selected
+ if (fieldChoice->isSelected(i)) {
+ appearBuf->append("1 g\n");
+ }
+
+ // write the text string
+ writeString(convertedText, appearBuf);
+ appearBuf->append(" Tj\n");
+
+ // cleanup
+ appearBuf->append("ET\n");
+ appearBuf->append("Q\n");
+
+ // next line
+ y -= 1.1 * fontSize;
+ }
+
+ if (daToks) {
+ deleteGooList(daToks, GooString);
+ }
+
+ delete convertedText;
+}
+
+void AnnotWidget::drawBorder() {
+ int dashLength;
+ double *dash;
+ AnnotColor adjustedColor;
+ double w = border->getWidth();
+
+ AnnotColor *aColor = appearCharacs->getBorderColor();
+ if (!aColor)
+ aColor = appearCharacs->getBackColor();
+ if (!aColor)
+ return;
+
+ double dx = rect->x2 - rect->x1;
+ double dy = rect->y2 - rect->y1;
+
+ // radio buttons with no caption have a round border
+ GBool hasCaption = appearCharacs->getNormalCaption() != NULL;
+ if (field->getType() == formButton &&
+ static_cast<FormFieldButton*>(field)->getButtonType() == formButtonRadio && !hasCaption) {
+ double r = 0.5 * (dx < dy ? dx : dy);
+ switch (border->getStyle()) {
+ case AnnotBorder::borderDashed:
+ appearBuf->append("[");
+ dashLength = border->getDashLength();
+ dash = border->getDash();
+ for (int i = 0; i < dashLength; ++i) {
+ appearBuf->appendf(" {0:.2f}", dash[i]);
+ }
+ appearBuf->append("] 0 d\n");
+ // fall through to the solid case
+ case AnnotBorder::borderSolid:
+ case AnnotBorder::borderUnderlined:
+ appearBuf->appendf("{0:.2f} w\n", w);
+ setColor(aColor, gFalse);
+ drawCircle(0.5 * dx, 0.5 * dy, r - 0.5 * w, gFalse);
+ break;
+ case AnnotBorder::borderBeveled:
+ case AnnotBorder::borderInset:
+ appearBuf->appendf("{0:.2f} w\n", 0.5 * w);
+ setColor(aColor, gFalse);
+ drawCircle(0.5 * dx, 0.5 * dy, r - 0.25 * w, gFalse);
+ adjustedColor = AnnotColor(*aColor);
+ adjustedColor.adjustColor(border->getStyle() == AnnotBorder::borderBeveled ? 1 : -1);
+ setColor(&adjustedColor, gFalse);
+ drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w);
+ adjustedColor = AnnotColor(*aColor);
+ adjustedColor.adjustColor(border->getStyle() == AnnotBorder::borderBeveled ? -1 : 1);
+ setColor(&adjustedColor, gFalse);
+ drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w);
+ break;
+ }
+ } else {
+ switch (border->getStyle()) {
+ case AnnotBorder::borderDashed:
+ appearBuf->append("[");
+ dashLength = border->getDashLength();
+ dash = border->getDash();
+ for (int i = 0; i < dashLength; ++i) {
+ appearBuf->appendf(" {0:.2f}", dash[i]);
+ }
+ appearBuf->append("] 0 d\n");
+ // fall through to the solid case
+ case AnnotBorder::borderSolid:
+ appearBuf->appendf("{0:.2f} w\n", w);
+ setColor(aColor, gFalse);
+ appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re s\n",
+ 0.5 * w, dx - w, dy - w);
+ break;
+ case AnnotBorder::borderBeveled:
+ case AnnotBorder::borderInset:
+ adjustedColor = AnnotColor(*aColor);
+ adjustedColor.adjustColor(border->getStyle() == AnnotBorder::borderBeveled ? 1 : -1);
+ setColor(&adjustedColor, gTrue);
+ appearBuf->append("0 0 m\n");
+ appearBuf->appendf("0 {0:.2f} l\n", dy);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w);
+ appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
+ appearBuf->append("f\n");
+ adjustedColor = AnnotColor(*aColor);
+ adjustedColor.adjustColor(border->getStyle() == AnnotBorder::borderBeveled ? -1 : 1);
+ setColor(&adjustedColor, gTrue);
+ appearBuf->append("0 0 m\n");
+ appearBuf->appendf("{0:.2f} 0 l\n", dx);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w);
+ appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
+ appearBuf->append("f\n");
+ break;
+ case AnnotBorder::borderUnderlined:
+ appearBuf->appendf("{0:.2f} w\n", w);
+ setColor(aColor, gFalse);
+ appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx);
+ break;
+ }
+
+ // clip to the inside of the border
+ appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n",
+ w, dx - 2 * w, dy - 2 * w);
+ }
+}
+
+void AnnotWidget::drawFormFieldButton(GfxResources *resources, GooString *da) {
+ GooString *caption = NULL;
+ if (appearCharacs)
+ caption = appearCharacs->getNormalCaption();
+
+ switch (static_cast<FormFieldButton *>(field)->getButtonType()) {
+ case formButtonRadio: {
+ //~ Acrobat doesn't draw a caption if there is no AP dict (?)
+ if (appearState && appearState->cmp("Off") != 0 &&
+ static_cast<FormFieldButton *>(field)->getState(appearState->getCString())) {
+ if (caption) {
+ drawText(caption, da, resources, gFalse, 0, fieldQuadCenter,
+ gFalse, gTrue);
+ } else if (appearCharacs) {
+ AnnotColor *aColor = appearCharacs->getBorderColor();
+ if (aColor) {
+ double dx = rect->x2 - rect->x1;
+ double dy = rect->y2 - rect->y1;
+ setColor(aColor, gTrue);
+ drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy), gTrue);
+ }
+ }
+ }
+ }
+ break;
+ case formButtonPush:
+ if (caption)
+ drawText(caption, da, resources, gFalse, 0, fieldQuadCenter, gFalse, gFalse);
+ break;
+ case formButtonCheck:
+ if (appearState && appearState->cmp("Off") != 0) {
+ if (!caption) {
+ GooString checkMark("3");
+ drawText(&checkMark, da, resources, gFalse, 0, fieldQuadCenter, gFalse, gTrue);
+ } else {
+ drawText(caption, da, resources, gFalse, 0, fieldQuadCenter, gFalse, gTrue);
+ }
+ }
+ break;
+ }
+}
+
+void AnnotWidget::drawFormFieldText(GfxResources *resources, GooString *da) {
+ VariableTextQuadding quadding;
+ GooString *contents;
+ FormFieldText *fieldText = static_cast<FormFieldText *>(field);
+
+ contents = fieldText->getContent();
+ if (contents) {
+ quadding = field->hasTextQuadding() ? field->getTextQuadding() : form->getTextQuadding();
+
+ int comb = 0;
+ if (fieldText->isComb())
+ comb = fieldText->getMaxLen();
+
+ drawText(contents, da, resources,
+ fieldText->isMultiline(), comb, quadding, gTrue, gFalse, fieldText->isPassword());
+ }
+}
+
+void AnnotWidget::drawFormFieldChoice(GfxResources *resources, GooString *da) {
+ GooString *selected;
+ VariableTextQuadding quadding;
+ FormFieldChoice *fieldChoice = static_cast<FormFieldChoice *>(field);
+
+ quadding = field->hasTextQuadding() ? field->getTextQuadding() : form->getTextQuadding();
+
+ if (fieldChoice->isCombo()) {
+ selected = fieldChoice->getSelectedChoice();
+ if (selected) {
+ drawText(selected, da, resources, gFalse, 0, quadding, gTrue, gFalse);
+ //~ Acrobat draws a popup icon on the right side
+ }
+ // list box
+ } else {
+ drawListBox(fieldChoice, da, resources, quadding);
+ }
+}
+
+void AnnotWidget::generateFieldAppearance() {
+ Object appearDict, obj1, obj2;
+ GfxResources *resources;
+ MemStream *appearStream;
+ GooString *da;
+
+ appearBuf = new GooString ();
+
+ // draw the background
+ if (appearCharacs) {
+ AnnotColor *aColor = appearCharacs->getBackColor();
+ if (aColor) {
+ setColor(aColor, gTrue);
+ appearBuf->appendf("0 0 {0:.2f} {1:.2f} re f\n",
+ rect->x2 - rect->x1, rect->y2 - rect->y1);
+ }
+ }
+
+ // draw the border
+ if (appearCharacs && border && border->getWidth() > 0)
+ drawBorder();
+
+ da = field->getDefaultAppearance();
+ if (!da)
+ da = form->getDefaultAppearance();
+
+ resources = form->getDefaultResources();
+
+ // draw the field contents
+ switch (field->getType()) {
+ case formButton:
+ drawFormFieldButton(resources, da);
+ break;
+ case formText:
+ drawFormFieldText(resources, da);
+ break;
+ case formChoice:
+ drawFormFieldChoice(resources, da);
+ break;
+ case formSignature:
+ //~unimp
+ break;
+ case formUndef:
+ default:
+ error(errSyntaxError, -1, "Unknown field type");
+ }
+
+ // build the appearance stream dictionary
+ appearDict.initDict(xref);
+ appearDict.dictAdd(copyString("Length"),
+ obj1.initInt(appearBuf->getLength()));
+ appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
+ obj1.initArray(xref);
+ obj1.arrayAdd(obj2.initReal(0));
+ obj1.arrayAdd(obj2.initReal(0));
+ obj1.arrayAdd(obj2.initReal(rect->x2 - rect->x1));
+ obj1.arrayAdd(obj2.initReal(rect->y2 - rect->y1));
+ appearDict.dictAdd(copyString("BBox"), &obj1);
+
+ // set the resource dictionary
+ Object *resDict = form->getDefaultResourcesObj();
+ if (resDict->isDict()) {
+ appearDict.dictAdd(copyString("Resources"), resDict->copy(&obj1));
+ }
+
+ // build the appearance stream
+ appearStream = new MemStream(copyString(appearBuf->getCString()), 0,
+ appearBuf->getLength(), &appearDict);
+ appearance.free();
+ appearance.initStream(appearStream);
+ delete appearBuf;
+
+ appearStream->setNeedFree(gTrue);
+}
+
+void AnnotWidget::updateAppearanceStream()
+{
+ // If this the first time updateAppearanceStream() is called on this widget,
+ // destroy the AP dictionary because we are going to create a new one.
+ if (updatedAppearanceStream.num == -1) {
+ invalidateAppearance(); // Delete AP dictionary and all referenced streams
+ }
+
+ // There's no need to create a new appearance stream if NeedAppearances is
+ // set, because it will be ignored next time anyway.
+ if (form && form->getNeedAppearances())
+ return;
+
+ // Create the new appearance
+ generateFieldAppearance();
+
+ // Fetch the appearance stream we've just created
+ Object obj1;
+ appearance.fetch(xref, &obj1);
+
+ // If this the first time updateAppearanceStream() is called on this widget,
+ // create a new AP dictionary containing the new appearance stream.
+ // Otherwise, just update the stream we had created previously.
+ if (updatedAppearanceStream.num == -1) {
+ // Write the appearance stream
+ updatedAppearanceStream = xref->addIndirectObject(&obj1);
+ obj1.free();
+
+ // Write the AP dictionary
+ Object obj2;
+ obj1.initDict(xref);
+ obj1.dictAdd(copyString("N"), obj2.initRef(updatedAppearanceStream.num, updatedAppearanceStream.gen));
+ update("AP", &obj1);
+
+ // Update our internal pointers to the appearance dictionary
+ appearStreams = new AnnotAppearance(doc, &obj1);
+ } else {
+ // Replace the existing appearance stream
+ xref->setModifiedObject(&obj1, updatedAppearanceStream);
+ obj1.free();
+ }
+}
+
+void AnnotWidget::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ addDingbatsResource = gFalse;
+
+ // Only construct the appearance stream when
+ // - annot doesn't have an AP or
+ // - NeedAppearances is true
+ if (field) {
+ if (appearance.isNull() || (form && form->getNeedAppearances()))
+ generateFieldAppearance();
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ if (addDingbatsResource) {
+ // We are forcing ZaDb but the font does not exist
+ // so create a fake one
+ Object baseFontObj, subtypeObj;
+ baseFontObj.initName("ZapfDingbats");
+ subtypeObj.initName("Type1");
+
+ Object fontDictObj;
+ Dict *fontDict = new Dict(gfx->getXRef());
+ fontDict->decRef();
+ fontDict->add(copyString("BaseFont"), &baseFontObj);
+ fontDict->add(copyString("Subtype"), &subtypeObj);
+ fontDictObj.initDict(fontDict);
+
+ Object fontsDictObj;
+ Dict *fontsDict = new Dict(gfx->getXRef());
+ fontsDict->decRef();
+ fontsDict->add(copyString("ZaDb"), &fontDictObj);
+ fontsDictObj.initDict(fontsDict);
+
+ Dict *dict = new Dict(gfx->getXRef());
+ dict->add(copyString("Font"), &fontsDictObj);
+ gfx->pushResources(dict);
+ delete dict;
+ }
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ if (addDingbatsResource) {
+ gfx->popResources();
+ }
+ obj.free();
+}
+
+
+//------------------------------------------------------------------------
+// AnnotMovie
+//------------------------------------------------------------------------
+AnnotMovie::AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA) :
+ Annot(docA, rect) {
+ Object obj1;
+
+ type = typeMovie;
+ annotObj.dictSet ("Subtype", obj1.initName ("Movie"));
+
+ movie = movieA->copy();
+ // TODO: create movie dict from movieA
+
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotMovie::AnnotMovie(PDFDoc *docA, Dict *dict, Object *obj) :
+ Annot(docA, dict, obj) {
+ type = typeMovie;
+ initialize(docA, dict);
+}
+
+AnnotMovie::~AnnotMovie() {
+ if (title)
+ delete title;
+ delete movie;
+}
+
+void AnnotMovie::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("T", &obj1)->isString()) {
+ title = obj1.getString()->copy();
+ } else {
+ title = NULL;
+ }
+ obj1.free();
+
+ Object movieDict;
+ if (dict->lookup("Movie", &movieDict)->isDict()) {
+ Object obj2;
+ dict->lookup("A", &obj2);
+ if (obj2.isDict())
+ movie = new Movie (&movieDict, &obj2);
+ else
+ movie = new Movie (&movieDict);
+ if (!movie->isOk()) {
+ delete movie;
+ movie = NULL;
+ ok = gFalse;
+ }
+ obj2.free();
+ } else {
+ error(errSyntaxError, -1, "Bad Annot Movie");
+ movie = NULL;
+ ok = gFalse;
+ }
+ movieDict.free();
+}
+
+void AnnotMovie::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull() && movie->getShowPoster()) {
+ int width, height;
+ Object poster;
+ movie->getPoster(&poster);
+ movie->getAspect(&width, &height);
+
+ if (width != -1 && height != -1 && !poster.isNone()) {
+ MemStream *mStream;
+
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+ appearBuf->appendf ("{0:d} 0 0 {1:d} 0 0 cm\n", width, height);
+ appearBuf->append ("/MImg Do\n");
+ appearBuf->append ("Q\n");
+
+ Object imgDict;
+ imgDict.initDict(gfx->getXRef());
+ imgDict.dictSet ("MImg", &poster);
+
+ Object resDict;
+ resDict.initDict(gfx->getXRef());
+ resDict.dictSet ("XObject", &imgDict);
+
+ Object formDict, obj1, obj2;
+ formDict.initDict(gfx->getXRef());
+ formDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
+ formDict.dictSet("Subtype", obj1.initName("Form"));
+ formDict.dictSet("Name", obj1.initName("FRM"));
+ obj1.initArray(gfx->getXRef());
+ obj1.arrayAdd(obj2.initInt(0));
+ obj1.arrayAdd(obj2.initInt(0));
+ obj1.arrayAdd(obj2.initInt(width));
+ obj1.arrayAdd(obj2.initInt(height));
+ formDict.dictSet("BBox", &obj1);
+ obj1.initArray(gfx->getXRef());
+ obj1.arrayAdd(obj2.initInt(1));
+ obj1.arrayAdd(obj2.initInt(0));
+ obj1.arrayAdd(obj2.initInt(0));
+ obj1.arrayAdd(obj2.initInt(1));
+ obj1.arrayAdd(obj2.initInt(-width / 2));
+ obj1.arrayAdd(obj2.initInt(-height / 2));
+ formDict.dictSet("Matrix", &obj1);
+ formDict.dictSet("Resources", &resDict);
+
+ Object aStream;
+ mStream = new MemStream(copyString(appearBuf->getCString()), 0,
+ appearBuf->getLength(), &formDict);
+ mStream->setNeedFree(gTrue);
+ aStream.initStream(mStream);
+ delete appearBuf;
+
+ Object objDict;
+ objDict.initDict(gfx->getXRef());
+ objDict.dictSet ("FRM", &aStream);
+
+ resDict.initDict(gfx->getXRef());
+ resDict.dictSet ("XObject", &objDict);
+
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+ appearBuf->appendf ("0 0 {0:d} {1:d} re W n\n", width, height);
+ appearBuf->append ("q\n");
+ appearBuf->appendf ("0 0 {0:d} {1:d} re W n\n", width, height);
+ appearBuf->appendf ("1 0 0 1 {0:d} {1:d} cm\n", width / 2, height / 2);
+ appearBuf->append ("/FRM Do\n");
+ appearBuf->append ("Q\n");
+ appearBuf->append ("Q\n");
+
+ double bbox[4];
+ bbox[0] = bbox[1] = 0;
+ bbox[2] = width;
+ bbox[3] = height;
+ createForm(bbox, gFalse, &resDict, &appearance);
+ delete appearBuf;
+ }
+ poster.free();
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotScreen
+//------------------------------------------------------------------------
+AnnotScreen::AnnotScreen(PDFDoc *docA, PDFRectangle *rect) :
+ Annot(docA, rect) {
+ Object obj1;
+
+ type = typeScreen;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("Screen"));
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotScreen::AnnotScreen(PDFDoc *docA, Dict *dict, Object *obj) :
+ Annot(docA, dict, obj) {
+ type = typeScreen;
+ initialize(docA, dict);
+}
+
+AnnotScreen::~AnnotScreen() {
+ if (title)
+ delete title;
+ if (appearCharacs)
+ delete appearCharacs;
+ if (action)
+ delete action;
+
+ additionalActions.free();
+}
+
+void AnnotScreen::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ title = NULL;
+ if (dict->lookup("T", &obj1)->isString()) {
+ title = obj1.getString()->copy();
+ }
+ obj1.free();
+
+ action = NULL;
+ if (dict->lookup("A", &obj1)->isDict()) {
+ action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
+ if (action->getKind() == actionRendition && page == 0) {
+ error (errSyntaxError, -1, "Invalid Rendition action: associated screen annotation without P");
+ delete action;
+ action = NULL;
+ ok = gFalse;
+ }
+ }
+ obj1.free();
+
+ dict->lookupNF("AA", &additionalActions);
+
+ appearCharacs = NULL;
+ if(dict->lookup("MK", &obj1)->isDict()) {
+ appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
+ }
+ obj1.free();
+}
+
+LinkAction* AnnotScreen::getAdditionalAction(AdditionalActionsType type)
+{
+ if (type == actionFocusIn || type == actionFocusOut) // not defined for screen annotation
+ return NULL;
+
+ return ::getAdditionalAction(type, &additionalActions, doc);
+}
+
+//------------------------------------------------------------------------
+// AnnotStamp
+//------------------------------------------------------------------------
+AnnotStamp::AnnotStamp(PDFDoc *docA, PDFRectangle *rect) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ type = typeStamp;
+ annotObj.dictSet ("Subtype", obj1.initName ("Stamp"));
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotStamp::AnnotStamp(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ type = typeStamp;
+ initialize(docA, dict);
+}
+
+AnnotStamp::~AnnotStamp() {
+ delete icon;
+}
+
+void AnnotStamp::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("Name", &obj1)->isName()) {
+ icon = new GooString(obj1.getName());
+ } else {
+ icon = new GooString("Draft");
+ }
+ obj1.free();
+
+}
+
+void AnnotStamp::setIcon(GooString *new_icon) {
+ delete icon;
+
+ if (new_icon) {
+ icon = new GooString (new_icon);
+ } else {
+ icon = new GooString();
+ }
+
+ Object obj1;
+ obj1.initName (icon->getCString());
+ update("Name", &obj1);
+ invalidateAppearance();
+}
+
+//------------------------------------------------------------------------
+// AnnotGeometry
+//------------------------------------------------------------------------
+AnnotGeometry::AnnotGeometry(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ switch (subType) {
+ case typeSquare:
+ annotObj.dictSet ("Subtype", obj1.initName ("Square"));
+ break;
+ case typeCircle:
+ annotObj.dictSet ("Subtype", obj1.initName ("Circle"));
+ break;
+ default:
+ assert (0 && "Invalid subtype for AnnotGeometry\n");
+ }
+
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotGeometry::AnnotGeometry(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ // the real type will be read in initialize()
+ type = typeSquare;
+ initialize(docA, dict);
+}
+
+AnnotGeometry::~AnnotGeometry() {
+ delete interiorColor;
+ delete borderEffect;
+ delete geometryRect;
+}
+
+void AnnotGeometry::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("Subtype", &obj1)->isName()) {
+ GooString typeName(obj1.getName());
+ if (!typeName.cmp("Square")) {
+ type = typeSquare;
+ } else if (!typeName.cmp("Circle")) {
+ type = typeCircle;
+ }
+ }
+ obj1.free();
+
+ if (dict->lookup("IC", &obj1)->isArray()) {
+ interiorColor = new AnnotColor(obj1.getArray());
+ } else {
+ interiorColor = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ delete border;
+ border = new AnnotBorderBS(obj1.getDict());
+ } else if (!border) {
+ border = new AnnotBorderBS();
+ }
+ obj1.free();
+
+ if (dict->lookup("BE", &obj1)->isDict()) {
+ borderEffect = new AnnotBorderEffect(obj1.getDict());
+ } else {
+ borderEffect = NULL;
+ }
+ obj1.free();
+
+ geometryRect = NULL;
+ if (dict->lookup("RD", &obj1)->isArray()) {
+ geometryRect = parseDiffRectangle(obj1.getArray(), rect);
+ }
+ obj1.free();
+
+}
+
+void AnnotGeometry::setType(AnnotSubtype new_type) {
+ Object obj1;
+
+ switch (new_type) {
+ case typeSquare:
+ obj1.initName("Square");
+ break;
+ case typeCircle:
+ obj1.initName("Circle");
+ break;
+ default:
+ assert(!"Invalid subtype");
+ }
+
+ type = new_type;
+ update("Subtype", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotGeometry::setInteriorColor(AnnotColor *new_color) {
+ delete interiorColor;
+
+ if (new_color) {
+ Object obj1;
+ new_color->writeToObject(xref, &obj1);
+ update ("IC", &obj1);
+ interiorColor = new_color;
+ } else {
+ interiorColor = NULL;
+ }
+ invalidateAppearance();
+}
+
+void AnnotGeometry::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+ double ca = 1;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull()) {
+ ca = opacity;
+
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+ if (color)
+ setColor(color, gFalse);
+
+ double borderWidth = border->getWidth();
+ setLineStyleForBorder(border);
+
+ if (interiorColor)
+ setColor(interiorColor, gTrue);
+
+ if (type == typeSquare) {
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re\n",
+ borderWidth / 2.0, borderWidth / 2.0,
+ (rect->x2 - rect->x1) - borderWidth,
+ (rect->y2 - rect->y1) - borderWidth);
+ } else {
+ double width, height;
+ double b;
+ double x1, y1, x2, y2, x3, y3;
+
+ width = rect->x2 - rect->x1;
+ height = rect->y2 - rect->y1;
+ b = borderWidth / 2.0;
+
+ x1 = b;
+ y1 = height / 2.0;
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", x1, y1);
+
+ y1 += height / 4.0;
+ x2 = width / 4.0;
+ y2 = height - b;
+ x3 = width / 2.0;
+ y3 = y2;
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ x1, y1, x2, y2, x3, y3);
+ x2 = width - b;
+ y2 = y1;
+ x1 = x3 + (width / 4.0);
+ y1 = y3;
+ x3 = x2;
+ y3 = height / 2.0;
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ x1, y1, x2, y2, x3, y3);
+
+ x2 = x1;
+ y2 = b;
+ x1 = x3;
+ y1 = height / 4.0;
+ x3 = width / 2.0;
+ y3 = b;
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ x1, y1, x2, y2, x3, y3);
+
+ x2 = b;
+ y2 = y1;
+ x1 = width / 4.0;
+ y1 = b;
+ x3 = b;
+ y3 = height / 2.0;
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ x1, y1, x2, y2, x3, y3);
+ }
+
+ if (interiorColor && interiorColor->getSpace() != AnnotColor::colorTransparent)
+ appearBuf->append ("b\n");
+ else
+ appearBuf->append ("S\n");
+
+ appearBuf->append ("Q\n");
+
+ double bbox[4];
+ bbox[0] = bbox[1] = 0;
+ bbox[2] = rect->x2 - rect->x1;
+ bbox[3] = rect->y2 - rect->y1;
+ if (ca == 1) {
+ createForm(bbox, gFalse, NULL, &appearance);
+ } else {
+ Object aStream;
+
+ createForm(bbox, gTrue, NULL, &aStream);
+ delete appearBuf;
+
+ Object resDict;
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotPolygon
+//------------------------------------------------------------------------
+AnnotPolygon::AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ switch (subType) {
+ case typePolygon:
+ annotObj.dictSet ("Subtype", obj1.initName ("Polygon"));
+ break;
+ case typePolyLine:
+ annotObj.dictSet ("Subtype", obj1.initName ("PolyLine"));
+ break;
+ default:
+ assert (0 && "Invalid subtype for AnnotGeometry\n");
+ }
+
+ // Store dummy path with one null vertex only
+ Object obj2, obj3;
+ obj2.initArray (doc->getXRef());
+ obj2.arrayAdd (obj3.initReal (0));
+ obj2.arrayAdd (obj3.initReal (0));
+ annotObj.dictSet ("Vertices", &obj2);
+
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotPolygon::AnnotPolygon(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ // the real type will be read in initialize()
+ type = typePolygon;
+ initialize(docA, dict);
+}
+
+AnnotPolygon::~AnnotPolygon() {
+ delete vertices;
+
+ if (interiorColor)
+ delete interiorColor;
+
+ if (borderEffect)
+ delete borderEffect;
+}
+
+void AnnotPolygon::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("Subtype", &obj1)->isName()) {
+ GooString typeName(obj1.getName());
+ if (!typeName.cmp("Polygon")) {
+ type = typePolygon;
+ } else if (!typeName.cmp("PolyLine")) {
+ type = typePolyLine;
+ }
+ }
+ obj1.free();
+
+ if (dict->lookup("Vertices", &obj1)->isArray()) {
+ vertices = new AnnotPath(obj1.getArray());
+ } else {
+ vertices = new AnnotPath();
+ error(errSyntaxError, -1, "Bad Annot Polygon Vertices");
+ ok = gFalse;
+ }
+ obj1.free();
+
+ if (dict->lookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
+ Object obj2;
+
+ if(obj1.arrayGet(0, &obj2)->isString())
+ startStyle = parseAnnotLineEndingStyle(obj2.getString());
+ else
+ startStyle = annotLineEndingNone;
+ obj2.free();
+
+ if(obj1.arrayGet(1, &obj2)->isString())
+ endStyle = parseAnnotLineEndingStyle(obj2.getString());
+ else
+ endStyle = annotLineEndingNone;
+ obj2.free();
+
+ } else {
+ startStyle = endStyle = annotLineEndingNone;
+ }
+ obj1.free();
+
+ if (dict->lookup("IC", &obj1)->isArray()) {
+ interiorColor = new AnnotColor(obj1.getArray());
+ } else {
+ interiorColor = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ delete border;
+ border = new AnnotBorderBS(obj1.getDict());
+ } else if (!border) {
+ border = new AnnotBorderBS();
+ }
+ obj1.free();
+
+ if (dict->lookup("BE", &obj1)->isDict()) {
+ borderEffect = new AnnotBorderEffect(obj1.getDict());
+ } else {
+ borderEffect = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("IT", &obj1)->isName()) {
+ const char *intentName = obj1.getName();
+
+ if(!strcmp(intentName, "PolygonCloud")) {
+ intent = polygonCloud;
+ } else if(!strcmp(intentName, "PolyLineDimension")) {
+ intent = polylineDimension;
+ } else {
+ intent = polygonDimension;
+ }
+ } else {
+ intent = polygonCloud;
+ }
+ obj1.free();
+}
+
+void AnnotPolygon::setType(AnnotSubtype new_type) {
+ Object obj1;
+
+ switch (new_type) {
+ case typePolygon:
+ obj1.initName("Polygon");
+ break;
+ case typePolyLine:
+ obj1.initName("PolyLine");
+ break;
+ default:
+ assert(!"Invalid subtype");
+ }
+
+ type = new_type;
+ update("Subtype", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotPolygon::setVertices(AnnotPath *path) {
+ Object obj1, obj2;
+ delete vertices;
+
+ obj1.initArray(xref);
+
+ for (int i = 0; i < path->getCoordsLength(); i++) {
+ obj1.arrayAdd (obj2.initReal (path->getX(i)));
+ obj1.arrayAdd (obj2.initReal (path->getY(i)));
+ }
+
+ vertices = new AnnotPath(obj1.getArray());
+
+ update("Vertices", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotPolygon::setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end) {
+ Object obj1, obj2;
+
+ startStyle = start;
+ endStyle = end;
+
+ obj1.initArray(xref);
+ obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( startStyle )) );
+ obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( endStyle )) );
+
+ update("LE", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotPolygon::setInteriorColor(AnnotColor *new_color) {
+ delete interiorColor;
+
+ if (new_color) {
+ Object obj1;
+ new_color->writeToObject(xref, &obj1);
+ update ("IC", &obj1);
+ interiorColor = new_color;
+ } else {
+ interiorColor = NULL;
+ }
+ invalidateAppearance();
+}
+
+void AnnotPolygon::setIntent(AnnotPolygonIntent new_intent) {
+ Object obj1;
+
+ intent = new_intent;
+ if (new_intent == polygonCloud)
+ obj1.initName("PolygonCloud");
+ else if (new_intent == polylineDimension)
+ obj1.initName("PolyLineDimension");
+ else // polygonDimension
+ obj1.initName("PolygonDimension");
+ update ("IT", &obj1);
+}
+
+void AnnotPolygon::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+ double ca = 1;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull()) {
+ appearBBox = new AnnotAppearanceBBox(rect);
+ ca = opacity;
+
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+
+ if (color) {
+ setColor(color, gFalse);
+ }
+
+ setLineStyleForBorder(border);
+ appearBBox->setBorderWidth(std::max(1., border->getWidth()));
+
+ if (interiorColor) {
+ setColor(interiorColor, gTrue);
+ }
+
+ if (vertices->getCoordsLength() != 0) {
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", vertices->getX(0) - rect->x1, vertices->getY(0) - rect->y1);
+ appearBBox->extendTo (vertices->getX(0) - rect->x1, vertices->getY(0) - rect->y1);
+
+ for (int i = 1; i < vertices->getCoordsLength(); ++i) {
+ appearBuf->appendf ("{0:.2f} {1:.2f} l\n", vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1);
+ appearBBox->extendTo (vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1);
+ }
+
+ if (type == typePolygon) {
+ if (interiorColor && interiorColor->getSpace() != AnnotColor::colorTransparent) {
+ appearBuf->append ("b\n");
+ } else {
+ appearBuf->append ("s\n");
+ }
+ } else {
+ appearBuf->append ("S\n");
+ }
+ }
+
+ appearBuf->append ("Q\n");
+
+ double bbox[4];
+ appearBBox->getBBoxRect(bbox);
+ if (ca == 1) {
+ createForm(bbox, gFalse, NULL, &appearance);
+ } else {
+ Object aStream, resDict;
+
+ createForm(bbox, gTrue, NULL, &aStream);
+ delete appearBuf;
+
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ if (appearBBox) {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ appearBBox->getPageXMin(), appearBBox->getPageYMin(),
+ appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+ getRotation());
+ } else {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ }
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotCaret
+//------------------------------------------------------------------------
+AnnotCaret::AnnotCaret(PDFDoc *docA, PDFRectangle *rect) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ type = typeCaret;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("Caret"));
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotCaret::AnnotCaret(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ type = typeCaret;
+ initialize(docA, dict);
+}
+
+AnnotCaret::~AnnotCaret() {
+ delete caretRect;
+}
+
+void AnnotCaret::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ symbol = symbolNone;
+ if (dict->lookup("Sy", &obj1)->isName()) {
+ GooString typeName(obj1.getName());
+ if (!typeName.cmp("P")) {
+ symbol = symbolP;
+ } else if (!typeName.cmp("None")) {
+ symbol = symbolNone;
+ }
+ }
+ obj1.free();
+
+ if (dict->lookup("RD", &obj1)->isArray()) {
+ caretRect = parseDiffRectangle(obj1.getArray(), rect);
+ } else {
+ caretRect = NULL;
+ }
+ obj1.free();
+
+}
+
+void AnnotCaret::setSymbol(AnnotCaretSymbol new_symbol) {
+ Object obj1;
+ obj1.initName( new_symbol == symbolP ? "P" : "None" );
+ symbol = new_symbol;
+ update("Sy", &obj1);
+ invalidateAppearance();
+}
+
+//------------------------------------------------------------------------
+// AnnotInk
+//------------------------------------------------------------------------
+AnnotInk::AnnotInk(PDFDoc *docA, PDFRectangle *rect) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ type = typeInk;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("Ink"));
+
+ // Store dummy path with one null vertex only
+ Object obj2, obj3, obj4;
+ obj2.initArray (doc->getXRef());
+ obj2.arrayAdd (obj3.initArray (doc->getXRef()));
+ obj3.arrayAdd (obj4.initReal (0));
+ obj3.arrayAdd (obj4.initReal (0));
+ annotObj.dictSet ("InkList", &obj2);
+
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotInk::AnnotInk(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ type = typeInk;
+ initialize(docA, dict);
+}
+
+AnnotInk::~AnnotInk() {
+ freeInkList();
+}
+
+void AnnotInk::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("InkList", &obj1)->isArray()) {
+ parseInkList(obj1.getArray());
+ } else {
+ inkListLength = 0;
+ inkList = NULL;
+ error(errSyntaxError, -1, "Bad Annot Ink List");
+ ok = gFalse;
+ }
+ obj1.free();
+
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ delete border;
+ border = new AnnotBorderBS(obj1.getDict());
+ } else if (!border) {
+ border = new AnnotBorderBS();
+ }
+ obj1.free();
+}
+
+void AnnotInk::writeInkList(AnnotPath **paths, int n_paths, Array *dest_array) {
+ Object obj1, obj2;
+ for (int i = 0; i < n_paths; ++i) {
+ AnnotPath *path = paths[i];
+ obj1.initArray (xref);
+ for (int j = 0; j < path->getCoordsLength(); ++j) {
+ obj1.arrayAdd (obj2.initReal (path->getX(j)));
+ obj1.arrayAdd (obj2.initReal (path->getY(j)));
+ }
+ dest_array->add (&obj1);
+ }
+}
+
+void AnnotInk::parseInkList(Array *array) {
+ inkListLength = array->getLength();
+ inkList = (AnnotPath **) gmallocn ((inkListLength), sizeof(AnnotPath *));
+ memset(inkList, 0, inkListLength * sizeof(AnnotPath *));
+ for (int i = 0; i < inkListLength; i++) {
+ Object obj2;
+ if (array->get(i, &obj2)->isArray())
+ inkList[i] = new AnnotPath(obj2.getArray());
+ obj2.free();
+ }
+}
+
+void AnnotInk::freeInkList() {
+ if (inkList) {
+ for (int i = 0; i < inkListLength; ++i)
+ delete inkList[i];
+ gfree(inkList);
+ }
+}
+
+void AnnotInk::setInkList(AnnotPath **paths, int n_paths) {
+ Object obj1;
+
+ freeInkList();
+
+ obj1.initArray (xref);
+ writeInkList(paths, n_paths, obj1.getArray());
+
+ parseInkList(obj1.getArray());
+ annotObj.dictSet ("InkList", &obj1);
+ invalidateAppearance();
+}
+
+void AnnotInk::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+ double ca = 1;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull()) {
+ appearBBox = new AnnotAppearanceBBox(rect);
+ ca = opacity;
+
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+
+ if (color) {
+ setColor(color, gFalse);
+ }
+
+ setLineStyleForBorder(border);
+ appearBBox->setBorderWidth(std::max(1., border->getWidth()));
+
+ for (int i = 0; i < inkListLength; ++i) {
+ const AnnotPath * path = inkList[i];
+ if (path->getCoordsLength() != 0) {
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", path->getX(0) - rect->x1, path->getY(0) - rect->y1);
+ appearBBox->extendTo (path->getX(0) - rect->x1, path->getY(0) - rect->y1);
+
+ for (int j = 1; j < path->getCoordsLength(); ++j) {
+ appearBuf->appendf ("{0:.2f} {1:.2f} l\n", path->getX(j) - rect->x1, path->getY(j) - rect->y1);
+ appearBBox->extendTo (path->getX(j) - rect->x1, path->getY(j) - rect->y1);
+ }
+
+ appearBuf->append ("S\n");
+ }
+ }
+
+ appearBuf->append ("Q\n");
+
+ double bbox[4];
+ appearBBox->getBBoxRect(bbox);
+ if (ca == 1) {
+ createForm(bbox, gFalse, NULL, &appearance);
+ } else {
+ Object aStream, resDict;
+
+ createForm(bbox, gTrue, NULL, &aStream);
+ delete appearBuf;
+
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ if (appearBBox) {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ appearBBox->getPageXMin(), appearBBox->getPageYMin(),
+ appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+ getRotation());
+ } else {
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ }
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotFileAttachment
+//------------------------------------------------------------------------
+AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooString *filename) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ type = typeFileAttachment;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("FileAttachment"));
+
+ Object obj2;
+ obj2.initString(filename->copy());
+ annotObj.dictSet ("FS", &obj2);
+
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ type = typeFileAttachment;
+ initialize(docA, dict);
+}
+
+AnnotFileAttachment::~AnnotFileAttachment() {
+ file.free();
+
+ if (name)
+ delete name;
+}
+
+void AnnotFileAttachment::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("FS", &obj1)->isDict() || dict->lookup("FS", &obj1)->isString()) {
+ obj1.copy(&file);
+ } else {
+ error(errSyntaxError, -1, "Bad Annot File Attachment");
+ ok = gFalse;
+ }
+ obj1.free();
+
+ if (dict->lookup("Name", &obj1)->isName()) {
+ name = new GooString(obj1.getName());
+ } else {
+ name = new GooString("PushPin");
+ }
+ obj1.free();
+}
+
+#define ANNOT_FILE_ATTACHMENT_AP_PUSHPIN \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 5 4 m 6 5 l S\n" \
+ "2 w\n" \
+ "11 14 m 9 12 l 6 12 l 13 5 l 13 8 l 15 10 l 18 11 l 20 11 l 12 19 l 12\n" \
+ "17 l 11 14 l h\n" \
+ "11 14 m S\n" \
+ "3 w\n" \
+ "6 5 m 9 8 l S\n" \
+ "0.729412 0.741176 0.713725 RG 2 w\n" \
+ "5 5 m 6 6 l S\n" \
+ "2 w\n" \
+ "11 15 m 9 13 l 6 13 l 13 6 l 13 9 l 15 11 l 18 12 l 20 12 l 12 20 l 12\n" \
+ "18 l 11 15 l h\n" \
+ "11 15 m S\n" \
+ "3 w\n" \
+ "6 6 m 9 9 l S\n"
+
+#define ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 16.645 12.035 m 12.418 7.707 l 10.902 6.559 6.402 11.203 8.09 12.562 c\n" \
+ "14.133 18.578 l 14.949 19.387 16.867 19.184 17.539 18.465 c 20.551\n" \
+ "15.23 l 21.191 14.66 21.336 12.887 20.426 12.102 c 13.18 4.824 l 12.18\n" \
+ "3.82 6.25 2.566 4.324 4.461 c 3 6.395 3.383 11.438 4.711 12.801 c 9.648\n" \
+ "17.887 l S\n" \
+ "0.729412 0.741176 0.713725 RG 16.645 13.035 m 12.418 8.707 l\n" \
+ "10.902 7.559 6.402 12.203 8.09 13.562 c\n" \
+ "14.133 19.578 l 14.949 20.387 16.867 20.184 17.539 19.465 c 20.551\n" \
+ "16.23 l 21.191 15.66 21.336 13.887 20.426 13.102 c 13.18 5.824 l 12.18\n" \
+ "4.82 6.25 3.566 4.324 5.461 c 3 7.395 3.383 12.438 4.711 13.801 c 9.648\n" \
+ "18.887 l S\n"
+
+#define ANNOT_FILE_ATTACHMENT_AP_GRAPH \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 1 w\n" \
+ "1 J\n" \
+ "0 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 18.5 15.5 m 18.5 13.086 l 16.086 15.5 l 18.5 15.5 l h\n" \
+ "18.5 15.5 m S\n" \
+ "7 7 m 10 11 l 13 9 l 18 15 l S\n" \
+ "0.729412 0.741176 0.713725 RG 7 8 m 10 12 l 13 10 l 18 16 l S\n" \
+ "18.5 16.5 m 18.5 14.086 l 16.086 16.5 l 18.5 16.5 l h\n" \
+ "18.5 16.5 m S\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "1 j\n" \
+ "3 19 m 3 3 l 21 3 l S\n" \
+ "0.729412 0.741176 0.713725 RG 3 20 m 3 4 l 21 4 l S\n"
+
+#define ANNOT_FILE_ATTACHMENT_AP_TAG \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 0.999781 w\n" \
+ "1 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M q 1 0 0 -1 0 24 cm\n" \
+ "8.492 8.707 m 8.492 9.535 7.82 10.207 6.992 10.207 c 6.164 10.207 5.492\n" \
+ "9.535 5.492 8.707 c 5.492 7.879 6.164 7.207 6.992 7.207 c 7.82 7.207\n" \
+ "8.492 7.879 8.492 8.707 c h\n" \
+ "8.492 8.707 m S Q\n" \
+ "2 w\n" \
+ "20.078 11.414 m 20.891 10.602 20.785 9.293 20.078 8.586 c 14.422 2.93 l\n" \
+ "13.715 2.223 12.301 2.223 11.594 2.93 c 3.816 10.707 l 3.109 11.414\n" \
+ "2.402 17.781 3.816 19.195 c 5.23 20.609 11.594 19.902 12.301 19.195 c\n" \
+ "20.078 11.414 l h\n" \
+ "20.078 11.414 m S\n" \
+ "0.729412 0.741176 0.713725 RG 20.078 12.414 m\n" \
+ "20.891 11.605 20.785 10.293 20.078 9.586 c 14.422 3.93 l\n" \
+ "13.715 3.223 12.301 3.223 11.594 3.93 c 3.816 11.707 l 3.109 12.414\n" \
+ "2.402 18.781 3.816 20.195 c 5.23 21.609 11.594 20.902 12.301 20.195 c\n" \
+ "20.078 12.414 l h\n" \
+ "20.078 12.414 m S\n" \
+ "0.533333 0.541176 0.521569 RG 1 w\n" \
+ "0 j\n" \
+ "11.949 13.184 m 16.191 8.941 l S\n" \
+ "0.729412 0.741176 0.713725 RG 11.949 14.184 m 16.191 9.941 l S\n" \
+ "0.533333 0.541176 0.521569 RG 14.07 6.82 m 9.828 11.062 l S\n" \
+ "0.729412 0.741176 0.713725 RG 14.07 7.82 m 9.828 12.062 l S\n" \
+ "0.533333 0.541176 0.521569 RG 6.93 15.141 m 8 20 14.27 20.5 16 20.5 c\n" \
+ "18.094 20.504 19.5 20 19.5 18 c 19.5 16.699 20.91 16.418 22.5 16.5 c S\n" \
+ "0.729412 0.741176 0.713725 RG 0.999781 w\n" \
+ "1 j\n" \
+ "q 1 0 0 -1 0 24 cm\n" \
+ "8.492 7.707 m 8.492 8.535 7.82 9.207 6.992 9.207 c 6.164 9.207 5.492\n" \
+ "8.535 5.492 7.707 c 5.492 6.879 6.164 6.207 6.992 6.207 c 7.82 6.207\n" \
+ "8.492 6.879 8.492 7.707 c h\n" \
+ "8.492 7.707 m S Q\n" \
+ "1 w\n" \
+ "0 j\n" \
+ "6.93 16.141 m 8 21 14.27 21.5 16 21.5 c 18.094 21.504 19.5 21 19.5 19 c\n" \
+ "19.5 17.699 20.91 17.418 22.5 17.5 c S\n"
+
+void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+ double ca = 1;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull()) {
+ ca = opacity;
+
+ appearBuf = new GooString ();
+
+ appearBuf->append ("q\n");
+ if (color)
+ setColor(color, gTrue);
+ else
+ appearBuf->append ("1 1 1 rg\n");
+ if (!name->cmp("PushPin"))
+ appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_PUSHPIN);
+ else if (!name->cmp("Paperclip"))
+ appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP);
+ else if (!name->cmp("Graph"))
+ appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_GRAPH);
+ else if (!name->cmp("Tag"))
+ appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_TAG);
+ appearBuf->append ("Q\n");
+
+ double bbox[4];
+ bbox[0] = bbox[1] = 0;
+ bbox[2] = bbox[3] = 24;
+ if (ca == 1) {
+ createForm (bbox, gFalse, NULL, &appearance);
+ } else {
+ Object aStream;
+
+ createForm (bbox, gTrue, NULL, &aStream);
+ delete appearBuf;
+
+ Object resDict;
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotSound
+//------------------------------------------------------------------------
+AnnotSound::AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA) :
+ AnnotMarkup(docA, rect) {
+ Object obj1;
+
+ type = typeSound;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("Sound"));
+
+ Object obj2;
+ Stream *str = soundA->getStream();
+ obj2.initStream (str);
+ str->incRef(); //FIXME: initStream should do this?
+ annotObj.dictSet ("Sound", &obj2);
+
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotSound::AnnotSound(PDFDoc *docA, Dict *dict, Object *obj) :
+ AnnotMarkup(docA, dict, obj) {
+ type = typeSound;
+ initialize(docA, dict);
+}
+
+AnnotSound::~AnnotSound() {
+ delete sound;
+
+ delete name;
+}
+
+void AnnotSound::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ sound = Sound::parseSound(dict->lookup("Sound", &obj1));
+ if (!sound) {
+ error(errSyntaxError, -1, "Bad Annot Sound");
+ ok = gFalse;
+ }
+ obj1.free();
+
+ if (dict->lookup("Name", &obj1)->isName()) {
+ name = new GooString(obj1.getName());
+ } else {
+ name = new GooString("Speaker");
+ }
+ obj1.free();
+}
+
+#define ANNOT_SOUND_AP_SPEAKER \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "0 J\n" \
+ "1 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 4 14 m 4.086 8.043 l 7 8 l 11 4 l 11 18 l 7 14 l 4 14 l h\n" \
+ "4 14 m S\n" \
+ "1 w\n" \
+ "1 J\n" \
+ "0 j\n" \
+ "13.699 15.398 m 14.699 13.398 14.699 9.398 13.699 7.398 c S\n" \
+ "18.199 19.398 m 21.199 17.398 21.199 5.398 18.199 3.398 c S\n" \
+ "16 17.398 m 18 16.398 18 7.398 16 5.398 c S\n" \
+ "0.729412 0.741176 0.713725 RG 2 w\n" \
+ "0 J\n" \
+ "1 j\n" \
+ "4 15 m 4.086 9.043 l 7 9 l 11 5 l 11 19 l 7 15 l 4 15 l h\n" \
+ "4 15 m S\n" \
+ "1 w\n" \
+ "1 J\n" \
+ "0 j\n" \
+ "13.699 16 m 14.699 14 14.699 10 13.699 8 c S\n" \
+ "18.199 20 m 21.199 18 21.199 6 18.199 4 c S\n" \
+ "16 18 m 18 17 18 8 16 6 c S\n"
+
+#define ANNOT_SOUND_AP_MIC \
+ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \
+ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \
+ "l 1 21.523 2.477 23 4.301 23 c h\n" \
+ "4.301 23 m f\n" \
+ "0.533333 0.541176 0.521569 RG 2 w\n" \
+ "1 J\n" \
+ "0 j\n" \
+ "[] 0.0 d\n" \
+ "4 M 12 20 m 12 20 l 13.656 20 15 18.656 15 17 c 15 13 l 15 11.344 13.656 10\n" \
+ "12 10 c 12 10 l 10.344 10 9 11.344 9 13 c 9 17 l 9 18.656 10.344 20 12\n" \
+ "20 c h\n" \
+ "12 20 m S\n" \
+ "1 w\n" \
+ "17.5 14.5 m 17.5 11.973 l 17.5 8.941 15.047 6.5 12 6.5 c 8.953 6.5 6.5\n" \
+ "8.941 6.5 11.973 c 6.5 14.5 l S\n" \
+ "2 w\n" \
+ "0 J\n" \
+ "12 6.52 m 12 3 l S\n" \
+ "1 J\n" \
+ "8 3 m 16 3 l S\n" \
+ "0.729412 0.741176 0.713725 RG 12 21 m 12 21 l 13.656 21 15 19.656 15 18 c\n" \
+ "15 14 l 15 12.344 13.656 11 12 11 c 12 11 l 10.344 11 9 12.344 9 14 c\n" \
+ "9 18 l 9 19.656 10.344 21 12 21 c h\n" \
+ "12 21 m S\n" \
+ "1 w\n" \
+ "17.5 15.5 m 17.5 12.973 l 17.5 9.941 15.047 7.5 12 7.5 c 8.953 7.5 6.5\n" \
+ "9.941 6.5 12.973 c 6.5 15.5 l S\n" \
+ "2 w\n" \
+ "0 J\n" \
+ "12 7.52 m 12 4 l S\n" \
+ "1 J\n" \
+ "8 4 m 16 4 l S\n"
+
+void AnnotSound::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+ double ca = 1;
+
+ if (!isVisible (printing))
+ return;
+
+ annotLocker();
+ if (appearance.isNull()) {
+ ca = opacity;
+
+ appearBuf = new GooString ();
+
+ appearBuf->append ("q\n");
+ if (color)
+ setColor(color, gTrue);
+ else
+ appearBuf->append ("1 1 1 rg\n");
+ if (!name->cmp("Speaker"))
+ appearBuf->append (ANNOT_SOUND_AP_SPEAKER);
+ else if (!name->cmp("Mic"))
+ appearBuf->append (ANNOT_SOUND_AP_MIC);
+ appearBuf->append ("Q\n");
+
+ double bbox[4];
+ bbox[0] = bbox[1] = 0;
+ bbox[2] = bbox[3] = 24;
+ if (ca == 1) {
+ createForm(bbox, gFalse, NULL, &appearance);
+ } else {
+ Object aStream, resDict;
+
+ createForm(bbox, gTrue, NULL, &aStream);
+ delete appearBuf;
+
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+ }
+
+ // draw the appearance stream
+ appearance.fetch(gfx->getXRef(), &obj);
+ gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+ rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// Annot3D
+//------------------------------------------------------------------------
+Annot3D::Annot3D(PDFDoc *docA, PDFRectangle *rect) :
+ Annot(docA, rect) {
+ Object obj1;
+
+ type = type3D;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("3D"));
+
+ initialize(docA, annotObj.getDict());
+}
+
+Annot3D::Annot3D(PDFDoc *docA, Dict *dict, Object *obj) :
+ Annot(docA, dict, obj) {
+ type = type3D;
+ initialize(docA, dict);
+}
+
+Annot3D::~Annot3D() {
+ if (activation)
+ delete activation;
+}
+
+void Annot3D::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("3DA", &obj1)->isDict()) {
+ activation = new Activation(obj1.getDict());
+ } else {
+ activation = NULL;
+ }
+ obj1.free();
+}
+
+Annot3D::Activation::Activation(Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("A", &obj1)->isName()) {
+ const char *name = obj1.getName();
+
+ if(!strcmp(name, "PO")) {
+ aTrigger = aTriggerPageOpened;
+ } else if(!strcmp(name, "PV")) {
+ aTrigger = aTriggerPageVisible;
+ } else if(!strcmp(name, "XA")) {
+ aTrigger = aTriggerUserAction;
+ } else {
+ aTrigger = aTriggerUnknown;
+ }
+ } else {
+ aTrigger = aTriggerUnknown;
+ }
+ obj1.free();
+
+ if(dict->lookup("AIS", &obj1)->isName()) {
+ const char *name = obj1.getName();
+
+ if(!strcmp(name, "I")) {
+ aState = aStateEnabled;
+ } else if(!strcmp(name, "L")) {
+ aState = aStateDisabled;
+ } else {
+ aState = aStateUnknown;
+ }
+ } else {
+ aState = aStateUnknown;
+ }
+ obj1.free();
+
+ if(dict->lookup("D", &obj1)->isName()) {
+ const char *name = obj1.getName();
+
+ if(!strcmp(name, "PC")) {
+ dTrigger = dTriggerPageClosed;
+ } else if(!strcmp(name, "PI")) {
+ dTrigger = dTriggerPageInvisible;
+ } else if(!strcmp(name, "XD")) {
+ dTrigger = dTriggerUserAction;
+ } else {
+ dTrigger = dTriggerUnknown;
+ }
+ } else {
+ dTrigger = dTriggerUnknown;
+ }
+ obj1.free();
+
+ if(dict->lookup("DIS", &obj1)->isName()) {
+ const char *name = obj1.getName();
+
+ if(!strcmp(name, "U")) {
+ dState = dStateUninstantiaded;
+ } else if(!strcmp(name, "I")) {
+ dState = dStateInstantiated;
+ } else if(!strcmp(name, "L")) {
+ dState = dStateLive;
+ } else {
+ dState = dStateUnknown;
+ }
+ } else {
+ dState = dStateUnknown;
+ }
+ obj1.free();
+
+ if (dict->lookup("TB", &obj1)->isBool()) {
+ displayToolbar = obj1.getBool();
+ } else {
+ displayToolbar = gTrue;
+ }
+ obj1.free();
+
+ if (dict->lookup("NP", &obj1)->isBool()) {
+ displayNavigation = obj1.getBool();
+ } else {
+ displayNavigation = gFalse;
+ }
+ obj1.free();
+}
+
+//------------------------------------------------------------------------
+// AnnotRichMedia
+//------------------------------------------------------------------------
+AnnotRichMedia::AnnotRichMedia(PDFDoc *docA, PDFRectangle *rect) :
+ Annot(docA, rect) {
+ Object obj1;
+
+ type = typeRichMedia;
+
+ annotObj.dictSet ("Subtype", obj1.initName ("RichMedia"));
+
+ initialize(docA, annotObj.getDict());
+}
+
+AnnotRichMedia::AnnotRichMedia(PDFDoc *docA, Dict *dict, Object *obj) :
+ Annot(docA, dict, obj) {
+ type = typeRichMedia;
+ initialize(docA, dict);
+}
+
+AnnotRichMedia::~AnnotRichMedia() {
+ delete content;
+ delete settings;
+}
+
+void AnnotRichMedia::initialize(PDFDoc *docA, Dict* dict) {
+ Object obj1;
+
+ if (dict->lookup("RichMediaContent", &obj1)->isDict()) {
+ content = new AnnotRichMedia::Content(obj1.getDict());
+ } else {
+ content = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("RichMediaSettings", &obj1)->isDict()) {
+ settings = new AnnotRichMedia::Settings(obj1.getDict());
+ } else {
+ settings = NULL;
+ }
+ obj1.free();
+}
+
+AnnotRichMedia::Content* AnnotRichMedia::getContent() const {
+ return content;
+}
+
+AnnotRichMedia::Settings* AnnotRichMedia::getSettings() const {
+ return settings;
+}
+
+AnnotRichMedia::Settings::Settings(Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("Activation", &obj1)->isDict()) {
+ activation = new AnnotRichMedia::Activation(obj1.getDict());
+ } else {
+ activation = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("Deactivation", &obj1)->isDict()) {
+ deactivation = new AnnotRichMedia::Deactivation(obj1.getDict());
+ } else {
+ deactivation = NULL;
+ }
+ obj1.free();
+}
+
+AnnotRichMedia::Settings::~Settings() {
+ delete activation;
+ delete deactivation;
+}
+
+AnnotRichMedia::Activation* AnnotRichMedia::Settings::getActivation() const {
+ return activation;
+}
+
+AnnotRichMedia::Deactivation* AnnotRichMedia::Settings::getDeactivation() const {
+ return deactivation;
+}
+
+AnnotRichMedia::Activation::Activation(Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("Condition", &obj1)->isName()) {
+ const char *name = obj1.getName();
+
+ if (!strcmp(name, "PO")) {
+ condition = conditionPageOpened;
+ } else if (!strcmp(name, "PV")) {
+ condition = conditionPageVisible;
+ } else if (!strcmp(name, "XA")) {
+ condition = conditionUserAction;
+ } else {
+ condition = conditionUserAction;
+ }
+ } else {
+ condition = conditionUserAction;
+ }
+ obj1.free();
+}
+
+AnnotRichMedia::Activation::Condition AnnotRichMedia::Activation::getCondition() const {
+ return condition;
+}
+
+AnnotRichMedia::Deactivation::Deactivation(Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("Condition", &obj1)->isName()) {
+ const char *name = obj1.getName();
+
+ if (!strcmp(name, "PC")) {
+ condition = conditionPageClosed;
+ } else if (!strcmp(name, "PI")) {
+ condition = conditionPageInvisible;
+ } else if (!strcmp(name, "XD")) {
+ condition = conditionUserAction;
+ } else {
+ condition = conditionUserAction;
+ }
+ } else {
+ condition = conditionUserAction;
+ }
+ obj1.free();
+}
+
+AnnotRichMedia::Deactivation::Condition AnnotRichMedia::Deactivation::getCondition() const {
+ return condition;
+}
+
+AnnotRichMedia::Content::Content(Dict *dict) {
+ Object obj1;
+
+ if (dict->lookup("Configurations", &obj1)->isArray()) {
+ nConfigurations = obj1.arrayGetLength();
+
+ configurations = (Configuration **)gmallocn(nConfigurations, sizeof(Configuration *));
+
+ for (int i = 0; i < nConfigurations; ++i) {
+ Object obj2;
+
+ if (obj1.arrayGet(i, &obj2)->isDict()) {
+ configurations[i] = new AnnotRichMedia::Configuration(obj2.getDict());
+ } else {
+ configurations[i] = NULL;
+ }
+ obj2.free();
+ }
+ } else {
+ configurations = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("Assets", &obj1)->isDict()) {
+ Object obj2;
+
+ if (obj1.getDict()->lookup("Names", &obj2)->isArray()) {
+ nAssets = obj2.arrayGetLength() / 2;
+
+ assets = (Asset **)gmallocn(nAssets, sizeof(Asset *));
+
+ int counter = 0;
+ for (int i = 0; i < obj2.arrayGetLength(); i += 2) {
+ Object objKey;
+
+ assets[counter] = new AnnotRichMedia::Asset;
+
+ obj2.arrayGet(i, &objKey);
+ obj2.arrayGet(i + 1, &assets[counter]->fileSpec);
+
+ assets[counter]->name = new GooString( objKey.getString() );
+ ++counter;
+
+ objKey.free();
+ }
+ }
+ obj2.free();
+
+ } else {
+ assets = NULL;
+ }
+ obj1.free();
+}
+
+AnnotRichMedia::Content::~Content() {
+ if (configurations) {
+ for (int i = 0; i < nConfigurations; ++i)
+ delete configurations[i];
+ gfree(configurations);
+ }
+
+ if (assets) {
+ for (int i = 0; i < nAssets; ++i)
+ delete assets[i];
+ gfree(assets);
+ }
+}
+
+int AnnotRichMedia::Content::getConfigurationsCount() const {
+ return nConfigurations;
+}
+
+AnnotRichMedia::Configuration* AnnotRichMedia::Content::getConfiguration(int index) const {
+ if (index < 0 || index >= nConfigurations)
+ return NULL;
+
+ return configurations[index];
+}
+
+int AnnotRichMedia::Content::getAssetsCount() const {
+ return nAssets;
+}
+
+AnnotRichMedia::Asset* AnnotRichMedia::Content::getAsset(int index) const {
+ if (index < 0 || index >= nAssets)
+ return NULL;
+
+ return assets[index];
+}
+
+AnnotRichMedia::Asset::Asset()
+ : name(NULL)
+{
+}
+
+AnnotRichMedia::Asset::~Asset()
+{
+ delete name;
+ fileSpec.free();
+}
+
+GooString* AnnotRichMedia::Asset::getName() const {
+ return name;
+}
+
+Object* AnnotRichMedia::Asset::getFileSpec() const {
+ return const_cast<Object*>(&fileSpec);
+}
+
+AnnotRichMedia::Configuration::Configuration(Dict *dict)
+{
+ Object obj1;
+
+ if (dict->lookup("Instances", &obj1)->isArray()) {
+ nInstances = obj1.arrayGetLength();
+
+ instances = (Instance **)gmallocn(nInstances, sizeof(Instance *));
+
+ for (int i = 0; i < nInstances; ++i) {
+ Object obj2;
+
+ if (obj1.arrayGet(i, &obj2)->isDict()) {
+ instances[i] = new AnnotRichMedia::Instance(obj2.getDict());
+ } else {
+ instances[i] = NULL;
+ }
+ obj2.free();
+ }
+ } else {
+ instances = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("Name", &obj1)->isString()) {
+ name = new GooString(obj1.getString());
+ } else {
+ name = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("Subtype", &obj1)->isName()) {
+ const char *name = obj1.getName();
+
+ if (!strcmp(name, "3D")) {
+ type = type3D;
+ } else if (!strcmp(name, "Flash")) {
+ type = typeFlash;
+ } else if (!strcmp(name, "Sound")) {
+ type = typeSound;
+ } else if (!strcmp(name, "Video")) {
+ type = typeVideo;
+ } else {
+ // determine from first instance
+ if (instances && nInstances > 0) {
+ AnnotRichMedia::Instance *instance = instances[0];
+ switch (instance->getType()) {
+ case AnnotRichMedia::Instance::type3D:
+ type = type3D;
+ break;
+ case AnnotRichMedia::Instance::typeFlash:
+ type = typeFlash;
+ break;
+ case AnnotRichMedia::Instance::typeSound:
+ type = typeSound;
+ break;
+ case AnnotRichMedia::Instance::typeVideo:
+ type = typeVideo;
+ break;
+ default:
+ type = typeFlash;
+ break;
+ }
+ }
+ }
+ }
+ obj1.free();
+}
+
+AnnotRichMedia::Configuration::~Configuration()
+{
+ if (instances) {
+ for (int i = 0; i < nInstances; ++i)
+ delete instances[i];
+ gfree(instances);
+ }
+
+ delete name;
+}
+
+int AnnotRichMedia::Configuration::getInstancesCount() const {
+ return nInstances;
+}
+
+AnnotRichMedia::Instance* AnnotRichMedia::Configuration::getInstance(int index) const {
+ if (index < 0 || index >= nInstances)
+ return NULL;
+
+ return instances[index];
+}
+
+GooString* AnnotRichMedia::Configuration::getName() const {
+ return name;
+}
+
+AnnotRichMedia::Configuration::Type AnnotRichMedia::Configuration::getType() const {
+ return type;
+}
+
+AnnotRichMedia::Instance::Instance(Dict *dict)
+{
+ Object obj1;
+
+ if (dict->lookup("Subtype", &obj1)->isName()) {
+ const char *name = obj1.getName();
+
+ if (!strcmp(name, "3D")) {
+ type = type3D;
+ } else if (!strcmp(name, "Flash")) {
+ type = typeFlash;
+ } else if (!strcmp(name, "Sound")) {
+ type = typeSound;
+ } else if (!strcmp(name, "Video")) {
+ type = typeVideo;
+ } else {
+ type = typeFlash;
+ }
+ }
+ obj1.free();
+
+ if (dict->lookup("Params", &obj1)->isDict()) {
+ params = new AnnotRichMedia::Params(obj1.getDict());
+ } else {
+ params = NULL;
+ }
+}
+
+AnnotRichMedia::Instance::~Instance()
+{
+ delete params;
+}
+
+AnnotRichMedia::Instance::Type AnnotRichMedia::Instance::getType() const {
+ return type;
+}
+
+AnnotRichMedia::Params* AnnotRichMedia::Instance::getParams() const {
+ return params;
+}
+
+AnnotRichMedia::Params::Params(Dict *dict)
+{
+ Object obj1;
+
+ if (dict->lookup("FlashVars", &obj1)->isString()) {
+ flashVars = new GooString(obj1.getString());
+ } else {
+ flashVars = NULL;
+ }
+ obj1.free();
+}
+
+AnnotRichMedia::Params::~Params()
+{
+ delete flashVars;
+}
+
+GooString* AnnotRichMedia::Params::getFlashVars() const {
+ return flashVars;
+}
+
+//------------------------------------------------------------------------
+// Annots
+//------------------------------------------------------------------------
+
+Annots::Annots(PDFDoc *docA, int page, Object *annotsObj) {
+ Annot *annot;
+ Object obj1;
+ int i;
+
+ doc = docA;
+ annots = NULL;
+ size = 0;
+ nAnnots = 0;
+
+ if (annotsObj->isArray()) {
+ for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
+ //get the Ref to this annot and pass it to Annot constructor
+ //this way, it'll be possible for the annot to retrieve the corresponding
+ //form widget
+ Object obj2;
+ if (annotsObj->arrayGet(i, &obj1)->isDict()) {
+ annotsObj->arrayGetNF(i, &obj2);
+ annot = createAnnot (obj1.getDict(), &obj2);
+ if (annot) {
+ if (annot->isOk()) {
+ annot->setPage(page, gFalse); // Don't change /P
+ appendAnnot(annot);
+ }
+ annot->decRefCnt();
+ }
+ }
+ obj2.free();
+ obj1.free();
+ }
+ }
+}
+
+void Annots::appendAnnot(Annot *annot) {
+ if (annot && annot->isOk()) {
+ if (nAnnots >= size) {
+ size += 16;
+ annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
+ }
+ annots[nAnnots++] = annot;
+ annot->incRefCnt();
+ }
+}
+
+GBool Annots::removeAnnot(Annot *annot) {
+ int idx = -1;
+ // Search annot and determine its index
+ for (int i = 0; idx == -1 && i < nAnnots; i++) {
+ if (annots[i] == annot) {
+ idx = i;
+ }
+ }
+ if (idx == -1) {
+ return gFalse;
+ } else {
+ --nAnnots;
+ memmove( annots + idx, annots + idx + 1, sizeof(annots[0]) * (nAnnots - idx) );
+ annot->decRefCnt();
+ return gTrue;
+ }
+}
+
+Annot *Annots::createAnnot(Dict* dict, Object *obj) {
+ Annot *annot = NULL;
+ Object obj1;
+
+ if (dict->lookup("Subtype", &obj1)->isName()) {
+ const char *typeName = obj1.getName();
+
+ if (!strcmp(typeName, "Text")) {
+ annot = new AnnotText(doc, dict, obj);
+ } else if (!strcmp(typeName, "Link")) {
+ annot = new AnnotLink(doc, dict, obj);
+ } else if (!strcmp(typeName, "FreeText")) {
+ annot = new AnnotFreeText(doc, dict, obj);
+ } else if (!strcmp(typeName, "Line")) {
+ annot = new AnnotLine(doc, dict, obj);
+ } else if (!strcmp(typeName, "Square")) {
+ annot = new AnnotGeometry(doc, dict, obj);
+ } else if (!strcmp(typeName, "Circle")) {
+ annot = new AnnotGeometry(doc, dict, obj);
+ } else if (!strcmp(typeName, "Polygon")) {
+ annot = new AnnotPolygon(doc, dict, obj);
+ } else if (!strcmp(typeName, "PolyLine")) {
+ annot = new AnnotPolygon(doc, dict, obj);
+ } else if (!strcmp(typeName, "Highlight")) {
+ annot = new AnnotTextMarkup(doc, dict, obj);
+ } else if (!strcmp(typeName, "Underline")) {
+ annot = new AnnotTextMarkup(doc, dict, obj);
+ } else if (!strcmp(typeName, "Squiggly")) {
+ annot = new AnnotTextMarkup(doc, dict, obj);
+ } else if (!strcmp(typeName, "StrikeOut")) {
+ annot = new AnnotTextMarkup(doc, dict, obj);
+ } else if (!strcmp(typeName, "Stamp")) {
+ annot = new AnnotStamp(doc, dict, obj);
+ } else if (!strcmp(typeName, "Caret")) {
+ annot = new AnnotCaret(doc, dict, obj);
+ } else if (!strcmp(typeName, "Ink")) {
+ annot = new AnnotInk(doc, dict, obj);
+ } else if (!strcmp(typeName, "FileAttachment")) {
+ annot = new AnnotFileAttachment(doc, dict, obj);
+ } else if (!strcmp(typeName, "Sound")) {
+ annot = new AnnotSound(doc, dict, obj);
+ } else if(!strcmp(typeName, "Movie")) {
+ annot = new AnnotMovie(doc, dict, obj);
+ } else if(!strcmp(typeName, "Widget")) {
+ // Find the annot in forms
+ if (obj->isRef()) {
+ Form *form = doc->getCatalog()->getForm();
+ if (form) {
+ FormWidget *widget = form->findWidgetByRef(obj->getRef());
+ if (widget) {
+ annot = widget->getWidgetAnnotation();
+ annot->incRefCnt();
+ }
+ }
+ }
+ if (!annot)
+ annot = new AnnotWidget(doc, dict, obj);
+ } else if(!strcmp(typeName, "Screen")) {
+ annot = new AnnotScreen(doc, dict, obj);
+ } else if(!strcmp(typeName, "PrinterMark")) {
+ annot = new Annot(doc, dict, obj);
+ } else if (!strcmp(typeName, "TrapNet")) {
+ annot = new Annot(doc, dict, obj);
+ } else if (!strcmp(typeName, "Watermark")) {
+ annot = new Annot(doc, dict, obj);
+ } else if (!strcmp(typeName, "3D")) {
+ annot = new Annot3D(doc, dict, obj);
+ } else if (!strcmp(typeName, "RichMedia")) {
+ annot = new AnnotRichMedia(doc, dict, obj);
+ } else if (!strcmp(typeName, "Popup")) {
+ /* Popup annots are already handled by markup annots
+ * Here we only care about popup annots without a
+ * markup annotation associated
+ */
+ Object obj2;
+
+ if (dict->lookup("Parent", &obj2)->isNull())
+ annot = new AnnotPopup(doc, dict, obj);
+ else
+ annot = NULL;
+
+ obj2.free();
+ } else {
+ annot = new Annot(doc, dict, obj);
+ }
+ }
+ obj1.free();
+
+ return annot;
+}
+
+Annot *Annots::findAnnot(Ref *ref) {
+ int i;
+
+ for (i = 0; i < nAnnots; ++i) {
+ if (annots[i]->match(ref)) {
+ return annots[i];
+ }
+ }
+ return NULL;
+}
+
+
+Annots::~Annots() {
+ int i;
+
+ for (i = 0; i < nAnnots; ++i) {
+ annots[i]->decRefCnt();
+ }
+ gfree(annots);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Annot.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Annot.h
new file mode 100644
index 00000000000..d90c8080ffe
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Annot.h
@@ -0,0 +1,1609 @@
+//========================================================================
+//
+// Annot.h
+//
+// Copyright 2000-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
+// Copyright (C) 2007, 2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2007-2011, 2013, 2015 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2007, 2008 Iñigo Martínez <inigomartinez@gmail.com>
+// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
+// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
+// Copyright (C) 2008 Pino Toscano <pino@kde.org>
+// Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com>
+// Copyright (C) 2009-2011, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012, 2015 Tobias Koenig <tokoe@kdab.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef ANNOT_H
+#define ANNOT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class XRef;
+class Gfx;
+class CharCodeToUnicode;
+class GfxFont;
+class GfxResources;
+class Page;
+class PDFDoc;
+class Form;
+class FormWidget;
+class FormField;
+class FormFieldChoice;
+class PDFRectangle;
+class Movie;
+class LinkAction;
+class Sound;
+class FileSpec;
+
+enum AnnotLineEndingStyle {
+ annotLineEndingSquare, // Square
+ annotLineEndingCircle, // Circle
+ annotLineEndingDiamond, // Diamond
+ annotLineEndingOpenArrow, // OpenArrow
+ annotLineEndingClosedArrow, // ClosedArrow
+ annotLineEndingNone, // None
+ annotLineEndingButt, // Butt
+ annotLineEndingROpenArrow, // ROpenArrow
+ annotLineEndingRClosedArrow, // RClosedArrow
+ annotLineEndingSlash // Slash
+};
+
+enum AnnotExternalDataType {
+ annotExternalDataMarkupUnknown,
+ annotExternalDataMarkup3D // Markup3D
+};
+
+//------------------------------------------------------------------------
+// AnnotCoord
+//------------------------------------------------------------------------
+
+class AnnotCoord {
+public:
+
+ AnnotCoord() : x(0), y(0) { }
+ AnnotCoord(double _x, double _y) : x(_x), y(_y) { }
+
+ double getX() const { return x; }
+ double getY() const { return y; }
+
+protected:
+
+ double x, y;
+};
+
+//------------------------------------------------------------------------
+// AnnotPath
+//------------------------------------------------------------------------
+
+class AnnotPath {
+public:
+ AnnotPath();
+ AnnotPath(Array *array);
+ AnnotPath(AnnotCoord **coords, int coordLength);
+ ~AnnotPath();
+
+ double getX(int coord) const;
+ double getY(int coord) const;
+ AnnotCoord *getCoord(int coord) const;
+ int getCoordsLength() const { return coordsLength; }
+protected:
+ AnnotCoord **coords;
+ int coordsLength;
+
+ void parsePathArray(Array *array);
+};
+
+//------------------------------------------------------------------------
+// AnnotCalloutLine
+//------------------------------------------------------------------------
+
+class AnnotCalloutLine {
+public:
+
+ AnnotCalloutLine(double x1, double y1, double x2, double y2);
+ virtual ~AnnotCalloutLine() { }
+
+ double getX1() const { return coord1.getX(); }
+ double getY1() const { return coord1.getY(); }
+ double getX2() const { return coord2.getX(); }
+ double getY2() const { return coord2.getY(); }
+
+protected:
+
+ AnnotCoord coord1, coord2;
+};
+
+//------------------------------------------------------------------------
+// AnnotCalloutMultiLine
+//------------------------------------------------------------------------
+
+class AnnotCalloutMultiLine: public AnnotCalloutLine {
+public:
+
+ AnnotCalloutMultiLine(double x1, double y1, double x2, double y2,
+ double x3, double y3);
+
+ double getX3() const { return coord3.getX(); }
+ double getY3() const { return coord3.getY(); }
+
+protected:
+
+ AnnotCoord coord3;
+};
+
+//------------------------------------------------------------------------
+// AnnotBorderEffect
+//------------------------------------------------------------------------
+
+class AnnotBorderEffect {
+public:
+
+ enum AnnotBorderEffectType {
+ borderEffectNoEffect, // S
+ borderEffectCloudy // C
+ };
+
+ AnnotBorderEffect(Dict *dict);
+
+ AnnotBorderEffectType getEffectType() const { return effectType; }
+ double getIntensity() const { return intensity; }
+
+private:
+
+ AnnotBorderEffectType effectType; // S (Default S)
+ double intensity; // I (Default 0)
+};
+
+//------------------------------------------------------------------------
+// AnnotQuadrilateral
+//------------------------------------------------------------------------
+
+class AnnotQuadrilaterals {
+public:
+ class AnnotQuadrilateral {
+ public:
+ AnnotQuadrilateral(double x1, double y1, double x2, double y2, double x3,
+ double y3, double x4, double y4);
+
+ AnnotCoord coord1, coord2, coord3, coord4;
+ };
+
+ AnnotQuadrilaterals(Array *array, PDFRectangle *rect);
+ AnnotQuadrilaterals(AnnotQuadrilateral **quads, int quadsLength);
+ ~AnnotQuadrilaterals();
+
+ double getX1(int quadrilateral);
+ double getY1(int quadrilateral);
+ double getX2(int quadrilateral);
+ double getY2(int quadrilateral);
+ double getX3(int quadrilateral);
+ double getY3(int quadrilateral);
+ double getX4(int quadrilateral);
+ double getY4(int quadrilateral);
+ int getQuadrilateralsLength() const { return quadrilateralsLength; }
+protected:
+
+ AnnotQuadrilateral** quadrilaterals;
+ int quadrilateralsLength;
+};
+
+//------------------------------------------------------------------------
+// AnnotBorder
+//------------------------------------------------------------------------
+
+class AnnotBorder {
+public:
+ enum AnnotBorderType {
+ typeArray,
+ typeBS
+ };
+
+ enum AnnotBorderStyle {
+ borderSolid, // Solid
+ borderDashed, // Dashed
+ borderBeveled, // Beveled
+ borderInset, // Inset
+ borderUnderlined // Underlined
+ };
+
+ virtual ~AnnotBorder();
+
+ virtual void setWidth(double new_width) { width = new_width; }
+
+ virtual AnnotBorderType getType() const = 0;
+ virtual double getWidth() const { return width; }
+ virtual int getDashLength() const { return dashLength; }
+ virtual double *getDash() const { return dash; }
+ virtual AnnotBorderStyle getStyle() const { return style; }
+
+ virtual void writeToObject(XRef *xref, Object *obj1) const = 0;
+
+protected:
+ AnnotBorder();
+
+ GBool parseDashArray(Object *dashObj);
+
+ AnnotBorderType type;
+ double width;
+ static const int DASH_LIMIT = 10; // implementation note 82 in Appendix H.
+ int dashLength;
+ double *dash;
+ AnnotBorderStyle style;
+};
+
+//------------------------------------------------------------------------
+// AnnotBorderArray
+//------------------------------------------------------------------------
+
+class AnnotBorderArray: public AnnotBorder {
+public:
+ AnnotBorderArray();
+ AnnotBorderArray(Array *array);
+
+ void setHorizontalCorner(double hc) { horizontalCorner = hc; }
+ void setVerticalCorner(double vc) { verticalCorner = vc; }
+
+ double getHorizontalCorner() const { return horizontalCorner; }
+ double getVerticalCorner() const { return verticalCorner; }
+
+private:
+ virtual AnnotBorderType getType() const { return typeArray; }
+ virtual void writeToObject(XRef *xref, Object *obj1) const;
+
+ double horizontalCorner; // (Default 0)
+ double verticalCorner; // (Default 0)
+ // double width; // (Default 1) (inherited from AnnotBorder)
+};
+
+//------------------------------------------------------------------------
+// AnnotBorderBS
+//------------------------------------------------------------------------
+
+class AnnotBorderBS: public AnnotBorder {
+public:
+
+ AnnotBorderBS();
+ AnnotBorderBS(Dict *dict);
+
+private:
+ virtual AnnotBorderType getType() const { return typeBS; }
+ virtual void writeToObject(XRef *xref, Object *obj1) const;
+
+ const char *getStyleName() const;
+
+ // double width; // W (Default 1) (inherited from AnnotBorder)
+ // AnnotBorderStyle style; // S (Default S) (inherited from AnnotBorder)
+ // double *dash; // D (Default [3]) (inherited from AnnotBorder)
+};
+
+//------------------------------------------------------------------------
+// AnnotColor
+//------------------------------------------------------------------------
+
+class AnnotColor {
+public:
+
+ enum AnnotColorSpace {
+ colorTransparent = 0,
+ colorGray = 1,
+ colorRGB = 3,
+ colorCMYK = 4
+ };
+
+ AnnotColor();
+ AnnotColor(double gray);
+ AnnotColor(double r, double g, double b);
+ AnnotColor(double c, double m, double y, double k);
+ AnnotColor(Array *array, int adjust = 0);
+
+ void adjustColor(int adjust);
+
+ AnnotColorSpace getSpace() const { return (AnnotColorSpace) length; }
+ const double *getValues() const { return values; }
+
+ void writeToObject(XRef *xref, Object *dest) const;
+
+private:
+
+ double values[4];
+ int length;
+};
+
+//------------------------------------------------------------------------
+// AnnotIconFit
+//------------------------------------------------------------------------
+
+class AnnotIconFit {
+public:
+
+ enum AnnotIconFitScaleWhen {
+ scaleAlways, // A
+ scaleBigger, // B
+ scaleSmaller, // S
+ scaleNever // N
+ };
+
+ enum AnnotIconFitScale {
+ scaleAnamorphic, // A
+ scaleProportional // P
+ };
+
+ AnnotIconFit(Dict *dict);
+
+ AnnotIconFitScaleWhen getScaleWhen() { return scaleWhen; }
+ AnnotIconFitScale getScale() { return scale; }
+ double getLeft() { return left; }
+ double getBottom() { return bottom; }
+ bool getFullyBounds() { return fullyBounds; }
+
+protected:
+
+ AnnotIconFitScaleWhen scaleWhen; // SW (Default A)
+ AnnotIconFitScale scale; // S (Default P)
+ double left; // A (Default [0.5 0.5]
+ double bottom; // Only if scale is P
+ bool fullyBounds; // FB (Default false)
+};
+
+//------------------------------------------------------------------------
+// AnnotAppearance
+//------------------------------------------------------------------------
+
+class AnnotAppearance {
+public:
+
+ enum AnnotAppearanceType {
+ appearNormal,
+ appearRollover,
+ appearDown
+ };
+
+ AnnotAppearance(PDFDoc *docA, Object *dict);
+ ~AnnotAppearance();
+
+ // State is ignored if no subdictionary is present
+ void getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest);
+
+ // Access keys in normal appearance subdictionary (N)
+ GooString * getStateKey(int i);
+ int getNumStates();
+
+ // Removes all associated streams in the xref table. Caller is required to
+ // reset parent annotation's AP and AS after this call.
+ void removeAllStreams();
+
+ // Test if this AnnotAppearance references the specified stream
+ GBool referencesStream(Ref targetStreamRef);
+
+private:
+ static GBool referencesStream(Object *stateObj, Ref targetStreamRef);
+ void removeStream(Ref refToStream);
+ void removeStateStreams(Object *state);
+
+protected:
+ PDFDoc *doc;
+ XRef *xref; // the xref table for this PDF file
+ Object appearDict; // Annotation's AP
+};
+
+//------------------------------------------------------------------------
+// AnnotAppearanceCharacs
+//------------------------------------------------------------------------
+
+class AnnotAppearanceCharacs {
+public:
+
+ enum AnnotAppearanceCharacsTextPos {
+ captionNoIcon, // 0
+ captionNoCaption, // 1
+ captionBelow, // 2
+ captionAbove, // 3
+ captionRight, // 4
+ captionLeft, // 5
+ captionOverlaid // 6
+ };
+
+ AnnotAppearanceCharacs(Dict *dict);
+ ~AnnotAppearanceCharacs();
+
+ int getRotation() { return rotation; }
+ AnnotColor *getBorderColor() { return borderColor; }
+ AnnotColor *getBackColor() { return backColor; }
+ GooString *getNormalCaption() { return normalCaption; }
+ GooString *getRolloverCaption() { return rolloverCaption; }
+ GooString *getAlternateCaption() { return alternateCaption; }
+ AnnotIconFit *getIconFit() { return iconFit; }
+ AnnotAppearanceCharacsTextPos getPosition() { return position; }
+
+protected:
+
+ int rotation; // R (Default 0)
+ AnnotColor *borderColor; // BC
+ AnnotColor *backColor; // BG
+ GooString *normalCaption; // CA
+ GooString *rolloverCaption; // RC
+ GooString *alternateCaption; // AC
+ // I
+ // RI
+ // IX
+ AnnotIconFit *iconFit; // IF
+ AnnotAppearanceCharacsTextPos position; // TP (Default 0)
+};
+
+//------------------------------------------------------------------------
+// AnnotAppearanceBBox
+//------------------------------------------------------------------------
+
+class AnnotAppearanceBBox
+{
+public:
+ AnnotAppearanceBBox(PDFRectangle *init);
+
+ void setBorderWidth(double w) { borderWidth = w; }
+
+ // The following functions operate on coords relative to [origX origY]
+ void extendTo(double x, double y);
+ void getBBoxRect(double bbox[4]) const;
+
+ // Get boundaries in page coordinates
+ double getPageXMin() const;
+ double getPageYMin() const;
+ double getPageXMax() const;
+ double getPageYMax() const;
+
+private:
+ double origX, origY, borderWidth;
+ double minX, minY, maxX, maxY;
+};
+
+//------------------------------------------------------------------------
+// Annot
+//------------------------------------------------------------------------
+
+class Annot {
+ friend class Annots;
+ friend class Page;
+public:
+ enum AnnotFlag {
+ flagUnknown = 0x0000,
+ flagInvisible = 0x0001,
+ flagHidden = 0x0002,
+ flagPrint = 0x0004,
+ flagNoZoom = 0x0008,
+ flagNoRotate = 0x0010,
+ flagNoView = 0x0020,
+ flagReadOnly = 0x0040,
+ flagLocked = 0x0080,
+ flagToggleNoView = 0x0100,
+ flagLockedContents = 0x0200
+ };
+
+ enum AnnotSubtype {
+ typeUnknown, // 0
+ typeText, // Text 1
+ typeLink, // Link 2
+ typeFreeText, // FreeText 3
+ typeLine, // Line 4
+ typeSquare, // Square 5
+ typeCircle, // Circle 6
+ typePolygon, // Polygon 7
+ typePolyLine, // PolyLine 8
+ typeHighlight, // Highlight 9
+ typeUnderline, // Underline 10
+ typeSquiggly, // Squiggly 11
+ typeStrikeOut, // StrikeOut 12
+ typeStamp, // Stamp 13
+ typeCaret, // Caret 14
+ typeInk, // Ink 15
+ typePopup, // Popup 16
+ typeFileAttachment, // FileAttachment 17
+ typeSound, // Sound 18
+ typeMovie, // Movie 19
+ typeWidget, // Widget 20
+ typeScreen, // Screen 21
+ typePrinterMark, // PrinterMark 22
+ typeTrapNet, // TrapNet 23
+ typeWatermark, // Watermark 24
+ type3D, // 3D 25
+ typeRichMedia // RichMedia 26
+ };
+
+ /**
+ * Describes the additional actions of a screen or widget annotation.
+ */
+ enum AdditionalActionsType {
+ actionCursorEntering, ///< Performed when the cursor enters the annotation's active area
+ actionCursorLeaving, ///< Performed when the cursor exists the annotation's active area
+ actionMousePressed, ///< Performed when the mouse button is pressed inside the annotation's active area
+ actionMouseReleased, ///< Performed when the mouse button is released inside the annotation's active area
+ actionFocusIn, ///< Performed when the annotation receives the input focus
+ actionFocusOut, ///< Performed when the annotation loses the input focus
+ actionPageOpening, ///< Performed when the page containing the annotation is opened
+ actionPageClosing, ///< Performed when the page containing the annotation is closed
+ actionPageVisible, ///< Performed when the page containing the annotation becomes visible
+ actionPageInvisible ///< Performed when the page containing the annotation becomes invisible
+ };
+
+ enum FormAdditionalActionsType {
+ actionFieldModified, ///< Performed when the when the user modifies the field
+ actionFormatField, ///< Performed before the field is formatted to display its value
+ actionValidateField, ///< Performed when the field value changes
+ actionCalculateField, ///< Performed when the field needs to be recalculated
+ };
+
+ Annot(PDFDoc *docA, PDFRectangle *rectA);
+ Annot(PDFDoc *docA, Dict *dict);
+ Annot(PDFDoc *docA, Dict *dict, Object *obj);
+ GBool isOk() { return ok; }
+
+ void incRefCnt();
+ void decRefCnt();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+ // Get the resource dict of the appearance stream
+ virtual Object *getAppearanceResDict(Object *dest);
+
+ GBool match(Ref *refA)
+ { return ref.num == refA->num && ref.gen == refA->gen; }
+
+ double getXMin();
+ double getYMin();
+ double getXMax();
+ double getYMax();
+
+ double getFontSize() { return fontSize; }
+
+ void setRect(PDFRectangle *rect);
+ void setRect(double x1, double y1, double x2, double y2);
+
+ // Sets the annot contents to new_content
+ // new_content should never be NULL
+ virtual void setContents(GooString *new_content);
+ void setName(GooString *new_name);
+ void setModified(GooString *new_date);
+ void setFlags(Guint new_flags);
+
+ void setBorder(AnnotBorder *new_border); // Takes ownership
+
+ // The annotation takes the ownership of
+ // new_color.
+ void setColor(AnnotColor *new_color);
+
+ void setAppearanceState(const char *state);
+
+ // getters
+ PDFDoc *getDoc() const { return doc; }
+ XRef *getXRef() const { return xref; }
+ GBool getHasRef() const { return hasRef; }
+ Ref getRef() const { return ref; }
+ AnnotSubtype getType() const { return type; }
+ PDFRectangle *getRect() const { return rect; }
+ void getRect(double *x1, double *y1, double *x2, double *y2) const;
+ GooString *getContents() const { return contents; }
+ int getPageNum() const { return page; }
+ GooString *getName() const { return name; }
+ GooString *getModified() const { return modified; }
+ Guint getFlags() const { return flags; }
+ AnnotAppearance *getAppearStreams() const { return appearStreams; }
+ GooString *getAppearState() const { return appearState; }
+ AnnotBorder *getBorder() const { return border; }
+ AnnotColor *getColor() const { return color; }
+ int getTreeKey() const { return treeKey; }
+
+ int getId() { return ref.num; }
+
+ // Check if point is inside the annot rectangle.
+ GBool inRect(double x, double y) const;
+
+private:
+ void readArrayNum(Object *pdfArray, int key, double *value);
+ // write vStr[i:j[ in appearBuf
+
+ void initialize (PDFDoc *docA, Dict *dict);
+ void setPage (int new_page, GBool updateP); // Called by Page::addAnnot and Annots ctor
+
+
+protected:
+ virtual ~Annot();
+ virtual void removeReferencedObjects(); // Called by Page::removeAnnot
+ void setColor(AnnotColor *color, GBool fill);
+ void setLineStyleForBorder(AnnotBorder *border);
+ void drawCircle(double cx, double cy, double r, GBool fill);
+ void drawCircleTopLeft(double cx, double cy, double r);
+ void drawCircleBottomRight(double cx, double cy, double r);
+ void layoutText(GooString *text, GooString *outBuf, int *i, GfxFont *font,
+ double *width, double widthLimit, int *charCount,
+ GBool noReencode);
+ void writeString(GooString *str, GooString *appearBuf);
+ void createForm(double *bbox, GBool transparencyGroup, Object *resDict, Object *aStream);
+ void createResourcesDict(const char *formName, Object *formStream, const char *stateName,
+ double opacity, const char *blendMode, Object *resDict);
+ GBool isVisible(GBool printing);
+ int getRotation() const;
+
+ // Updates the field key of the annotation dictionary
+ // and sets M to the current time
+ void update(const char *key, Object *value);
+
+ // Delete appearance streams and reset appearance state
+ void invalidateAppearance();
+
+ int refCnt;
+
+ Object annotObj;
+
+ // required data
+ AnnotSubtype type; // Annotation type
+ PDFRectangle *rect; // Rect
+
+ // optional data
+ GooString *contents; // Contents
+ int page; // P
+ GooString *name; // NM
+ GooString *modified; // M
+ Guint flags; // F (must be a 32 bit unsigned int)
+ AnnotAppearance *appearStreams; // AP
+ Object appearance; // a reference to the Form XObject stream
+ // for the normal appearance
+ AnnotAppearanceBBox *appearBBox; // BBox of generated appearance
+ GooString *appearState; // AS
+ int treeKey; // Struct Parent;
+ Object oc; // OC
+
+ PDFDoc *doc;
+ XRef *xref; // the xref table for this PDF file
+ Ref ref; // object ref identifying this annotation
+ GooString *appearBuf;
+ AnnotBorder *border; // Border, BS
+ AnnotColor *color; // C
+ double fontSize;
+ GBool ok;
+
+ bool hasRef;
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+//------------------------------------------------------------------------
+// AnnotPopup
+//------------------------------------------------------------------------
+
+class AnnotPopup: public Annot {
+public:
+ AnnotPopup(PDFDoc *docA, PDFRectangle *rect);
+ AnnotPopup(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotPopup();
+
+ Object *getParent(Object *obj) { return parent.fetch (xref, obj); }
+ Object *getParentNF() { return &parent; }
+ void setParent(Object *parentA);
+ void setParent(Annot *parentA);
+ GBool getOpen() const { return open; }
+ void setOpen(GBool openA);
+
+protected:
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ Object parent; // Parent
+ GBool open; // Open
+};
+
+//------------------------------------------------------------------------
+// AnnotMarkup
+//------------------------------------------------------------------------
+
+class AnnotMarkup: public Annot {
+public:
+ enum AnnotMarkupReplyType {
+ replyTypeR, // R
+ replyTypeGroup // Group
+ };
+
+ AnnotMarkup(PDFDoc *docA, PDFRectangle *rect);
+ AnnotMarkup(PDFDoc *docA, Dict *dict, Object *obj);
+ virtual ~AnnotMarkup();
+
+ // getters
+ GooString *getLabel() const { return label; }
+ AnnotPopup *getPopup() const { return popup; }
+ double getOpacity() const { return opacity; }
+ // getRC
+ GooString *getDate() const { return date; }
+ int getInReplyToID() const { return inReplyTo.num; }
+ GooString *getSubject() const { return subject; }
+ AnnotMarkupReplyType getReplyTo() const { return replyTo; }
+ AnnotExternalDataType getExData() const { return exData; }
+
+ // The annotation takes the ownership of new_popup
+ void setPopup(AnnotPopup *new_popup);
+ void setLabel(GooString *new_label);
+ void setOpacity(double opacityA);
+ void setDate(GooString *new_date);
+
+protected:
+ virtual void removeReferencedObjects();
+
+ GooString *label; // T (Default autor)
+ AnnotPopup *popup; // Popup
+ double opacity; // CA (Default 1.0)
+ // RC
+ GooString *date; // CreationDate
+ Ref inReplyTo; // IRT
+ GooString *subject; // Subj
+ AnnotMarkupReplyType replyTo; // RT (Default R)
+ // this object is overrided by the custom intent fields defined in some
+ // annotation types.
+ //GooString *intent; // IT
+ AnnotExternalDataType exData; // ExData
+
+private:
+ void initialize(PDFDoc *docA, Dict *dict, Object *obj);
+};
+
+//------------------------------------------------------------------------
+// AnnotText
+//------------------------------------------------------------------------
+
+class AnnotText: public AnnotMarkup {
+public:
+ enum AnnotTextState {
+ stateUnknown,
+ // Marked state model
+ stateMarked, // Marked
+ stateUnmarked, // Unmarked
+ // Review state model
+ stateAccepted, // Accepted
+ stateRejected, // Rejected
+ stateCancelled, // Cancelled
+ stateCompleted, // Completed
+ stateNone // None
+ };
+
+ AnnotText(PDFDoc *docA, PDFRectangle *rect);
+ AnnotText(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotText();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ // getters
+ GBool getOpen() const { return open; }
+ GooString *getIcon() const { return icon; }
+ AnnotTextState getState() const { return state; }
+
+ void setOpen(GBool openA);
+ void setIcon(GooString *new_icon);
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ GBool open; // Open (Default false)
+ GooString *icon; // Name (Default Note)
+ AnnotTextState state; // State (Default Umarked if
+ // StateModel Marked
+ // None if StareModel Review)
+};
+
+//------------------------------------------------------------------------
+// AnnotMovie
+//------------------------------------------------------------------------
+
+
+
+class AnnotMovie: public Annot {
+ public:
+ AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA);
+ AnnotMovie(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotMovie();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ GooString* getTitle() { return title; }
+ Movie* getMovie() { return movie; }
+
+ private:
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ GooString* title; // T
+ Movie* movie; // Movie + A
+};
+
+
+//------------------------------------------------------------------------
+// AnnotScreen
+//------------------------------------------------------------------------
+
+class AnnotScreen: public Annot {
+ public:
+
+ AnnotScreen(PDFDoc *docA, PDFRectangle *rect);
+ AnnotScreen(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotScreen();
+
+ GooString* getTitle() { return title; }
+
+ AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
+ LinkAction* getAction() { return action; }
+ LinkAction *getAdditionalAction(AdditionalActionsType type);
+
+ private:
+ void initialize(PDFDoc *docA, Dict *dict);
+
+
+ GooString* title; // T
+
+ AnnotAppearanceCharacs* appearCharacs; // MK
+
+ LinkAction *action; // A
+ Object additionalActions; // AA
+};
+
+//------------------------------------------------------------------------
+// AnnotLink
+//------------------------------------------------------------------------
+
+class AnnotLink: public Annot {
+public:
+
+ enum AnnotLinkEffect {
+ effectNone, // N
+ effectInvert, // I
+ effectOutline, // O
+ effectPush // P
+ };
+
+ AnnotLink(PDFDoc *docA, PDFRectangle *rect);
+ AnnotLink(PDFDoc *docA, Dict *dict, Object *obj);
+ virtual ~AnnotLink();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ // getters
+ LinkAction *getAction() const { return action; }
+ AnnotLinkEffect getLinkEffect() const { return linkEffect; }
+ Dict *getUriAction() const { return uriAction; }
+ AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals; }
+
+protected:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ LinkAction *action; // A, Dest
+ AnnotLinkEffect linkEffect; // H (Default I)
+ Dict *uriAction; // PA
+
+ AnnotQuadrilaterals *quadrilaterals; // QuadPoints
+};
+
+//------------------------------------------------------------------------
+// AnnotFreeText
+//------------------------------------------------------------------------
+
+class AnnotFreeText: public AnnotMarkup {
+public:
+
+ enum AnnotFreeTextQuadding {
+ quaddingLeftJustified, // 0
+ quaddingCentered, // 1
+ quaddingRightJustified // 2
+ };
+
+ enum AnnotFreeTextIntent {
+ intentFreeText, // FreeText
+ intentFreeTextCallout, // FreeTextCallout
+ intentFreeTextTypeWriter // FreeTextTypeWriter
+ };
+
+ AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da);
+ AnnotFreeText(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotFreeText();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+ virtual Object *getAppearanceResDict(Object *dest);
+ virtual void setContents(GooString *new_content);
+
+ void setAppearanceString(GooString *new_string);
+ void setQuadding(AnnotFreeTextQuadding new_quadding);
+ void setStyleString(GooString *new_string);
+ void setCalloutLine(AnnotCalloutLine *line);
+ void setIntent(AnnotFreeTextIntent new_intent);
+
+ // getters
+ GooString *getAppearanceString() const { return appearanceString; }
+ AnnotFreeTextQuadding getQuadding() const { return quadding; }
+ // return rc
+ GooString *getStyleString() const { return styleString; }
+ AnnotCalloutLine *getCalloutLine() const { return calloutLine; }
+ AnnotFreeTextIntent getIntent() const { return intent; }
+ AnnotBorderEffect *getBorderEffect() const { return borderEffect; }
+ PDFRectangle *getRectangle() const { return rectangle; }
+ AnnotLineEndingStyle getEndStyle() const { return endStyle; }
+
+protected:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+ static void parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor);
+ void generateFreeTextAppearance();
+
+ // required
+ GooString *appearanceString; // DA
+
+ // optional
+ AnnotFreeTextQuadding quadding; // Q (Default 0)
+ // RC
+ GooString *styleString; // DS
+ AnnotCalloutLine *calloutLine; // CL
+ AnnotFreeTextIntent intent; // IT
+ AnnotBorderEffect *borderEffect; // BE
+ PDFRectangle *rectangle; // RD
+ // inherited from Annot
+ // AnnotBorderBS border; // BS
+ AnnotLineEndingStyle endStyle; // LE (Default None)
+};
+
+//------------------------------------------------------------------------
+// AnnotLine
+//------------------------------------------------------------------------
+
+class AnnotLine: public AnnotMarkup {
+public:
+
+ enum AnnotLineIntent {
+ intentLineArrow, // LineArrow
+ intentLineDimension // LineDimension
+ };
+
+ enum AnnotLineCaptionPos {
+ captionPosInline, // Inline
+ captionPosTop // Top
+ };
+
+ AnnotLine(PDFDoc *docA, PDFRectangle *rect);
+ AnnotLine(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotLine();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+ virtual Object *getAppearanceResDict(Object *dest);
+ virtual void setContents(GooString *new_content);
+
+ void setVertices(double x1, double y1, double x2, double y2);
+ void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end);
+ void setInteriorColor(AnnotColor *new_color);
+ void setLeaderLineLength(double len);
+ void setLeaderLineExtension(double len);
+ void setCaption(bool new_cap);
+ void setIntent(AnnotLineIntent new_intent);
+
+ // getters
+ AnnotLineEndingStyle getStartStyle() const { return startStyle; }
+ AnnotLineEndingStyle getEndStyle() const { return endStyle; }
+ AnnotColor *getInteriorColor() const { return interiorColor; }
+ double getLeaderLineLength() const { return leaderLineLength; }
+ double getLeaderLineExtension() const { return leaderLineExtension; }
+ bool getCaption() const { return caption; }
+ AnnotLineIntent getIntent() const { return intent; }
+ double getLeaderLineOffset() const { return leaderLineOffset; }
+ AnnotLineCaptionPos getCaptionPos() const { return captionPos; }
+ Dict *getMeasure() const { return measure; }
+ double getCaptionTextHorizontal() const { return captionTextHorizontal; }
+ double getCaptionTextVertical() const { return captionTextVertical; }
+ double getX1() const { return coord1->getX(); }
+ double getY1() const { return coord1->getY(); }
+ double getX2() const { return coord2->getX(); }
+ double getY2() const { return coord2->getY(); }
+
+protected:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+ void generateLineAppearance();
+
+ // required
+ AnnotCoord *coord1, *coord2;
+
+ // optional
+ // inherited from Annot
+ // AnnotBorderBS border; // BS
+ AnnotLineEndingStyle startStyle; // LE (Default [/None /None])
+ AnnotLineEndingStyle endStyle; //
+ AnnotColor *interiorColor; // IC
+ double leaderLineLength; // LL (Default 0)
+ double leaderLineExtension; // LLE (Default 0)
+ bool caption; // Cap (Default false)
+ AnnotLineIntent intent; // IT
+ double leaderLineOffset; // LLO
+ AnnotLineCaptionPos captionPos; // CP (Default Inline)
+ Dict *measure; // Measure
+ double captionTextHorizontal; // CO (Default [0, 0])
+ double captionTextVertical; //
+};
+
+//------------------------------------------------------------------------
+// AnnotTextMarkup
+//------------------------------------------------------------------------
+
+class AnnotTextMarkup: public AnnotMarkup {
+public:
+
+ AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
+ AnnotTextMarkup(PDFDoc *docA, Dict *dict, Object *obj);
+ virtual ~AnnotTextMarkup();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ // typeHighlight, typeUnderline, typeSquiggly or typeStrikeOut
+ void setType(AnnotSubtype new_type);
+
+ void setQuadrilaterals(AnnotQuadrilaterals *quadPoints);
+
+ AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals; }
+
+protected:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ AnnotQuadrilaterals *quadrilaterals; // QuadPoints
+};
+
+//------------------------------------------------------------------------
+// AnnotStamp
+//------------------------------------------------------------------------
+
+class AnnotStamp: public AnnotMarkup {
+public:
+
+ AnnotStamp(PDFDoc *docA, PDFRectangle *rect);
+ AnnotStamp(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotStamp();
+
+ void setIcon(GooString *new_icon);
+
+ // getters
+ GooString *getIcon() const { return icon; }
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ GooString *icon; // Name (Default Draft)
+};
+
+//------------------------------------------------------------------------
+// AnnotGeometry
+//------------------------------------------------------------------------
+
+class AnnotGeometry: public AnnotMarkup {
+public:
+
+ AnnotGeometry(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
+ AnnotGeometry(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotGeometry();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ void setType(AnnotSubtype new_type); // typeSquare or typeCircle
+ void setInteriorColor(AnnotColor *new_color);
+
+ // getters
+ AnnotColor *getInteriorColor() const { return interiorColor; }
+ AnnotBorderEffect *getBorderEffect() const { return borderEffect; }
+ PDFRectangle *getGeometryRect() const { return geometryRect; }
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ AnnotColor *interiorColor; // IC
+ AnnotBorderEffect *borderEffect; // BE
+ PDFRectangle *geometryRect; // RD (combined with Rect)
+};
+
+//------------------------------------------------------------------------
+// AnnotPolygon
+//------------------------------------------------------------------------
+
+class AnnotPolygon: public AnnotMarkup {
+public:
+
+ enum AnnotPolygonIntent {
+ polygonCloud, // PolygonCloud
+ polylineDimension, // PolyLineDimension
+ polygonDimension // PolygonDimension
+ };
+
+ AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
+ AnnotPolygon(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotPolygon();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ void setType(AnnotSubtype new_type); // typePolygon or typePolyLine
+ void setVertices(AnnotPath *path);
+ void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end);
+ void setInteriorColor(AnnotColor *new_color);
+ void setIntent(AnnotPolygonIntent new_intent);
+
+ // getters
+ AnnotPath *getVertices() const { return vertices; }
+ AnnotLineEndingStyle getStartStyle() const { return startStyle; }
+ AnnotLineEndingStyle getEndStyle() const { return endStyle; }
+ AnnotColor *getInteriorColor() const { return interiorColor; }
+ AnnotBorderEffect *getBorderEffect() const { return borderEffect; }
+ AnnotPolygonIntent getIntent() const { return intent; }
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ // required
+ AnnotPath *vertices; // Vertices
+
+ // optional
+ AnnotLineEndingStyle startStyle; // LE (Default [/None /None])
+ AnnotLineEndingStyle endStyle; //
+ // inherited from Annot
+ // AnnotBorderBS border; // BS
+ AnnotColor *interiorColor; // IC
+ AnnotBorderEffect *borderEffect; // BE
+ AnnotPolygonIntent intent; // IT
+ // Measure
+};
+
+//------------------------------------------------------------------------
+// AnnotCaret
+//------------------------------------------------------------------------
+
+class AnnotCaret: public AnnotMarkup {
+public:
+
+ enum AnnotCaretSymbol {
+ symbolNone, // None
+ symbolP // P
+ };
+
+ AnnotCaret(PDFDoc *docA, PDFRectangle *rect);
+ AnnotCaret(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotCaret();
+
+ void setSymbol(AnnotCaretSymbol new_symbol);
+
+ // getters
+ AnnotCaretSymbol getSymbol() const { return symbol; }
+ PDFRectangle *getCaretRect() const { return caretRect; }
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ AnnotCaretSymbol symbol; // Sy (Default None)
+ PDFRectangle *caretRect; // RD (combined with Rect)
+};
+
+//------------------------------------------------------------------------
+// AnnotInk
+//------------------------------------------------------------------------
+
+class AnnotInk: public AnnotMarkup {
+public:
+
+ AnnotInk(PDFDoc *docA, PDFRectangle *rect);
+ AnnotInk(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotInk();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ void setInkList(AnnotPath **paths, int n_paths);
+
+ // getters
+ AnnotPath **getInkList() const { return inkList; }
+ int getInkListLength() const { return inkListLength; }
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+ void writeInkList(AnnotPath **paths, int n_paths, Array *dest_array);
+ void parseInkList(Array *src_array);
+ void freeInkList();
+
+ // required
+ AnnotPath **inkList; // InkList
+ int inkListLength;
+
+ // optional
+ // inherited from Annot
+ // AnnotBorderBS border; // BS
+};
+
+//------------------------------------------------------------------------
+// AnnotFileAttachment
+//------------------------------------------------------------------------
+
+class AnnotFileAttachment: public AnnotMarkup {
+public:
+
+ AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooString *filename);
+ AnnotFileAttachment(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotFileAttachment();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ // getters
+ Object *getFile() { return &file; }
+ GooString *getName() const { return name; }
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ // required
+ Object file; // FS
+
+ // optional
+ GooString *name; // Name
+};
+
+//------------------------------------------------------------------------
+// AnnotSound
+//------------------------------------------------------------------------
+
+class AnnotSound: public AnnotMarkup {
+public:
+
+ AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA);
+ AnnotSound(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotSound();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ // getters
+ Sound *getSound() { return sound; }
+ GooString *getName() const { return name; }
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ // required
+ Sound *sound; // Sound
+
+ // optional
+ GooString *name; // Name
+};
+
+//------------------------------------------------------------------------
+// AnnotWidget
+//------------------------------------------------------------------------
+
+class AnnotWidget: public Annot {
+public:
+
+ enum AnnotWidgetHighlightMode {
+ highlightModeNone, // N
+ highlightModeInvert, // I
+ highlightModeOutline, // O
+ highlightModePush // P,T
+ };
+
+ AnnotWidget(PDFDoc *docA, Dict *dict, Object *obj);
+ AnnotWidget(PDFDoc *docA, Dict *dict, Object *obj, FormField *fieldA);
+ virtual ~AnnotWidget();
+
+ virtual void draw(Gfx *gfx, GBool printing);
+
+ void drawBorder();
+ void drawFormFieldButton(GfxResources *resources, GooString *da);
+ void drawFormFieldText(GfxResources *resources, GooString *da);
+ void drawFormFieldChoice(GfxResources *resources, GooString *da);
+ void generateFieldAppearance ();
+ void updateAppearanceStream ();
+
+ AnnotWidgetHighlightMode getMode() { return mode; }
+ AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
+ LinkAction *getAction() { return action; }
+ LinkAction *getAdditionalAction(AdditionalActionsType type);
+ LinkAction *getFormAdditionalAction(FormAdditionalActionsType type);
+ Dict *getParent() { return parent; }
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ void drawText(GooString *text, GooString *da, GfxResources *resources,
+ GBool multiline, int comb, int quadding,
+ GBool txField, GBool forceZapfDingbats,
+ GBool password=false);
+ void drawListBox(FormFieldChoice *fieldChoice,
+ GooString *da, GfxResources *resources, int quadding);
+
+ Form *form;
+ FormField *field; // FormField object for this annotation
+ AnnotWidgetHighlightMode mode; // H (Default I)
+ AnnotAppearanceCharacs *appearCharacs; // MK
+ LinkAction *action; // A
+ Object additionalActions; // AA
+ // inherited from Annot
+ // AnnotBorderBS border; // BS
+ Dict *parent; // Parent
+ GBool addDingbatsResource;
+ Ref updatedAppearanceStream; // {-1,-1} if updateAppearanceStream has never been called
+};
+
+//------------------------------------------------------------------------
+// Annot3D
+//------------------------------------------------------------------------
+
+class Annot3D: public Annot {
+ class Activation {
+ public:
+ enum ActivationATrigger {
+ aTriggerUnknown,
+ aTriggerPageOpened, // PO
+ aTriggerPageVisible, // PV
+ aTriggerUserAction // XA
+ };
+
+ enum ActivationAState {
+ aStateUnknown,
+ aStateEnabled, // I
+ aStateDisabled // L
+ };
+
+ enum ActivationDTrigger {
+ dTriggerUnknown,
+ dTriggerPageClosed, // PC
+ dTriggerPageInvisible, // PI
+ dTriggerUserAction // XD
+ };
+
+ enum ActivationDState {
+ dStateUnknown,
+ dStateUninstantiaded, // U
+ dStateInstantiated, // I
+ dStateLive // L
+ };
+
+ Activation(Dict *dict);
+ private:
+
+ ActivationATrigger aTrigger; // A (Default XA)
+ ActivationAState aState; // AIS (Default L)
+ ActivationDTrigger dTrigger; // D (Default PI)
+ ActivationDState dState; // DIS (Default U)
+ GBool displayToolbar; // TB (Default true)
+ GBool displayNavigation; // NP (Default false);
+ };
+public:
+
+ Annot3D(PDFDoc *docA, PDFRectangle *rect);
+ Annot3D(PDFDoc *docA, Dict *dict, Object *obj);
+ ~Annot3D();
+
+ // getters
+
+private:
+
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ Activation *activation; // 3DA
+};
+
+//------------------------------------------------------------------------
+// AnnotRichMedia
+//------------------------------------------------------------------------
+
+class AnnotRichMedia: public Annot {
+public:
+ class Params {
+ public:
+ Params(Dict *dict);
+ ~Params();
+
+ GooString* getFlashVars() const;
+
+ private:
+ // optional
+ GooString *flashVars; // FlashVars
+ };
+
+ class Instance {
+ public:
+ enum Type {
+ type3D, // 3D
+ typeFlash, // Flash
+ typeSound, // Sound
+ typeVideo // Video
+ };
+
+ Instance(Dict *dict);
+ ~Instance();
+
+ Type getType() const;
+ Params* getParams() const;
+
+ private:
+ // optional
+ Type type; // Subtype
+ Params *params; // Params
+ };
+
+ class Configuration {
+ public:
+ enum Type {
+ type3D, // 3D
+ typeFlash, // Flash
+ typeSound, // Sound
+ typeVideo // Video
+ };
+
+ Configuration(Dict *dict);
+ ~Configuration();
+
+ Type getType() const;
+ GooString* getName() const;
+ int getInstancesCount() const;
+ Instance* getInstance(int index) const;
+
+ private:
+ // optional
+ Type type; // Subtype
+ GooString *name; // Name
+ Instance **instances; // Instances
+ int nInstances;
+ };
+
+ class Content;
+
+ class Asset {
+ public:
+ Asset();
+ ~Asset();
+
+ GooString* getName() const;
+ Object* getFileSpec() const;
+
+ private:
+ friend class AnnotRichMedia::Content;
+
+ GooString *name;
+ Object fileSpec;
+ };
+
+ class Content {
+ public:
+ Content(Dict *dict);
+ ~Content();
+
+ int getConfigurationsCount() const;
+ Configuration* getConfiguration(int index) const;
+
+ int getAssetsCount() const;
+ Asset* getAsset(int index) const;
+
+ private:
+ // optional
+ Configuration **configurations; // Configurations
+ int nConfigurations;
+
+ Asset **assets; // Assets
+ int nAssets;
+ };
+
+ class Activation {
+ public:
+ enum Condition {
+ conditionPageOpened, // PO
+ conditionPageVisible, // PV
+ conditionUserAction // XA
+ };
+
+ Activation(Dict *dict);
+
+ Condition getCondition() const;
+
+ private:
+ // optional
+ Condition condition;
+ };
+
+ class Deactivation {
+ public:
+ enum Condition {
+ conditionPageClosed, // PC
+ conditionPageInvisible, // PI
+ conditionUserAction // XD
+ };
+
+ Deactivation(Dict *dict);
+
+ Condition getCondition() const;
+
+ private:
+ // optional
+ Condition condition;
+ };
+
+ class Settings {
+ public:
+ Settings(Dict *dict);
+ ~Settings();
+
+ Activation* getActivation() const;
+ Deactivation* getDeactivation() const;
+
+ private:
+ // optional
+ Activation *activation;
+ Deactivation *deactivation;
+ };
+
+ AnnotRichMedia(PDFDoc *docA, PDFRectangle *rect);
+ AnnotRichMedia(PDFDoc *docA, Dict *dict, Object *obj);
+ ~AnnotRichMedia();
+
+ Content* getContent() const;
+
+ Settings* getSettings() const;
+
+private:
+ void initialize(PDFDoc *docA, Dict *dict);
+
+ // required
+ Content *content; // RichMediaContent
+
+ // optional
+ Settings *settings; // RichMediaSettings
+};
+
+
+//------------------------------------------------------------------------
+// Annots
+//------------------------------------------------------------------------
+
+class Annots {
+public:
+
+ // Build a list of Annot objects and call setPage on them
+ Annots(PDFDoc *docA, int page, Object *annotsObj);
+
+ ~Annots();
+
+ // Iterate through list of annotations.
+ int getNumAnnots() { return nAnnots; }
+ Annot *getAnnot(int i) { return annots[i]; }
+ void appendAnnot(Annot *annot);
+ GBool removeAnnot(Annot *annot);
+
+private:
+ Annot* createAnnot(Dict* dict, Object *obj);
+ Annot *findAnnot(Ref *ref);
+
+ PDFDoc *doc;
+ Annot **annots;
+ int nAnnots;
+ int size;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Array.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Array.cc
new file mode 100644
index 00000000000..230c3287683
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Array.cc
@@ -0,0 +1,152 @@
+//========================================================================
+//
+// Array.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include "goo/gmem.h"
+#include "Object.h"
+#include "Array.h"
+
+#if MULTITHREADED
+# define arrayLocker() MutexLocker locker(&mutex)
+#else
+# define arrayLocker()
+#endif
+//------------------------------------------------------------------------
+// Array
+//------------------------------------------------------------------------
+
+Array::Array(XRef *xrefA) {
+ xref = xrefA;
+ elems = NULL;
+ size = length = 0;
+ ref = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+Array::~Array() {
+ int i;
+
+ for (i = 0; i < length; ++i)
+ elems[i].free();
+ gfree(elems);
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+Object *Array::copy(XRef *xrefA, Object *obj) {
+ arrayLocker();
+ obj->initArray(xrefA);
+ for (int i = 0; i < length; ++i) {
+ Object obj1;
+ obj->arrayAdd(elems[i].copy(&obj1));
+ }
+ return obj;
+}
+
+int Array::incRef() {
+ arrayLocker();
+ ++ref;
+ return ref;
+}
+
+int Array::decRef() {
+ arrayLocker();
+ --ref;
+ return ref;
+}
+
+void Array::add(Object *elem) {
+ arrayLocker();
+ if (length == size) {
+ if (length == 0) {
+ size = 8;
+ } else {
+ size *= 2;
+ }
+ elems = (Object *)greallocn(elems, size, sizeof(Object));
+ }
+ elems[length] = *elem;
+ ++length;
+}
+
+void Array::remove(int i) {
+ arrayLocker();
+ if (i < 0 || i >= length) {
+#ifdef DEBUG_MEM
+ abort();
+#else
+ return;
+#endif
+ }
+ --length;
+ memmove( elems + i, elems + i + 1, sizeof(elems[0]) * (length - i) );
+}
+
+Object *Array::get(int i, Object *obj, int recursion) {
+ if (i < 0 || i >= length) {
+#ifdef DEBUG_MEM
+ abort();
+#else
+ return obj->initNull();
+#endif
+ }
+ return elems[i].fetch(xref, obj, recursion);
+}
+
+Object *Array::getNF(int i, Object *obj) {
+ if (i < 0 || i >= length) {
+#ifdef DEBUG_MEM
+ abort();
+#else
+ return obj->initNull();
+#endif
+ }
+ return elems[i].copy(obj);
+}
+
+GBool Array::getString(int i, GooString *string)
+{
+ Object obj;
+
+ if (getNF(i, &obj)->isString()) {
+ string->clear();
+ string->append(obj.getString());
+ obj.free();
+ return gTrue;
+ } else {
+ obj.free();
+ return gFalse;
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Array.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Array.h
new file mode 100644
index 00000000000..e78e399baf2
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Array.h
@@ -0,0 +1,84 @@
+//========================================================================
+//
+// Array.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "Object.h"
+#include "goo/GooMutex.h"
+
+class XRef;
+
+//------------------------------------------------------------------------
+// Array
+//------------------------------------------------------------------------
+
+class Array {
+public:
+
+ // Constructor.
+ Array(XRef *xrefA);
+
+ // Destructor.
+ ~Array();
+
+ // Reference counting.
+ int incRef();
+ int decRef();
+
+ // Get number of elements.
+ int getLength() { return length; }
+
+ // Copy array with new xref
+ Object *copy(XRef *xrefA, Object *obj);
+
+ // Add an element.
+ void add(Object *elem);
+
+ // Remove an element by position
+ void remove(int i);
+
+ // Accessors.
+ Object *get(int i, Object *obj, int resursion = 0);
+ Object *getNF(int i, Object *obj);
+ GBool getString(int i, GooString *string);
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Object *elems; // array of elements
+ int size; // size of <elems> array
+ int length; // number of elements in array
+ int ref; // reference count
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFont.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFont.cc
new file mode 100644
index 00000000000..20a297d6135
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFont.cc
@@ -0,0 +1,65 @@
+//========================================================================
+//
+// BuiltinFont.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "FontEncodingTables.h"
+#include "BuiltinFont.h"
+
+//------------------------------------------------------------------------
+
+BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) {
+ int i, h;
+
+ size = sizeA;
+ tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *));
+ for (i = 0; i < size; ++i) {
+ tab[i] = NULL;
+ }
+ for (i = 0; i < sizeA; ++i) {
+ h = hash(widths[i].name);
+ widths[i].next = tab[h];
+ tab[h] = &widths[i];
+ }
+}
+
+BuiltinFontWidths::~BuiltinFontWidths() {
+ gfree(tab);
+}
+
+GBool BuiltinFontWidths::getWidth(const char *name, Gushort *width) {
+ int h;
+ BuiltinFontWidth *p;
+
+ h = hash(name);
+ for (p = tab[h]; p; p = p->next) {
+ if (!strcmp(p->name, name)) {
+ *width = p->width;
+ return gTrue;
+ }
+ }
+ return gFalse;
+}
+
+int BuiltinFontWidths::hash(const char *name) {
+ const char *p;
+ unsigned int h;
+
+ h = 0;
+ for (p = name; *p; ++p) {
+ h = 17 * h + (int)(*p & 0xff);
+ }
+ return (int)(h % size);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFont.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFont.h
new file mode 100644
index 00000000000..bbdd0558e9f
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFont.h
@@ -0,0 +1,55 @@
+//========================================================================
+//
+// BuiltinFont.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef BUILTINFONT_H
+#define BUILTINFONT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+
+struct BuiltinFont;
+class BuiltinFontWidths;
+
+//------------------------------------------------------------------------
+
+struct BuiltinFont {
+ const char *name;
+ const char **defaultBaseEnc;
+ short ascent;
+ short descent;
+ short bbox[4];
+ BuiltinFontWidths *widths;
+};
+
+//------------------------------------------------------------------------
+
+struct BuiltinFontWidth {
+ const char *name;
+ Gushort width;
+ BuiltinFontWidth *next;
+};
+
+class BuiltinFontWidths {
+public:
+
+ BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA);
+ ~BuiltinFontWidths();
+ GBool getWidth(const char *name, Gushort *width);
+
+private:
+
+ int hash(const char *name);
+
+ BuiltinFontWidth **tab;
+ int size;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFontTables.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFontTables.cc
new file mode 100644
index 00000000000..5115b7bcf13
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFontTables.cc
@@ -0,0 +1,4284 @@
+//========================================================================
+//
+// BuiltinFontTables.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <config.h>
+#include <stdlib.h>
+#include "FontEncodingTables.h"
+#include "BuiltinFontTables.h"
+
+static BuiltinFontWidth courierWidthsTab[] = {
+ { "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
+ { "comma", 600, NULL },
+ { "cedilla", 600, NULL },
+ { "plusminus", 600, NULL },
+ { "circumflex", 600, NULL },
+ { "dotaccent", 600, NULL },
+ { "edotaccent", 600, NULL },
+ { "asciitilde", 600, NULL },
+ { "colon", 600, NULL },
+ { "onehalf", 600, NULL },
+ { "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
+ { "ntilde", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
+ { "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
+ { "yen", 600, NULL },
+ { "space", 600, NULL },
+ { "Omacron", 600, NULL },
+ { "questiondown", 600, NULL },
+ { "emdash", 600, NULL },
+ { "Agrave", 600, NULL },
+ { "three", 600, NULL },
+ { "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
+ { "A", 600, NULL },
+ { "B", 600, NULL },
+ { "C", 600, NULL },
+ { "aogonek", 600, NULL },
+ { "D", 600, NULL },
+ { "E", 600, NULL },
+ { "onequarter", 600, NULL },
+ { "F", 600, NULL },
+ { "G", 600, NULL },
+ { "H", 600, NULL },
+ { "I", 600, NULL },
+ { "J", 600, NULL },
+ { "K", 600, NULL },
+ { "iogonek", 600, NULL },
+ { "L", 600, NULL },
+ { "backslash", 600, NULL },
+ { "periodcentered", 600, NULL },
+ { "M", 600, NULL },
+ { "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
+ { "O", 600, NULL },
+ { "P", 600, NULL },
+ { "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
+ { "R", 600, NULL },
+ { "Aacute", 600, NULL },
+ { "caron", 600, NULL },
+ { "S", 600, NULL },
+ { "T", 600, NULL },
+ { "U", 600, NULL },
+ { "agrave", 600, NULL },
+ { "V", 600, NULL },
+ { "W", 600, NULL },
+ { "equal", 600, NULL },
+ { "question", 600, NULL },
+ { "X", 600, NULL },
+ { "Y", 600, NULL },
+ { "Z", 600, NULL },
+ { "four", 600, NULL },
+ { "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
+ { "b", 600, NULL },
+ { "c", 600, NULL },
+ { "d", 600, NULL },
+ { "e", 600, NULL },
+ { "f", 600, NULL },
+ { "g", 600, NULL },
+ { "bullet", 600, NULL },
+ { "h", 600, NULL },
+ { "i", 600, NULL },
+ { "Oslash", 600, NULL },
+ { "dagger", 600, NULL },
+ { "j", 600, NULL },
+ { "k", 600, NULL },
+ { "l", 600, NULL },
+ { "m", 600, NULL },
+ { "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
+ { "o", 600, NULL },
+ { "ordfeminine", 600, NULL },
+ { "ring", 600, NULL },
+ { "p", 600, NULL },
+ { "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
+ { "r", 600, NULL },
+ { "twosuperior", 600, NULL },
+ { "aacute", 600, NULL },
+ { "s", 600, NULL },
+ { "OE", 600, NULL },
+ { "t", 600, NULL },
+ { "divide", 600, NULL },
+ { "u", 600, NULL },
+ { "Ccaron", 600, NULL },
+ { "v", 600, NULL },
+ { "w", 600, NULL },
+ { "x", 600, NULL },
+ { "y", 600, NULL },
+ { "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
+ { "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
+ { "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
+ { "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
+ { "Scaron", 600, NULL },
+ { "Lslash", 600, NULL },
+ { "semicolon", 600, NULL },
+ { "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
+ { "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
+ { "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
+ { "trademark", 600, NULL },
+ { "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
+ { "macron", 600, NULL },
+ { "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
+ { "ellipsis", 600, NULL },
+ { "scaron", 600, NULL },
+ { "AE", 600, NULL },
+ { "Ucircumflex", 600, NULL },
+ { "lslash", 600, NULL },
+ { "quotedblleft", 600, NULL },
+ { "hyphen", 600, NULL },
+ { "guilsinglright", 600, NULL },
+ { "quotesingle", 600, NULL },
+ { "eight", 600, NULL },
+ { "exclamdown", 600, NULL },
+ { "endash", 600, NULL },
+ { "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
+ { "ecircumflex", 600, NULL },
+ { "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
+ { "Egrave", 600, NULL },
+ { "slash", 600, NULL },
+ { "Edieresis", 600, NULL },
+ { "otilde", 600, NULL },
+ { "Idieresis", 600, NULL },
+ { "parenleft", 600, NULL },
+ { "one", 600, NULL },
+ { "emacron", 600, NULL },
+ { "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
+ { "bracketleft", 600, NULL },
+ { "Ugrave", 600, NULL },
+ { "quoteright", 600, NULL },
+ { "Udieresis", 600, NULL },
+ { "perthousand", 600, NULL },
+ { "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
+ { "Eacute", 600, NULL },
+ { "adieresis", 600, NULL },
+ { "egrave", 600, NULL },
+ { "edieresis", 600, NULL },
+ { "idieresis", 600, NULL },
+ { "Eth", 600, NULL },
+ { "ae", 600, NULL },
+ { "asterisk", 600, NULL },
+ { "odieresis", 600, NULL },
+ { "Uacute", 600, NULL },
+ { "ugrave", 600, NULL },
+ { "five", 600, NULL },
+ { "nine", 600, NULL },
+ { "udieresis", 600, NULL },
+ { "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
+ { "threequarters", 600, NULL },
+ { "guillemotright", 600, NULL },
+ { "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
+ { "tilde", 600, NULL },
+ { "at", 600, NULL },
+ { "eacute", 600, NULL },
+ { "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
+ { "zero", 600, NULL },
+ { "multiply", 600, NULL },
+ { "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Racute", 600, NULL },
+ { "Ograve", 600, NULL },
+ { "partialdiff", 600, NULL },
+ { "uacute", 600, NULL },
+ { "braceleft", 600, NULL },
+ { "Thorn", 600, NULL },
+ { "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
+ { "ccedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "scedilla", 600, NULL },
+ { "Oacute", 600, NULL },
+ { "Ocircumflex", 600, NULL },
+ { "ogonek", 600, NULL },
+ { "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
+ { "thorn", 600, NULL },
+ { "degree", 600, NULL },
+ { "registered", 600, NULL },
+ { "radical", 600, NULL },
+ { "Aring", 600, NULL },
+ { "percent", 600, NULL },
+ { "six", 600, NULL },
+ { "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
+ { "two", 600, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
+ { "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
+ { "asciicircum", 600, NULL },
+ { "aring", 600, NULL },
+ { "grave", 600, NULL },
+ { "uogonek", 600, NULL },
+ { "bracketright", 600, NULL },
+ { "ampersand", 600, NULL },
+ { "Iacute", 600, NULL },
+ { "lacute", 600, NULL },
+ { "igrave", 600, NULL },
+ { "Ncaron", 600, NULL },
+ { "plus", 600, NULL },
+ { "uring", 600, NULL },
+ { "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
+ { "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
+ { "threesuperior", 600, NULL },
+ { "acute", 600, NULL },
+ { "section", 600, NULL },
+ { "dieresis", 600, NULL },
+ { "quotedblbase", 600, NULL },
+ { "iacute", 600, NULL },
+ { "ncaron", 600, NULL },
+ { "florin", 600, NULL },
+ { "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
+ { "fi", 600, NULL },
+ { "fl", 600, NULL },
+ { "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
+ { "Icircumflex", 600, NULL },
+ { "guillemotleft", 600, NULL },
+ { "germandbls", 600, NULL },
+ { "seven", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "Sacute", 600, NULL },
+ { "ordmasculine", 600, NULL },
+ { "dotlessi", 600, NULL },
+ { "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
+ { "acircumflex", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
+ { "braceright", 600, NULL },
+ { "icircumflex", 600, NULL },
+ { "quotedblright", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
+ { "cent", 600, NULL },
+ { "currency", 600, NULL },
+ { "logicalnot", 600, NULL },
+ { "zdotaccent", 600, NULL },
+ { "Atilde", 600, NULL },
+ { "breve", 600, NULL },
+ { "bar", 600, NULL },
+ { "fraction", 600, NULL },
+ { "less", 600, NULL },
+ { "ecaron", 600, NULL },
+ { "guilsinglleft", 600, NULL },
+ { "exclam", 600, NULL },
+ { "period", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
+ { "greater", 600, NULL },
+ { "atilde", 600, NULL },
+ { "brokenbar", 600, NULL },
+ { "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
+ { "onesuperior", 600, NULL }
+};
+
+static BuiltinFontWidth courierBoldWidthsTab[] = {
+ { "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
+ { "comma", 600, NULL },
+ { "cedilla", 600, NULL },
+ { "plusminus", 600, NULL },
+ { "circumflex", 600, NULL },
+ { "dotaccent", 600, NULL },
+ { "edotaccent", 600, NULL },
+ { "asciitilde", 600, NULL },
+ { "colon", 600, NULL },
+ { "onehalf", 600, NULL },
+ { "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
+ { "ntilde", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
+ { "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
+ { "yen", 600, NULL },
+ { "space", 600, NULL },
+ { "Omacron", 600, NULL },
+ { "questiondown", 600, NULL },
+ { "emdash", 600, NULL },
+ { "Agrave", 600, NULL },
+ { "three", 600, NULL },
+ { "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
+ { "A", 600, NULL },
+ { "B", 600, NULL },
+ { "C", 600, NULL },
+ { "aogonek", 600, NULL },
+ { "D", 600, NULL },
+ { "E", 600, NULL },
+ { "onequarter", 600, NULL },
+ { "F", 600, NULL },
+ { "G", 600, NULL },
+ { "H", 600, NULL },
+ { "I", 600, NULL },
+ { "J", 600, NULL },
+ { "K", 600, NULL },
+ { "iogonek", 600, NULL },
+ { "backslash", 600, NULL },
+ { "L", 600, NULL },
+ { "periodcentered", 600, NULL },
+ { "M", 600, NULL },
+ { "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
+ { "O", 600, NULL },
+ { "P", 600, NULL },
+ { "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
+ { "R", 600, NULL },
+ { "Aacute", 600, NULL },
+ { "caron", 600, NULL },
+ { "S", 600, NULL },
+ { "T", 600, NULL },
+ { "U", 600, NULL },
+ { "agrave", 600, NULL },
+ { "V", 600, NULL },
+ { "W", 600, NULL },
+ { "X", 600, NULL },
+ { "question", 600, NULL },
+ { "equal", 600, NULL },
+ { "Y", 600, NULL },
+ { "Z", 600, NULL },
+ { "four", 600, NULL },
+ { "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
+ { "b", 600, NULL },
+ { "c", 600, NULL },
+ { "d", 600, NULL },
+ { "e", 600, NULL },
+ { "f", 600, NULL },
+ { "g", 600, NULL },
+ { "bullet", 600, NULL },
+ { "h", 600, NULL },
+ { "i", 600, NULL },
+ { "Oslash", 600, NULL },
+ { "dagger", 600, NULL },
+ { "j", 600, NULL },
+ { "k", 600, NULL },
+ { "l", 600, NULL },
+ { "m", 600, NULL },
+ { "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
+ { "o", 600, NULL },
+ { "ordfeminine", 600, NULL },
+ { "ring", 600, NULL },
+ { "p", 600, NULL },
+ { "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
+ { "r", 600, NULL },
+ { "twosuperior", 600, NULL },
+ { "aacute", 600, NULL },
+ { "s", 600, NULL },
+ { "OE", 600, NULL },
+ { "t", 600, NULL },
+ { "divide", 600, NULL },
+ { "u", 600, NULL },
+ { "Ccaron", 600, NULL },
+ { "v", 600, NULL },
+ { "w", 600, NULL },
+ { "x", 600, NULL },
+ { "y", 600, NULL },
+ { "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
+ { "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
+ { "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
+ { "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
+ { "Scaron", 600, NULL },
+ { "Lslash", 600, NULL },
+ { "semicolon", 600, NULL },
+ { "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
+ { "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
+ { "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
+ { "trademark", 600, NULL },
+ { "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
+ { "macron", 600, NULL },
+ { "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
+ { "ellipsis", 600, NULL },
+ { "scaron", 600, NULL },
+ { "AE", 600, NULL },
+ { "Ucircumflex", 600, NULL },
+ { "lslash", 600, NULL },
+ { "quotedblleft", 600, NULL },
+ { "guilsinglright", 600, NULL },
+ { "hyphen", 600, NULL },
+ { "quotesingle", 600, NULL },
+ { "eight", 600, NULL },
+ { "exclamdown", 600, NULL },
+ { "endash", 600, NULL },
+ { "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
+ { "ecircumflex", 600, NULL },
+ { "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
+ { "Egrave", 600, NULL },
+ { "slash", 600, NULL },
+ { "Edieresis", 600, NULL },
+ { "otilde", 600, NULL },
+ { "Idieresis", 600, NULL },
+ { "parenleft", 600, NULL },
+ { "one", 600, NULL },
+ { "emacron", 600, NULL },
+ { "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
+ { "bracketleft", 600, NULL },
+ { "Ugrave", 600, NULL },
+ { "quoteright", 600, NULL },
+ { "Udieresis", 600, NULL },
+ { "perthousand", 600, NULL },
+ { "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
+ { "Eacute", 600, NULL },
+ { "adieresis", 600, NULL },
+ { "egrave", 600, NULL },
+ { "edieresis", 600, NULL },
+ { "idieresis", 600, NULL },
+ { "Eth", 600, NULL },
+ { "ae", 600, NULL },
+ { "asterisk", 600, NULL },
+ { "odieresis", 600, NULL },
+ { "Uacute", 600, NULL },
+ { "ugrave", 600, NULL },
+ { "nine", 600, NULL },
+ { "five", 600, NULL },
+ { "udieresis", 600, NULL },
+ { "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
+ { "threequarters", 600, NULL },
+ { "guillemotright", 600, NULL },
+ { "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
+ { "tilde", 600, NULL },
+ { "at", 600, NULL },
+ { "eacute", 600, NULL },
+ { "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
+ { "multiply", 600, NULL },
+ { "zero", 600, NULL },
+ { "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
+ { "uacute", 600, NULL },
+ { "braceleft", 600, NULL },
+ { "Thorn", 600, NULL },
+ { "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
+ { "ccedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "Ocircumflex", 600, NULL },
+ { "Oacute", 600, NULL },
+ { "scedilla", 600, NULL },
+ { "ogonek", 600, NULL },
+ { "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
+ { "thorn", 600, NULL },
+ { "degree", 600, NULL },
+ { "registered", 600, NULL },
+ { "radical", 600, NULL },
+ { "Aring", 600, NULL },
+ { "percent", 600, NULL },
+ { "six", 600, NULL },
+ { "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
+ { "two", 600, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
+ { "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
+ { "asciicircum", 600, NULL },
+ { "aring", 600, NULL },
+ { "grave", 600, NULL },
+ { "uogonek", 600, NULL },
+ { "bracketright", 600, NULL },
+ { "Iacute", 600, NULL },
+ { "ampersand", 600, NULL },
+ { "igrave", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
+ { "plus", 600, NULL },
+ { "uring", 600, NULL },
+ { "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
+ { "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
+ { "threesuperior", 600, NULL },
+ { "acute", 600, NULL },
+ { "section", 600, NULL },
+ { "dieresis", 600, NULL },
+ { "iacute", 600, NULL },
+ { "quotedblbase", 600, NULL },
+ { "ncaron", 600, NULL },
+ { "florin", 600, NULL },
+ { "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
+ { "fi", 600, NULL },
+ { "fl", 600, NULL },
+ { "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
+ { "Icircumflex", 600, NULL },
+ { "guillemotleft", 600, NULL },
+ { "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "seven", 600, NULL },
+ { "Sacute", 600, NULL },
+ { "ordmasculine", 600, NULL },
+ { "dotlessi", 600, NULL },
+ { "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
+ { "acircumflex", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
+ { "icircumflex", 600, NULL },
+ { "braceright", 600, NULL },
+ { "quotedblright", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
+ { "cent", 600, NULL },
+ { "currency", 600, NULL },
+ { "logicalnot", 600, NULL },
+ { "zdotaccent", 600, NULL },
+ { "Atilde", 600, NULL },
+ { "breve", 600, NULL },
+ { "bar", 600, NULL },
+ { "fraction", 600, NULL },
+ { "less", 600, NULL },
+ { "ecaron", 600, NULL },
+ { "guilsinglleft", 600, NULL },
+ { "exclam", 600, NULL },
+ { "period", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
+ { "greater", 600, NULL },
+ { "atilde", 600, NULL },
+ { "brokenbar", 600, NULL },
+ { "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
+ { "onesuperior", 600, NULL }
+};
+
+static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
+ { "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
+ { "comma", 600, NULL },
+ { "cedilla", 600, NULL },
+ { "plusminus", 600, NULL },
+ { "circumflex", 600, NULL },
+ { "dotaccent", 600, NULL },
+ { "edotaccent", 600, NULL },
+ { "asciitilde", 600, NULL },
+ { "colon", 600, NULL },
+ { "onehalf", 600, NULL },
+ { "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
+ { "ntilde", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
+ { "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
+ { "yen", 600, NULL },
+ { "space", 600, NULL },
+ { "Omacron", 600, NULL },
+ { "questiondown", 600, NULL },
+ { "emdash", 600, NULL },
+ { "Agrave", 600, NULL },
+ { "three", 600, NULL },
+ { "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
+ { "A", 600, NULL },
+ { "B", 600, NULL },
+ { "C", 600, NULL },
+ { "aogonek", 600, NULL },
+ { "D", 600, NULL },
+ { "E", 600, NULL },
+ { "onequarter", 600, NULL },
+ { "F", 600, NULL },
+ { "G", 600, NULL },
+ { "H", 600, NULL },
+ { "I", 600, NULL },
+ { "J", 600, NULL },
+ { "K", 600, NULL },
+ { "iogonek", 600, NULL },
+ { "backslash", 600, NULL },
+ { "L", 600, NULL },
+ { "periodcentered", 600, NULL },
+ { "M", 600, NULL },
+ { "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
+ { "O", 600, NULL },
+ { "P", 600, NULL },
+ { "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
+ { "R", 600, NULL },
+ { "Aacute", 600, NULL },
+ { "caron", 600, NULL },
+ { "S", 600, NULL },
+ { "T", 600, NULL },
+ { "U", 600, NULL },
+ { "agrave", 600, NULL },
+ { "V", 600, NULL },
+ { "W", 600, NULL },
+ { "X", 600, NULL },
+ { "question", 600, NULL },
+ { "equal", 600, NULL },
+ { "Y", 600, NULL },
+ { "Z", 600, NULL },
+ { "four", 600, NULL },
+ { "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
+ { "b", 600, NULL },
+ { "c", 600, NULL },
+ { "d", 600, NULL },
+ { "e", 600, NULL },
+ { "f", 600, NULL },
+ { "g", 600, NULL },
+ { "bullet", 600, NULL },
+ { "h", 600, NULL },
+ { "i", 600, NULL },
+ { "Oslash", 600, NULL },
+ { "dagger", 600, NULL },
+ { "j", 600, NULL },
+ { "k", 600, NULL },
+ { "l", 600, NULL },
+ { "m", 600, NULL },
+ { "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
+ { "o", 600, NULL },
+ { "ordfeminine", 600, NULL },
+ { "ring", 600, NULL },
+ { "p", 600, NULL },
+ { "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
+ { "r", 600, NULL },
+ { "twosuperior", 600, NULL },
+ { "aacute", 600, NULL },
+ { "s", 600, NULL },
+ { "OE", 600, NULL },
+ { "t", 600, NULL },
+ { "divide", 600, NULL },
+ { "u", 600, NULL },
+ { "Ccaron", 600, NULL },
+ { "v", 600, NULL },
+ { "w", 600, NULL },
+ { "x", 600, NULL },
+ { "y", 600, NULL },
+ { "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
+ { "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
+ { "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
+ { "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
+ { "Scaron", 600, NULL },
+ { "Lslash", 600, NULL },
+ { "semicolon", 600, NULL },
+ { "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
+ { "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
+ { "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
+ { "trademark", 600, NULL },
+ { "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
+ { "macron", 600, NULL },
+ { "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
+ { "ellipsis", 600, NULL },
+ { "scaron", 600, NULL },
+ { "AE", 600, NULL },
+ { "Ucircumflex", 600, NULL },
+ { "lslash", 600, NULL },
+ { "quotedblleft", 600, NULL },
+ { "guilsinglright", 600, NULL },
+ { "hyphen", 600, NULL },
+ { "quotesingle", 600, NULL },
+ { "eight", 600, NULL },
+ { "exclamdown", 600, NULL },
+ { "endash", 600, NULL },
+ { "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
+ { "ecircumflex", 600, NULL },
+ { "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
+ { "Egrave", 600, NULL },
+ { "slash", 600, NULL },
+ { "Edieresis", 600, NULL },
+ { "otilde", 600, NULL },
+ { "Idieresis", 600, NULL },
+ { "parenleft", 600, NULL },
+ { "one", 600, NULL },
+ { "emacron", 600, NULL },
+ { "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
+ { "bracketleft", 600, NULL },
+ { "Ugrave", 600, NULL },
+ { "quoteright", 600, NULL },
+ { "Udieresis", 600, NULL },
+ { "perthousand", 600, NULL },
+ { "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
+ { "Eacute", 600, NULL },
+ { "adieresis", 600, NULL },
+ { "egrave", 600, NULL },
+ { "edieresis", 600, NULL },
+ { "idieresis", 600, NULL },
+ { "Eth", 600, NULL },
+ { "ae", 600, NULL },
+ { "asterisk", 600, NULL },
+ { "odieresis", 600, NULL },
+ { "Uacute", 600, NULL },
+ { "ugrave", 600, NULL },
+ { "nine", 600, NULL },
+ { "five", 600, NULL },
+ { "udieresis", 600, NULL },
+ { "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
+ { "threequarters", 600, NULL },
+ { "guillemotright", 600, NULL },
+ { "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
+ { "tilde", 600, NULL },
+ { "at", 600, NULL },
+ { "eacute", 600, NULL },
+ { "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
+ { "multiply", 600, NULL },
+ { "zero", 600, NULL },
+ { "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
+ { "uacute", 600, NULL },
+ { "braceleft", 600, NULL },
+ { "Thorn", 600, NULL },
+ { "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
+ { "ccedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "Ocircumflex", 600, NULL },
+ { "Oacute", 600, NULL },
+ { "scedilla", 600, NULL },
+ { "ogonek", 600, NULL },
+ { "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
+ { "thorn", 600, NULL },
+ { "degree", 600, NULL },
+ { "registered", 600, NULL },
+ { "radical", 600, NULL },
+ { "Aring", 600, NULL },
+ { "percent", 600, NULL },
+ { "six", 600, NULL },
+ { "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
+ { "two", 600, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
+ { "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
+ { "asciicircum", 600, NULL },
+ { "aring", 600, NULL },
+ { "grave", 600, NULL },
+ { "uogonek", 600, NULL },
+ { "bracketright", 600, NULL },
+ { "Iacute", 600, NULL },
+ { "ampersand", 600, NULL },
+ { "igrave", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
+ { "plus", 600, NULL },
+ { "uring", 600, NULL },
+ { "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
+ { "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
+ { "threesuperior", 600, NULL },
+ { "acute", 600, NULL },
+ { "section", 600, NULL },
+ { "dieresis", 600, NULL },
+ { "iacute", 600, NULL },
+ { "quotedblbase", 600, NULL },
+ { "ncaron", 600, NULL },
+ { "florin", 600, NULL },
+ { "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
+ { "fi", 600, NULL },
+ { "fl", 600, NULL },
+ { "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
+ { "Icircumflex", 600, NULL },
+ { "guillemotleft", 600, NULL },
+ { "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "seven", 600, NULL },
+ { "Sacute", 600, NULL },
+ { "ordmasculine", 600, NULL },
+ { "dotlessi", 600, NULL },
+ { "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
+ { "acircumflex", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
+ { "icircumflex", 600, NULL },
+ { "braceright", 600, NULL },
+ { "quotedblright", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
+ { "cent", 600, NULL },
+ { "currency", 600, NULL },
+ { "logicalnot", 600, NULL },
+ { "zdotaccent", 600, NULL },
+ { "Atilde", 600, NULL },
+ { "breve", 600, NULL },
+ { "bar", 600, NULL },
+ { "fraction", 600, NULL },
+ { "less", 600, NULL },
+ { "ecaron", 600, NULL },
+ { "guilsinglleft", 600, NULL },
+ { "exclam", 600, NULL },
+ { "period", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
+ { "greater", 600, NULL },
+ { "atilde", 600, NULL },
+ { "brokenbar", 600, NULL },
+ { "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
+ { "onesuperior", 600, NULL }
+};
+
+static BuiltinFontWidth courierObliqueWidthsTab[] = {
+ { "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
+ { "comma", 600, NULL },
+ { "cedilla", 600, NULL },
+ { "plusminus", 600, NULL },
+ { "circumflex", 600, NULL },
+ { "dotaccent", 600, NULL },
+ { "edotaccent", 600, NULL },
+ { "asciitilde", 600, NULL },
+ { "colon", 600, NULL },
+ { "onehalf", 600, NULL },
+ { "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
+ { "ntilde", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
+ { "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
+ { "yen", 600, NULL },
+ { "space", 600, NULL },
+ { "Omacron", 600, NULL },
+ { "questiondown", 600, NULL },
+ { "emdash", 600, NULL },
+ { "Agrave", 600, NULL },
+ { "three", 600, NULL },
+ { "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
+ { "A", 600, NULL },
+ { "B", 600, NULL },
+ { "C", 600, NULL },
+ { "aogonek", 600, NULL },
+ { "D", 600, NULL },
+ { "E", 600, NULL },
+ { "onequarter", 600, NULL },
+ { "F", 600, NULL },
+ { "G", 600, NULL },
+ { "H", 600, NULL },
+ { "I", 600, NULL },
+ { "J", 600, NULL },
+ { "K", 600, NULL },
+ { "iogonek", 600, NULL },
+ { "backslash", 600, NULL },
+ { "L", 600, NULL },
+ { "periodcentered", 600, NULL },
+ { "M", 600, NULL },
+ { "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
+ { "O", 600, NULL },
+ { "P", 600, NULL },
+ { "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
+ { "R", 600, NULL },
+ { "Aacute", 600, NULL },
+ { "caron", 600, NULL },
+ { "S", 600, NULL },
+ { "T", 600, NULL },
+ { "U", 600, NULL },
+ { "agrave", 600, NULL },
+ { "V", 600, NULL },
+ { "W", 600, NULL },
+ { "X", 600, NULL },
+ { "question", 600, NULL },
+ { "equal", 600, NULL },
+ { "Y", 600, NULL },
+ { "Z", 600, NULL },
+ { "four", 600, NULL },
+ { "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
+ { "b", 600, NULL },
+ { "c", 600, NULL },
+ { "d", 600, NULL },
+ { "e", 600, NULL },
+ { "f", 600, NULL },
+ { "g", 600, NULL },
+ { "bullet", 600, NULL },
+ { "h", 600, NULL },
+ { "i", 600, NULL },
+ { "Oslash", 600, NULL },
+ { "dagger", 600, NULL },
+ { "j", 600, NULL },
+ { "k", 600, NULL },
+ { "l", 600, NULL },
+ { "m", 600, NULL },
+ { "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
+ { "o", 600, NULL },
+ { "ordfeminine", 600, NULL },
+ { "ring", 600, NULL },
+ { "p", 600, NULL },
+ { "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
+ { "r", 600, NULL },
+ { "twosuperior", 600, NULL },
+ { "aacute", 600, NULL },
+ { "s", 600, NULL },
+ { "OE", 600, NULL },
+ { "t", 600, NULL },
+ { "divide", 600, NULL },
+ { "u", 600, NULL },
+ { "Ccaron", 600, NULL },
+ { "v", 600, NULL },
+ { "w", 600, NULL },
+ { "x", 600, NULL },
+ { "y", 600, NULL },
+ { "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
+ { "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
+ { "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
+ { "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
+ { "Scaron", 600, NULL },
+ { "Lslash", 600, NULL },
+ { "semicolon", 600, NULL },
+ { "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
+ { "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
+ { "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
+ { "trademark", 600, NULL },
+ { "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
+ { "macron", 600, NULL },
+ { "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
+ { "ellipsis", 600, NULL },
+ { "scaron", 600, NULL },
+ { "AE", 600, NULL },
+ { "Ucircumflex", 600, NULL },
+ { "lslash", 600, NULL },
+ { "quotedblleft", 600, NULL },
+ { "guilsinglright", 600, NULL },
+ { "hyphen", 600, NULL },
+ { "quotesingle", 600, NULL },
+ { "eight", 600, NULL },
+ { "exclamdown", 600, NULL },
+ { "endash", 600, NULL },
+ { "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
+ { "ecircumflex", 600, NULL },
+ { "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
+ { "Egrave", 600, NULL },
+ { "slash", 600, NULL },
+ { "Edieresis", 600, NULL },
+ { "otilde", 600, NULL },
+ { "Idieresis", 600, NULL },
+ { "parenleft", 600, NULL },
+ { "one", 600, NULL },
+ { "emacron", 600, NULL },
+ { "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
+ { "bracketleft", 600, NULL },
+ { "Ugrave", 600, NULL },
+ { "quoteright", 600, NULL },
+ { "Udieresis", 600, NULL },
+ { "perthousand", 600, NULL },
+ { "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
+ { "Eacute", 600, NULL },
+ { "adieresis", 600, NULL },
+ { "egrave", 600, NULL },
+ { "edieresis", 600, NULL },
+ { "idieresis", 600, NULL },
+ { "Eth", 600, NULL },
+ { "ae", 600, NULL },
+ { "asterisk", 600, NULL },
+ { "odieresis", 600, NULL },
+ { "Uacute", 600, NULL },
+ { "ugrave", 600, NULL },
+ { "nine", 600, NULL },
+ { "five", 600, NULL },
+ { "udieresis", 600, NULL },
+ { "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
+ { "threequarters", 600, NULL },
+ { "guillemotright", 600, NULL },
+ { "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
+ { "tilde", 600, NULL },
+ { "at", 600, NULL },
+ { "eacute", 600, NULL },
+ { "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
+ { "multiply", 600, NULL },
+ { "zero", 600, NULL },
+ { "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
+ { "uacute", 600, NULL },
+ { "braceleft", 600, NULL },
+ { "Thorn", 600, NULL },
+ { "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
+ { "ccedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "Ocircumflex", 600, NULL },
+ { "Oacute", 600, NULL },
+ { "scedilla", 600, NULL },
+ { "ogonek", 600, NULL },
+ { "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
+ { "thorn", 600, NULL },
+ { "degree", 600, NULL },
+ { "registered", 600, NULL },
+ { "radical", 600, NULL },
+ { "Aring", 600, NULL },
+ { "percent", 600, NULL },
+ { "six", 600, NULL },
+ { "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
+ { "two", 600, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
+ { "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
+ { "asciicircum", 600, NULL },
+ { "aring", 600, NULL },
+ { "grave", 600, NULL },
+ { "uogonek", 600, NULL },
+ { "bracketright", 600, NULL },
+ { "Iacute", 600, NULL },
+ { "ampersand", 600, NULL },
+ { "igrave", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
+ { "plus", 600, NULL },
+ { "uring", 600, NULL },
+ { "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
+ { "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
+ { "threesuperior", 600, NULL },
+ { "acute", 600, NULL },
+ { "section", 600, NULL },
+ { "dieresis", 600, NULL },
+ { "iacute", 600, NULL },
+ { "quotedblbase", 600, NULL },
+ { "ncaron", 600, NULL },
+ { "florin", 600, NULL },
+ { "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
+ { "fi", 600, NULL },
+ { "fl", 600, NULL },
+ { "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
+ { "Icircumflex", 600, NULL },
+ { "guillemotleft", 600, NULL },
+ { "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "seven", 600, NULL },
+ { "Sacute", 600, NULL },
+ { "ordmasculine", 600, NULL },
+ { "dotlessi", 600, NULL },
+ { "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
+ { "acircumflex", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
+ { "icircumflex", 600, NULL },
+ { "braceright", 600, NULL },
+ { "quotedblright", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
+ { "cent", 600, NULL },
+ { "currency", 600, NULL },
+ { "logicalnot", 600, NULL },
+ { "zdotaccent", 600, NULL },
+ { "Atilde", 600, NULL },
+ { "breve", 600, NULL },
+ { "bar", 600, NULL },
+ { "fraction", 600, NULL },
+ { "less", 600, NULL },
+ { "ecaron", 600, NULL },
+ { "guilsinglleft", 600, NULL },
+ { "exclam", 600, NULL },
+ { "period", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
+ { "greater", 600, NULL },
+ { "atilde", 600, NULL },
+ { "brokenbar", 600, NULL },
+ { "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
+ { "onesuperior", 600, NULL }
+};
+
+static BuiltinFontWidth helveticaWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 278, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 584, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
+ { "asciitilde", 584, NULL },
+ { "colon", 278, NULL },
+ { "onehalf", 834, NULL },
+ { "dollar", 556, NULL },
+ { "Lcaron", 556, NULL },
+ { "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
+ { "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
+ { "yen", 556, NULL },
+ { "space", 278, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 611, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 667, NULL },
+ { "three", 556, NULL },
+ { "numbersign", 556, NULL },
+ { "lcaron", 299, NULL },
+ { "A", 667, NULL },
+ { "B", 667, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 556, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 834, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 722, NULL },
+ { "I", 278, NULL },
+ { "J", 500, NULL },
+ { "K", 667, NULL },
+ { "iogonek", 222, NULL },
+ { "backslash", 278, NULL },
+ { "L", 556, NULL },
+ { "periodcentered", 278, NULL },
+ { "M", 833, NULL },
+ { "N", 722, NULL },
+ { "omacron", 556, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 778, NULL },
+ { "P", 667, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 667, NULL },
+ { "caron", 333, NULL },
+ { "S", 667, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 556, NULL },
+ { "V", 667, NULL },
+ { "W", 944, NULL },
+ { "X", 667, NULL },
+ { "question", 556, NULL },
+ { "equal", 584, NULL },
+ { "Y", 667, NULL },
+ { "Z", 611, NULL },
+ { "four", 556, NULL },
+ { "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 556, NULL },
+ { "c", 500, NULL },
+ { "d", 556, NULL },
+ { "e", 556, NULL },
+ { "f", 278, NULL },
+ { "g", 556, NULL },
+ { "bullet", 350, NULL },
+ { "h", 556, NULL },
+ { "i", 222, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 556, NULL },
+ { "j", 222, NULL },
+ { "k", 500, NULL },
+ { "l", 222, NULL },
+ { "m", 833, NULL },
+ { "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 556, NULL },
+ { "ordfeminine", 370, NULL },
+ { "ring", 333, NULL },
+ { "p", 556, NULL },
+ { "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
+ { "r", 333, NULL },
+ { "twosuperior", 333, NULL },
+ { "aacute", 556, NULL },
+ { "s", 500, NULL },
+ { "OE", 1000, NULL },
+ { "t", 278, NULL },
+ { "divide", 584, NULL },
+ { "u", 556, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 500, NULL },
+ { "w", 722, NULL },
+ { "x", 500, NULL },
+ { "y", 500, NULL },
+ { "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 355, NULL },
+ { "gcommaaccent", 556, NULL },
+ { "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 667, NULL },
+ { "Lslash", 556, NULL },
+ { "semicolon", 278, NULL },
+ { "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 500, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 556, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 556, NULL },
+ { "nacute", 556, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 500, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 222, NULL },
+ { "quotedblleft", 333, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 191, NULL },
+ { "eight", 556, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 556, NULL },
+ { "oe", 944, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 556, NULL },
+ { "Adieresis", 667, NULL },
+ { "copyright", 737, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 556, NULL },
+ { "Idieresis", 278, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 556, NULL },
+ { "emacron", 556, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
+ { "bracketleft", 278, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 222, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 667, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 556, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 556, NULL },
+ { "egrave", 556, NULL },
+ { "edieresis", 556, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 889, NULL },
+ { "asterisk", 389, NULL },
+ { "odieresis", 556, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 556, NULL },
+ { "nine", 556, NULL },
+ { "five", 556, NULL },
+ { "udieresis", 556, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
+ { "threequarters", 834, NULL },
+ { "guillemotright", 556, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
+ { "tilde", 333, NULL },
+ { "at", 1015, NULL },
+ { "eacute", 556, NULL },
+ { "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 584, NULL },
+ { "zero", 556, NULL },
+ { "eth", 556, NULL },
+ { "Scedilla", 667, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 476, NULL },
+ { "uacute", 556, NULL },
+ { "braceleft", 334, NULL },
+ { "Thorn", 667, NULL },
+ { "zcaron", 500, NULL },
+ { "scommaaccent", 500, NULL },
+ { "ccedilla", 500, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 500, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 556, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 556, NULL },
+ { "degree", 400, NULL },
+ { "registered", 737, NULL },
+ { "radical", 453, NULL },
+ { "Aring", 667, NULL },
+ { "percent", 889, NULL },
+ { "six", 556, NULL },
+ { "paragraph", 537, NULL },
+ { "dcaron", 643, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 556, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 278, NULL },
+ { "Lacute", 556, NULL },
+ { "ocircumflex", 556, NULL },
+ { "oacute", 556, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 317, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 469, NULL },
+ { "aring", 556, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 556, NULL },
+ { "bracketright", 278, NULL },
+ { "Iacute", 278, NULL },
+ { "ampersand", 667, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 222, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 584, NULL },
+ { "uring", 556, NULL },
+ { "quotesinglbase", 222, NULL },
+ { "lcommaaccent", 222, NULL },
+ { "Yacute", 667, NULL },
+ { "ohungarumlaut", 556, NULL },
+ { "threesuperior", 333, NULL },
+ { "acute", 333, NULL },
+ { "section", 556, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 333, NULL },
+ { "ncaron", 556, NULL },
+ { "florin", 556, NULL },
+ { "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 500, NULL },
+ { "fl", 500, NULL },
+ { "Acircumflex", 667, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 278, NULL },
+ { "guillemotleft", 556, NULL },
+ { "germandbls", 611, NULL },
+ { "Amacron", 667, NULL },
+ { "seven", 556, NULL },
+ { "Sacute", 667, NULL },
+ { "ordmasculine", 365, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 556, NULL },
+ { "cacute", 500, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 334, NULL },
+ { "quotedblright", 333, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 500, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 556, NULL },
+ { "currency", 556, NULL },
+ { "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
+ { "Atilde", 667, NULL },
+ { "breve", 333, NULL },
+ { "bar", 260, NULL },
+ { "fraction", 167, NULL },
+ { "less", 584, NULL },
+ { "ecaron", 556, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 278, NULL },
+ { "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 667, NULL },
+ { "greater", 584, NULL },
+ { "atilde", 556, NULL },
+ { "brokenbar", 260, NULL },
+ { "quoteleft", 222, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 333, NULL }
+};
+
+static BuiltinFontWidth helveticaBoldWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 278, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 584, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
+ { "asciitilde", 584, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 834, NULL },
+ { "dollar", 556, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 611, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 611, NULL },
+ { "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
+ { "yen", 556, NULL },
+ { "space", 278, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 611, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 722, NULL },
+ { "three", 556, NULL },
+ { "numbersign", 556, NULL },
+ { "lcaron", 400, NULL },
+ { "A", 722, NULL },
+ { "B", 722, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 556, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 834, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 722, NULL },
+ { "I", 278, NULL },
+ { "J", 556, NULL },
+ { "K", 722, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 611, NULL },
+ { "periodcentered", 278, NULL },
+ { "M", 833, NULL },
+ { "N", 722, NULL },
+ { "omacron", 611, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 778, NULL },
+ { "P", 667, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 722, NULL },
+ { "caron", 333, NULL },
+ { "S", 667, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 556, NULL },
+ { "V", 667, NULL },
+ { "W", 944, NULL },
+ { "X", 667, NULL },
+ { "question", 611, NULL },
+ { "equal", 584, NULL },
+ { "Y", 667, NULL },
+ { "Z", 611, NULL },
+ { "four", 556, NULL },
+ { "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 611, NULL },
+ { "c", 556, NULL },
+ { "d", 611, NULL },
+ { "e", 556, NULL },
+ { "f", 333, NULL },
+ { "g", 611, NULL },
+ { "bullet", 350, NULL },
+ { "h", 611, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 556, NULL },
+ { "j", 278, NULL },
+ { "k", 556, NULL },
+ { "l", 278, NULL },
+ { "m", 889, NULL },
+ { "n", 611, NULL },
+ { "tcommaaccent", 333, NULL },
+ { "o", 611, NULL },
+ { "ordfeminine", 370, NULL },
+ { "ring", 333, NULL },
+ { "p", 611, NULL },
+ { "q", 611, NULL },
+ { "uhungarumlaut", 611, NULL },
+ { "r", 389, NULL },
+ { "twosuperior", 333, NULL },
+ { "aacute", 556, NULL },
+ { "s", 556, NULL },
+ { "OE", 1000, NULL },
+ { "t", 333, NULL },
+ { "divide", 584, NULL },
+ { "u", 611, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 556, NULL },
+ { "w", 778, NULL },
+ { "x", 556, NULL },
+ { "y", 556, NULL },
+ { "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 474, NULL },
+ { "gcommaaccent", 611, NULL },
+ { "mu", 611, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 667, NULL },
+ { "Lslash", 611, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 556, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 611, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 556, NULL },
+ { "nacute", 611, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 556, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 500, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 238, NULL },
+ { "eight", 556, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 556, NULL },
+ { "oe", 944, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 556, NULL },
+ { "Adieresis", 722, NULL },
+ { "copyright", 737, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 611, NULL },
+ { "Idieresis", 278, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 556, NULL },
+ { "emacron", 556, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 611, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 278, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 667, NULL },
+ { "umacron", 611, NULL },
+ { "abreve", 556, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 556, NULL },
+ { "egrave", 556, NULL },
+ { "edieresis", 556, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 889, NULL },
+ { "asterisk", 389, NULL },
+ { "odieresis", 611, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 611, NULL },
+ { "nine", 556, NULL },
+ { "five", 556, NULL },
+ { "udieresis", 611, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
+ { "threequarters", 834, NULL },
+ { "guillemotright", 556, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 556, NULL },
+ { "tilde", 333, NULL },
+ { "dbldaggerumlaut", 556, NULL },
+ { "at", 975, NULL },
+ { "eacute", 556, NULL },
+ { "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 584, NULL },
+ { "zero", 556, NULL },
+ { "eth", 611, NULL },
+ { "Scedilla", 667, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
+ { "uacute", 611, NULL },
+ { "braceleft", 389, NULL },
+ { "Thorn", 667, NULL },
+ { "zcaron", 500, NULL },
+ { "scommaaccent", 556, NULL },
+ { "ccedilla", 556, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 611, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 556, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 611, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 611, NULL },
+ { "degree", 400, NULL },
+ { "registered", 737, NULL },
+ { "radical", 549, NULL },
+ { "Aring", 722, NULL },
+ { "percent", 889, NULL },
+ { "six", 556, NULL },
+ { "paragraph", 556, NULL },
+ { "dcaron", 743, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 556, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 278, NULL },
+ { "Lacute", 611, NULL },
+ { "ocircumflex", 611, NULL },
+ { "oacute", 611, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 389, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 584, NULL },
+ { "aring", 556, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 611, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 278, NULL },
+ { "ampersand", 722, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 584, NULL },
+ { "uring", 611, NULL },
+ { "quotesinglbase", 278, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 667, NULL },
+ { "ohungarumlaut", 611, NULL },
+ { "threesuperior", 333, NULL },
+ { "acute", 333, NULL },
+ { "section", 556, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 500, NULL },
+ { "ncaron", 611, NULL },
+ { "florin", 556, NULL },
+ { "yacute", 556, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 611, NULL },
+ { "fl", 611, NULL },
+ { "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 278, NULL },
+ { "guillemotleft", 556, NULL },
+ { "germandbls", 611, NULL },
+ { "Amacron", 722, NULL },
+ { "seven", 556, NULL },
+ { "Sacute", 667, NULL },
+ { "ordmasculine", 365, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 556, NULL },
+ { "cacute", 556, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 389, NULL },
+ { "quotedblright", 500, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 556, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 556, NULL },
+ { "currency", 556, NULL },
+ { "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
+ { "Atilde", 722, NULL },
+ { "breve", 333, NULL },
+ { "bar", 280, NULL },
+ { "fraction", 167, NULL },
+ { "less", 584, NULL },
+ { "ecaron", 556, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 722, NULL },
+ { "greater", 584, NULL },
+ { "atilde", 556, NULL },
+ { "brokenbar", 280, NULL },
+ { "quoteleft", 278, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 333, NULL }
+};
+
+static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 278, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 584, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
+ { "asciitilde", 584, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 834, NULL },
+ { "dollar", 556, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 611, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 611, NULL },
+ { "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
+ { "yen", 556, NULL },
+ { "space", 278, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 611, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 722, NULL },
+ { "three", 556, NULL },
+ { "numbersign", 556, NULL },
+ { "lcaron", 400, NULL },
+ { "A", 722, NULL },
+ { "B", 722, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 556, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 834, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 722, NULL },
+ { "I", 278, NULL },
+ { "J", 556, NULL },
+ { "K", 722, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 611, NULL },
+ { "periodcentered", 278, NULL },
+ { "M", 833, NULL },
+ { "N", 722, NULL },
+ { "omacron", 611, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 778, NULL },
+ { "P", 667, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 722, NULL },
+ { "caron", 333, NULL },
+ { "S", 667, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 556, NULL },
+ { "V", 667, NULL },
+ { "W", 944, NULL },
+ { "X", 667, NULL },
+ { "question", 611, NULL },
+ { "equal", 584, NULL },
+ { "Y", 667, NULL },
+ { "Z", 611, NULL },
+ { "four", 556, NULL },
+ { "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 611, NULL },
+ { "c", 556, NULL },
+ { "d", 611, NULL },
+ { "e", 556, NULL },
+ { "f", 333, NULL },
+ { "g", 611, NULL },
+ { "bullet", 350, NULL },
+ { "h", 611, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 556, NULL },
+ { "j", 278, NULL },
+ { "k", 556, NULL },
+ { "l", 278, NULL },
+ { "m", 889, NULL },
+ { "n", 611, NULL },
+ { "tcommaaccent", 333, NULL },
+ { "o", 611, NULL },
+ { "ordfeminine", 370, NULL },
+ { "ring", 333, NULL },
+ { "p", 611, NULL },
+ { "q", 611, NULL },
+ { "uhungarumlaut", 611, NULL },
+ { "r", 389, NULL },
+ { "twosuperior", 333, NULL },
+ { "aacute", 556, NULL },
+ { "s", 556, NULL },
+ { "OE", 1000, NULL },
+ { "t", 333, NULL },
+ { "divide", 584, NULL },
+ { "u", 611, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 556, NULL },
+ { "w", 778, NULL },
+ { "x", 556, NULL },
+ { "y", 556, NULL },
+ { "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 474, NULL },
+ { "gcommaaccent", 611, NULL },
+ { "mu", 611, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 667, NULL },
+ { "Lslash", 611, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 556, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 611, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 556, NULL },
+ { "nacute", 611, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 556, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 500, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 238, NULL },
+ { "eight", 556, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 556, NULL },
+ { "oe", 944, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 556, NULL },
+ { "Adieresis", 722, NULL },
+ { "copyright", 737, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 611, NULL },
+ { "Idieresis", 278, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 556, NULL },
+ { "emacron", 556, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 611, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 278, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 667, NULL },
+ { "umacron", 611, NULL },
+ { "abreve", 556, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 556, NULL },
+ { "egrave", 556, NULL },
+ { "edieresis", 556, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 889, NULL },
+ { "asterisk", 389, NULL },
+ { "odieresis", 611, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 611, NULL },
+ { "nine", 556, NULL },
+ { "five", 556, NULL },
+ { "udieresis", 611, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
+ { "threequarters", 834, NULL },
+ { "guillemotright", 556, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 556, NULL },
+ { "tilde", 333, NULL },
+ { "at", 975, NULL },
+ { "eacute", 556, NULL },
+ { "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 584, NULL },
+ { "zero", 556, NULL },
+ { "eth", 611, NULL },
+ { "Scedilla", 667, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
+ { "uacute", 611, NULL },
+ { "braceleft", 389, NULL },
+ { "Thorn", 667, NULL },
+ { "zcaron", 500, NULL },
+ { "scommaaccent", 556, NULL },
+ { "ccedilla", 556, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 611, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 556, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 611, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 611, NULL },
+ { "degree", 400, NULL },
+ { "registered", 737, NULL },
+ { "radical", 549, NULL },
+ { "Aring", 722, NULL },
+ { "percent", 889, NULL },
+ { "six", 556, NULL },
+ { "paragraph", 556, NULL },
+ { "dcaron", 743, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 556, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 278, NULL },
+ { "Lacute", 611, NULL },
+ { "ocircumflex", 611, NULL },
+ { "oacute", 611, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 389, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 584, NULL },
+ { "aring", 556, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 611, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 278, NULL },
+ { "ampersand", 722, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 584, NULL },
+ { "uring", 611, NULL },
+ { "quotesinglbase", 278, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 667, NULL },
+ { "ohungarumlaut", 611, NULL },
+ { "threesuperior", 333, NULL },
+ { "acute", 333, NULL },
+ { "section", 556, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 500, NULL },
+ { "ncaron", 611, NULL },
+ { "florin", 556, NULL },
+ { "yacute", 556, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 611, NULL },
+ { "fl", 611, NULL },
+ { "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 278, NULL },
+ { "guillemotleft", 556, NULL },
+ { "germandbls", 611, NULL },
+ { "Amacron", 722, NULL },
+ { "seven", 556, NULL },
+ { "Sacute", 667, NULL },
+ { "ordmasculine", 365, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 556, NULL },
+ { "cacute", 556, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 389, NULL },
+ { "quotedblright", 500, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 556, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 556, NULL },
+ { "currency", 556, NULL },
+ { "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
+ { "Atilde", 722, NULL },
+ { "breve", 333, NULL },
+ { "bar", 280, NULL },
+ { "fraction", 167, NULL },
+ { "less", 584, NULL },
+ { "ecaron", 556, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 722, NULL },
+ { "greater", 584, NULL },
+ { "atilde", 556, NULL },
+ { "brokenbar", 280, NULL },
+ { "quoteleft", 278, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 333, NULL }
+};
+
+static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 278, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 584, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
+ { "asciitilde", 584, NULL },
+ { "colon", 278, NULL },
+ { "onehalf", 834, NULL },
+ { "dollar", 556, NULL },
+ { "Lcaron", 556, NULL },
+ { "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
+ { "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
+ { "yen", 556, NULL },
+ { "space", 278, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 611, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 667, NULL },
+ { "three", 556, NULL },
+ { "numbersign", 556, NULL },
+ { "lcaron", 299, NULL },
+ { "A", 667, NULL },
+ { "B", 667, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 556, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 834, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 722, NULL },
+ { "I", 278, NULL },
+ { "J", 500, NULL },
+ { "K", 667, NULL },
+ { "iogonek", 222, NULL },
+ { "backslash", 278, NULL },
+ { "L", 556, NULL },
+ { "periodcentered", 278, NULL },
+ { "M", 833, NULL },
+ { "N", 722, NULL },
+ { "omacron", 556, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 778, NULL },
+ { "P", 667, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 667, NULL },
+ { "caron", 333, NULL },
+ { "S", 667, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 556, NULL },
+ { "V", 667, NULL },
+ { "W", 944, NULL },
+ { "X", 667, NULL },
+ { "question", 556, NULL },
+ { "equal", 584, NULL },
+ { "Y", 667, NULL },
+ { "Z", 611, NULL },
+ { "four", 556, NULL },
+ { "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 556, NULL },
+ { "c", 500, NULL },
+ { "d", 556, NULL },
+ { "e", 556, NULL },
+ { "f", 278, NULL },
+ { "g", 556, NULL },
+ { "bullet", 350, NULL },
+ { "h", 556, NULL },
+ { "i", 222, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 556, NULL },
+ { "j", 222, NULL },
+ { "k", 500, NULL },
+ { "l", 222, NULL },
+ { "m", 833, NULL },
+ { "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 556, NULL },
+ { "ordfeminine", 370, NULL },
+ { "ring", 333, NULL },
+ { "p", 556, NULL },
+ { "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
+ { "r", 333, NULL },
+ { "twosuperior", 333, NULL },
+ { "aacute", 556, NULL },
+ { "s", 500, NULL },
+ { "OE", 1000, NULL },
+ { "t", 278, NULL },
+ { "divide", 584, NULL },
+ { "u", 556, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 500, NULL },
+ { "w", 722, NULL },
+ { "x", 500, NULL },
+ { "y", 500, NULL },
+ { "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 355, NULL },
+ { "gcommaaccent", 556, NULL },
+ { "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 667, NULL },
+ { "Lslash", 556, NULL },
+ { "semicolon", 278, NULL },
+ { "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 500, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 556, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 556, NULL },
+ { "nacute", 556, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 500, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 222, NULL },
+ { "quotedblleft", 333, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 191, NULL },
+ { "eight", 556, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 556, NULL },
+ { "oe", 944, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 556, NULL },
+ { "Adieresis", 667, NULL },
+ { "copyright", 737, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 556, NULL },
+ { "Idieresis", 278, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 556, NULL },
+ { "emacron", 556, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
+ { "bracketleft", 278, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 222, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 667, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 556, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 556, NULL },
+ { "egrave", 556, NULL },
+ { "edieresis", 556, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 889, NULL },
+ { "asterisk", 389, NULL },
+ { "odieresis", 556, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 556, NULL },
+ { "nine", 556, NULL },
+ { "five", 556, NULL },
+ { "udieresis", 556, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
+ { "threequarters", 834, NULL },
+ { "guillemotright", 556, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
+ { "tilde", 333, NULL },
+ { "at", 1015, NULL },
+ { "eacute", 556, NULL },
+ { "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 584, NULL },
+ { "zero", 556, NULL },
+ { "eth", 556, NULL },
+ { "Scedilla", 667, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 476, NULL },
+ { "uacute", 556, NULL },
+ { "braceleft", 334, NULL },
+ { "Thorn", 667, NULL },
+ { "zcaron", 500, NULL },
+ { "scommaaccent", 500, NULL },
+ { "ccedilla", 500, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 500, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 556, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 556, NULL },
+ { "degree", 400, NULL },
+ { "registered", 737, NULL },
+ { "radical", 453, NULL },
+ { "Aring", 667, NULL },
+ { "percent", 889, NULL },
+ { "six", 556, NULL },
+ { "paragraph", 537, NULL },
+ { "dcaron", 643, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 556, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 278, NULL },
+ { "Lacute", 556, NULL },
+ { "ocircumflex", 556, NULL },
+ { "oacute", 556, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 317, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 469, NULL },
+ { "aring", 556, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 556, NULL },
+ { "bracketright", 278, NULL },
+ { "Iacute", 278, NULL },
+ { "ampersand", 667, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 222, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 584, NULL },
+ { "uring", 556, NULL },
+ { "quotesinglbase", 222, NULL },
+ { "lcommaaccent", 222, NULL },
+ { "Yacute", 667, NULL },
+ { "ohungarumlaut", 556, NULL },
+ { "threesuperior", 333, NULL },
+ { "acute", 333, NULL },
+ { "section", 556, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 333, NULL },
+ { "ncaron", 556, NULL },
+ { "florin", 556, NULL },
+ { "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 500, NULL },
+ { "fl", 500, NULL },
+ { "Acircumflex", 667, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 278, NULL },
+ { "guillemotleft", 556, NULL },
+ { "germandbls", 611, NULL },
+ { "Amacron", 667, NULL },
+ { "seven", 556, NULL },
+ { "Sacute", 667, NULL },
+ { "ordmasculine", 365, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 556, NULL },
+ { "cacute", 500, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 334, NULL },
+ { "quotedblright", 333, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 500, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 556, NULL },
+ { "currency", 556, NULL },
+ { "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
+ { "Atilde", 667, NULL },
+ { "breve", 333, NULL },
+ { "bar", 260, NULL },
+ { "fraction", 167, NULL },
+ { "less", 584, NULL },
+ { "ecaron", 556, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 278, NULL },
+ { "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 667, NULL },
+ { "greater", 584, NULL },
+ { "atilde", 556, NULL },
+ { "brokenbar", 260, NULL },
+ { "quoteleft", 222, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 333, NULL }
+};
+
+static BuiltinFontWidth symbolWidthsTab[] = {
+ { "bracketleftex", 384, NULL },
+ { "alpha", 631, NULL },
+ { "union", 768, NULL },
+ { "infinity", 713, NULL },
+ { "comma", 250, NULL },
+ { "copyrightsans", 790, NULL },
+ { "plusminus", 549, NULL },
+ { "arrowup", 603, NULL },
+ { "apple", 790, NULL },
+ { "parenleftbt", 384, NULL },
+ { "notelement", 713, NULL },
+ { "colon", 278, NULL },
+ { "beta", 549, NULL },
+ { "braceleftbt", 494, NULL },
+ { "Lambda", 686, NULL },
+ { "Phi", 763, NULL },
+ { "minus", 549, NULL },
+ { "space", 250, NULL },
+ { "Sigma", 592, NULL },
+ { "approxequal", 549, NULL },
+ { "minute", 247, NULL },
+ { "circleplus", 768, NULL },
+ { "Omicron", 722, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lambda", 549, NULL },
+ { "phi", 521, NULL },
+ { "aleph", 823, NULL },
+ { "Tau", 611, NULL },
+ { "spade", 753, NULL },
+ { "logicaland", 603, NULL },
+ { "sigma", 603, NULL },
+ { "propersuperset", 713, NULL },
+ { "omicron", 549, NULL },
+ { "question", 444, NULL },
+ { "equal", 549, NULL },
+ { "Epsilon", 611, NULL },
+ { "emptyset", 823, NULL },
+ { "diamond", 753, NULL },
+ { "four", 500, NULL },
+ { "Mu", 889, NULL },
+ { "parenlefttp", 384, NULL },
+ { "club", 753, NULL },
+ { "bullet", 460, NULL },
+ { "Omega", 768, NULL },
+ { "tau", 439, NULL },
+ { "Upsilon", 690, NULL },
+ { "bracelefttp", 494, NULL },
+ { "heart", 753, NULL },
+ { "divide", 549, NULL },
+ { "epsilon", 439, NULL },
+ { "logicalor", 603, NULL },
+ { "parenleftex", 384, NULL },
+ { "greaterequal", 549, NULL },
+ { "mu", 576, NULL },
+ { "Nu", 722, NULL },
+ { "therefore", 863, NULL },
+ { "notsubset", 713, NULL },
+ { "omega", 686, NULL },
+ { "semicolon", 278, NULL },
+ { "element", 713, NULL },
+ { "upsilon", 576, NULL },
+ { "existential", 549, NULL },
+ { "integralbt", 686, NULL },
+ { "lessequal", 549, NULL },
+ { "phi1", 603, NULL },
+ { "lozenge", 494, NULL },
+ { "trademarkserif", 890, NULL },
+ { "parenright", 333, NULL },
+ { "reflexsuperset", 713, NULL },
+ { "sigma1", 439, NULL },
+ { "nu", 521, NULL },
+ { "Gamma", 603, NULL },
+ { "angleright", 329, NULL },
+ { "ellipsis", 1000, NULL },
+ { "Rho", 556, NULL },
+ { "parenrightbt", 384, NULL },
+ { "radicalex", 500, NULL },
+ { "eight", 500, NULL },
+ { "angleleft", 329, NULL },
+ { "arrowdbldown", 603, NULL },
+ { "congruent", 549, NULL },
+ { "Theta", 741, NULL },
+ { "intersection", 768, NULL },
+ { "Pi", 768, NULL },
+ { "slash", 278, NULL },
+ { "registerserif", 790, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "gamma", 411, NULL },
+ { "bracketleft", 333, NULL },
+ { "rho", 549, NULL },
+ { "circlemultiply", 768, NULL },
+ { "Chi", 722, NULL },
+ { "theta", 521, NULL },
+ { "pi", 549, NULL },
+ { "integraltp", 686, NULL },
+ { "Eta", 722, NULL },
+ { "product", 823, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "propersubset", 713, NULL },
+ { "bracketrightbt", 384, NULL },
+ { "trademarksans", 786, NULL },
+ { "dotmath", 250, NULL },
+ { "integralex", 686, NULL },
+ { "chi", 549, NULL },
+ { "parenrighttp", 384, NULL },
+ { "eta", 603, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 750, NULL },
+ { "multiply", 549, NULL },
+ { "zero", 500, NULL },
+ { "partialdiff", 494, NULL },
+ { "angle", 768, NULL },
+ { "arrowdblleft", 987, NULL },
+ { "braceleft", 480, NULL },
+ { "parenrightex", 384, NULL },
+ { "Rfraktur", 795, NULL },
+ { "Zeta", 611, NULL },
+ { "braceex", 494, NULL },
+ { "arrowdblup", 603, NULL },
+ { "arrowdown", 603, NULL },
+ { "Ifraktur", 686, NULL },
+ { "degree", 400, NULL },
+ { "Iota", 333, NULL },
+ { "perpendicular", 658, NULL },
+ { "radical", 549, NULL },
+ { "asteriskmath", 500, NULL },
+ { "percent", 833, NULL },
+ { "zeta", 494, NULL },
+ { "six", 500, NULL },
+ { "two", 500, NULL },
+ { "weierstrass", 987, NULL },
+ { "summation", 713, NULL },
+ { "bracketrighttp", 384, NULL },
+ { "carriagereturn", 658, NULL },
+ { "suchthat", 439, NULL },
+ { "arrowvertex", 603, NULL },
+ { "Delta", 612, NULL },
+ { "iota", 329, NULL },
+ { "arrowhorizex", 1000, NULL },
+ { "bracketrightex", 384, NULL },
+ { "bracketright", 333, NULL },
+ { "ampersand", 778, NULL },
+ { "plus", 549, NULL },
+ { "proportional", 713, NULL },
+ { "delta", 494, NULL },
+ { "copyrightserif", 790, NULL },
+ { "bracerightmid", 494, NULL },
+ { "arrowleft", 987, NULL },
+ { "second", 411, NULL },
+ { "arrowdblboth", 1042, NULL },
+ { "florin", 500, NULL },
+ { "Psi", 795, NULL },
+ { "bracerightbt", 494, NULL },
+ { "bracketleftbt", 384, NULL },
+ { "seven", 500, NULL },
+ { "braceleftmid", 494, NULL },
+ { "notequal", 549, NULL },
+ { "psi", 686, NULL },
+ { "equivalence", 549, NULL },
+ { "universal", 713, NULL },
+ { "arrowdblright", 987, NULL },
+ { "braceright", 480, NULL },
+ { "reflexsubset", 713, NULL },
+ { "Xi", 645, NULL },
+ { "theta1", 631, NULL },
+ { "logicalnot", 713, NULL },
+ { "Kappa", 722, NULL },
+ { "similar", 549, NULL },
+ { "bar", 200, NULL },
+ { "fraction", 167, NULL },
+ { "less", 549, NULL },
+ { "registersans", 790, NULL },
+ { "omega1", 713, NULL },
+ { "exclam", 333, NULL },
+ { "Upsilon1", 620, NULL },
+ { "bracerighttp", 494, NULL },
+ { "xi", 493, NULL },
+ { "period", 250, NULL },
+ { "Alpha", 722, NULL },
+ { "arrowright", 987, NULL },
+ { "greater", 549, NULL },
+ { "bracketlefttp", 384, NULL },
+ { "kappa", 549, NULL },
+ { "gradient", 713, NULL },
+ { "integral", 274, NULL },
+ { "arrowboth", 1042, NULL },
+ { "Beta", 667, NULL }
+};
+
+static BuiltinFontWidth timesBoldWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 444, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 667, NULL },
+ { "comma", 250, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 570, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
+ { "asciitilde", 520, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 750, NULL },
+ { "dollar", 500, NULL },
+ { "Lcaron", 667, NULL },
+ { "ntilde", 556, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 556, NULL },
+ { "minus", 570, NULL },
+ { "Iogonek", 389, NULL },
+ { "zacute", 444, NULL },
+ { "yen", 500, NULL },
+ { "space", 250, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 500, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 722, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lcaron", 394, NULL },
+ { "A", 722, NULL },
+ { "B", 667, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 500, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 750, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 778, NULL },
+ { "I", 389, NULL },
+ { "J", 500, NULL },
+ { "K", 778, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 667, NULL },
+ { "periodcentered", 250, NULL },
+ { "M", 944, NULL },
+ { "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 667, NULL },
+ { "O", 778, NULL },
+ { "P", 611, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 722, NULL },
+ { "caron", 333, NULL },
+ { "S", 556, NULL },
+ { "T", 667, NULL },
+ { "U", 722, NULL },
+ { "agrave", 500, NULL },
+ { "V", 722, NULL },
+ { "W", 1000, NULL },
+ { "X", 722, NULL },
+ { "question", 500, NULL },
+ { "equal", 570, NULL },
+ { "Y", 722, NULL },
+ { "Z", 667, NULL },
+ { "four", 500, NULL },
+ { "a", 500, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 556, NULL },
+ { "c", 444, NULL },
+ { "d", 556, NULL },
+ { "e", 444, NULL },
+ { "f", 333, NULL },
+ { "g", 500, NULL },
+ { "bullet", 350, NULL },
+ { "h", 556, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 500, NULL },
+ { "j", 333, NULL },
+ { "k", 556, NULL },
+ { "l", 278, NULL },
+ { "m", 833, NULL },
+ { "n", 556, NULL },
+ { "tcommaaccent", 333, NULL },
+ { "o", 500, NULL },
+ { "ordfeminine", 300, NULL },
+ { "ring", 333, NULL },
+ { "p", 556, NULL },
+ { "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
+ { "r", 444, NULL },
+ { "twosuperior", 300, NULL },
+ { "aacute", 500, NULL },
+ { "s", 389, NULL },
+ { "OE", 1000, NULL },
+ { "t", 333, NULL },
+ { "divide", 570, NULL },
+ { "u", 556, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 500, NULL },
+ { "w", 722, NULL },
+ { "x", 500, NULL },
+ { "y", 500, NULL },
+ { "z", 444, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 389, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 555, NULL },
+ { "gcommaaccent", 500, NULL },
+ { "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 556, NULL },
+ { "Lslash", 667, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 500, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 500, NULL },
+ { "nacute", 556, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 389, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 500, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 278, NULL },
+ { "eight", 500, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 500, NULL },
+ { "oe", 722, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 444, NULL },
+ { "Adieresis", 722, NULL },
+ { "copyright", 747, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 500, NULL },
+ { "Idieresis", 389, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "emacron", 444, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 333, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 722, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 500, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 500, NULL },
+ { "egrave", 444, NULL },
+ { "edieresis", 444, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 722, NULL },
+ { "asterisk", 500, NULL },
+ { "odieresis", 500, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 556, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "udieresis", 556, NULL },
+ { "Zcaron", 667, NULL },
+ { "Scommaaccent", 556, NULL },
+ { "threequarters", 750, NULL },
+ { "guillemotright", 500, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
+ { "tilde", 333, NULL },
+ { "at", 930, NULL },
+ { "eacute", 444, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 570, NULL },
+ { "zero", 500, NULL },
+ { "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
+ { "uacute", 556, NULL },
+ { "braceleft", 394, NULL },
+ { "Thorn", 611, NULL },
+ { "zcaron", 444, NULL },
+ { "scommaaccent", 389, NULL },
+ { "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 389, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 500, NULL },
+ { "racute", 444, NULL },
+ { "Tcaron", 667, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 556, NULL },
+ { "degree", 400, NULL },
+ { "registered", 747, NULL },
+ { "radical", 549, NULL },
+ { "Aring", 722, NULL },
+ { "percent", 1000, NULL },
+ { "six", 500, NULL },
+ { "paragraph", 540, NULL },
+ { "dcaron", 672, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 500, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 389, NULL },
+ { "Lacute", 667, NULL },
+ { "ocircumflex", 500, NULL },
+ { "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 667, NULL },
+ { "tcaron", 416, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 581, NULL },
+ { "aring", 500, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 556, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 389, NULL },
+ { "ampersand", 833, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 570, NULL },
+ { "uring", 556, NULL },
+ { "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 722, NULL },
+ { "ohungarumlaut", 500, NULL },
+ { "threesuperior", 300, NULL },
+ { "acute", 333, NULL },
+ { "section", 500, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 500, NULL },
+ { "ncaron", 556, NULL },
+ { "florin", 500, NULL },
+ { "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 556, NULL },
+ { "fl", 556, NULL },
+ { "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 389, NULL },
+ { "guillemotleft", 500, NULL },
+ { "germandbls", 556, NULL },
+ { "Amacron", 722, NULL },
+ { "seven", 500, NULL },
+ { "Sacute", 556, NULL },
+ { "ordmasculine", 330, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 389, NULL },
+ { "rcommaaccent", 444, NULL },
+ { "Zdotaccent", 667, NULL },
+ { "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 394, NULL },
+ { "quotedblright", 500, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 500, NULL },
+ { "currency", 500, NULL },
+ { "logicalnot", 570, NULL },
+ { "zdotaccent", 444, NULL },
+ { "Atilde", 722, NULL },
+ { "breve", 333, NULL },
+ { "bar", 220, NULL },
+ { "fraction", 167, NULL },
+ { "less", 570, NULL },
+ { "ecaron", 444, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 250, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 778, NULL },
+ { "greater", 570, NULL },
+ { "atilde", 500, NULL },
+ { "brokenbar", 220, NULL },
+ { "quoteleft", 333, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 300, NULL }
+};
+
+static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 250, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 570, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
+ { "asciitilde", 570, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 750, NULL },
+ { "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
+ { "minus", 606, NULL },
+ { "Iogonek", 389, NULL },
+ { "zacute", 389, NULL },
+ { "yen", 500, NULL },
+ { "space", 250, NULL },
+ { "Omacron", 722, NULL },
+ { "questiondown", 500, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 667, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lcaron", 382, NULL },
+ { "A", 667, NULL },
+ { "B", 667, NULL },
+ { "C", 667, NULL },
+ { "aogonek", 500, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 750, NULL },
+ { "F", 667, NULL },
+ { "G", 722, NULL },
+ { "H", 778, NULL },
+ { "I", 389, NULL },
+ { "J", 500, NULL },
+ { "K", 667, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 611, NULL },
+ { "periodcentered", 250, NULL },
+ { "M", 889, NULL },
+ { "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 722, NULL },
+ { "P", 611, NULL },
+ { "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 667, NULL },
+ { "Aacute", 667, NULL },
+ { "caron", 333, NULL },
+ { "S", 556, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 500, NULL },
+ { "V", 667, NULL },
+ { "W", 889, NULL },
+ { "X", 667, NULL },
+ { "question", 500, NULL },
+ { "equal", 570, NULL },
+ { "Y", 611, NULL },
+ { "Z", 611, NULL },
+ { "four", 500, NULL },
+ { "a", 500, NULL },
+ { "Gcommaaccent", 722, NULL },
+ { "b", 500, NULL },
+ { "c", 444, NULL },
+ { "d", 500, NULL },
+ { "e", 444, NULL },
+ { "f", 333, NULL },
+ { "g", 500, NULL },
+ { "bullet", 350, NULL },
+ { "h", 556, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 722, NULL },
+ { "dagger", 500, NULL },
+ { "j", 278, NULL },
+ { "k", 500, NULL },
+ { "l", 278, NULL },
+ { "m", 778, NULL },
+ { "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 500, NULL },
+ { "ordfeminine", 266, NULL },
+ { "ring", 333, NULL },
+ { "p", 500, NULL },
+ { "q", 500, NULL },
+ { "uhungarumlaut", 556, NULL },
+ { "r", 389, NULL },
+ { "twosuperior", 300, NULL },
+ { "aacute", 500, NULL },
+ { "s", 389, NULL },
+ { "OE", 944, NULL },
+ { "t", 278, NULL },
+ { "divide", 570, NULL },
+ { "u", 556, NULL },
+ { "Ccaron", 667, NULL },
+ { "v", 444, NULL },
+ { "w", 667, NULL },
+ { "x", 500, NULL },
+ { "y", 444, NULL },
+ { "z", 389, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 389, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 555, NULL },
+ { "gcommaaccent", 500, NULL },
+ { "mu", 576, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 556, NULL },
+ { "Lslash", 611, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 500, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 500, NULL },
+ { "nacute", 556, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 722, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 389, NULL },
+ { "AE", 944, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 500, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 278, NULL },
+ { "eight", 500, NULL },
+ { "exclamdown", 389, NULL },
+ { "endash", 500, NULL },
+ { "oe", 722, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 444, NULL },
+ { "Adieresis", 667, NULL },
+ { "copyright", 747, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 500, NULL },
+ { "Idieresis", 389, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "emacron", 444, NULL },
+ { "Odieresis", 722, NULL },
+ { "ucircumflex", 556, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 333, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 611, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 500, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 500, NULL },
+ { "egrave", 444, NULL },
+ { "edieresis", 444, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 722, NULL },
+ { "asterisk", 500, NULL },
+ { "odieresis", 500, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 556, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "udieresis", 556, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 556, NULL },
+ { "threequarters", 750, NULL },
+ { "guillemotright", 500, NULL },
+ { "Ccedilla", 667, NULL },
+ { "ydieresis", 444, NULL },
+ { "tilde", 333, NULL },
+ { "at", 832, NULL },
+ { "eacute", 444, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 570, NULL },
+ { "zero", 500, NULL },
+ { "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
+ { "Ograve", 722, NULL },
+ { "Racute", 667, NULL },
+ { "partialdiff", 494, NULL },
+ { "uacute", 556, NULL },
+ { "braceleft", 348, NULL },
+ { "Thorn", 611, NULL },
+ { "zcaron", 389, NULL },
+ { "scommaaccent", 389, NULL },
+ { "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
+ { "Ocircumflex", 722, NULL },
+ { "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 500, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 500, NULL },
+ { "degree", 400, NULL },
+ { "registered", 747, NULL },
+ { "radical", 549, NULL },
+ { "Aring", 667, NULL },
+ { "percent", 833, NULL },
+ { "six", 500, NULL },
+ { "paragraph", 500, NULL },
+ { "dcaron", 608, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 500, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 389, NULL },
+ { "Lacute", 611, NULL },
+ { "ocircumflex", 500, NULL },
+ { "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 366, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
+ { "asciicircum", 570, NULL },
+ { "aring", 500, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 556, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 389, NULL },
+ { "ampersand", 778, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 570, NULL },
+ { "uring", 556, NULL },
+ { "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 611, NULL },
+ { "ohungarumlaut", 500, NULL },
+ { "threesuperior", 300, NULL },
+ { "acute", 333, NULL },
+ { "section", 500, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 500, NULL },
+ { "ncaron", 556, NULL },
+ { "florin", 500, NULL },
+ { "yacute", 444, NULL },
+ { "Rcommaaccent", 667, NULL },
+ { "fi", 556, NULL },
+ { "fl", 556, NULL },
+ { "Acircumflex", 667, NULL },
+ { "Cacute", 667, NULL },
+ { "Icircumflex", 389, NULL },
+ { "guillemotleft", 500, NULL },
+ { "germandbls", 500, NULL },
+ { "Amacron", 667, NULL },
+ { "seven", 500, NULL },
+ { "Sacute", 556, NULL },
+ { "ordmasculine", 300, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 389, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 348, NULL },
+ { "quotedblright", 500, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 500, NULL },
+ { "currency", 500, NULL },
+ { "logicalnot", 606, NULL },
+ { "zdotaccent", 389, NULL },
+ { "Atilde", 667, NULL },
+ { "breve", 333, NULL },
+ { "bar", 220, NULL },
+ { "fraction", 167, NULL },
+ { "less", 570, NULL },
+ { "ecaron", 444, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 389, NULL },
+ { "period", 250, NULL },
+ { "Rcaron", 667, NULL },
+ { "Kcommaaccent", 667, NULL },
+ { "greater", 570, NULL },
+ { "atilde", 500, NULL },
+ { "brokenbar", 220, NULL },
+ { "quoteleft", 333, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 300, NULL }
+};
+
+static BuiltinFontWidth timesItalicWidthsTab[] = {
+ { "Ntilde", 667, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 444, NULL },
+ { "Ncommaaccent", 667, NULL },
+ { "Zacute", 556, NULL },
+ { "comma", 250, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 675, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
+ { "asciitilde", 541, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 750, NULL },
+ { "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 500, NULL },
+ { "Aogonek", 611, NULL },
+ { "ncommaaccent", 500, NULL },
+ { "minus", 675, NULL },
+ { "Iogonek", 333, NULL },
+ { "zacute", 389, NULL },
+ { "yen", 500, NULL },
+ { "space", 250, NULL },
+ { "Omacron", 722, NULL },
+ { "questiondown", 500, NULL },
+ { "emdash", 889, NULL },
+ { "Agrave", 611, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lcaron", 300, NULL },
+ { "A", 611, NULL },
+ { "B", 611, NULL },
+ { "C", 667, NULL },
+ { "aogonek", 500, NULL },
+ { "D", 722, NULL },
+ { "E", 611, NULL },
+ { "onequarter", 750, NULL },
+ { "F", 611, NULL },
+ { "G", 722, NULL },
+ { "H", 722, NULL },
+ { "I", 333, NULL },
+ { "J", 444, NULL },
+ { "K", 667, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 556, NULL },
+ { "periodcentered", 250, NULL },
+ { "M", 833, NULL },
+ { "N", 667, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 556, NULL },
+ { "O", 722, NULL },
+ { "P", 611, NULL },
+ { "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 611, NULL },
+ { "Aacute", 611, NULL },
+ { "caron", 333, NULL },
+ { "S", 500, NULL },
+ { "T", 556, NULL },
+ { "U", 722, NULL },
+ { "agrave", 500, NULL },
+ { "V", 611, NULL },
+ { "W", 833, NULL },
+ { "X", 611, NULL },
+ { "question", 500, NULL },
+ { "equal", 675, NULL },
+ { "Y", 556, NULL },
+ { "Z", 556, NULL },
+ { "four", 500, NULL },
+ { "a", 500, NULL },
+ { "Gcommaaccent", 722, NULL },
+ { "b", 500, NULL },
+ { "c", 444, NULL },
+ { "d", 500, NULL },
+ { "e", 444, NULL },
+ { "f", 278, NULL },
+ { "g", 500, NULL },
+ { "bullet", 350, NULL },
+ { "h", 500, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 722, NULL },
+ { "dagger", 500, NULL },
+ { "j", 278, NULL },
+ { "k", 444, NULL },
+ { "l", 278, NULL },
+ { "m", 722, NULL },
+ { "n", 500, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 500, NULL },
+ { "ordfeminine", 276, NULL },
+ { "ring", 333, NULL },
+ { "p", 500, NULL },
+ { "q", 500, NULL },
+ { "uhungarumlaut", 500, NULL },
+ { "r", 389, NULL },
+ { "twosuperior", 300, NULL },
+ { "aacute", 500, NULL },
+ { "s", 389, NULL },
+ { "OE", 944, NULL },
+ { "t", 278, NULL },
+ { "divide", 675, NULL },
+ { "u", 500, NULL },
+ { "Ccaron", 667, NULL },
+ { "v", 444, NULL },
+ { "w", 667, NULL },
+ { "x", 444, NULL },
+ { "y", 444, NULL },
+ { "z", 389, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 333, NULL },
+ { "Nacute", 667, NULL },
+ { "quotedbl", 420, NULL },
+ { "gcommaaccent", 500, NULL },
+ { "mu", 500, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 500, NULL },
+ { "Lslash", 556, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
+ { "Ecircumflex", 611, NULL },
+ { "gbreve", 500, NULL },
+ { "trademark", 980, NULL },
+ { "daggerdbl", 500, NULL },
+ { "nacute", 500, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 722, NULL },
+ { "Emacron", 611, NULL },
+ { "ellipsis", 889, NULL },
+ { "scaron", 389, NULL },
+ { "AE", 889, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 556, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 214, NULL },
+ { "eight", 500, NULL },
+ { "exclamdown", 389, NULL },
+ { "endash", 500, NULL },
+ { "oe", 667, NULL },
+ { "Abreve", 611, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 444, NULL },
+ { "Adieresis", 611, NULL },
+ { "copyright", 760, NULL },
+ { "Egrave", 611, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 611, NULL },
+ { "otilde", 500, NULL },
+ { "Idieresis", 333, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "emacron", 444, NULL },
+ { "Odieresis", 722, NULL },
+ { "ucircumflex", 500, NULL },
+ { "bracketleft", 389, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 333, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 556, NULL },
+ { "umacron", 500, NULL },
+ { "abreve", 500, NULL },
+ { "Eacute", 611, NULL },
+ { "adieresis", 500, NULL },
+ { "egrave", 444, NULL },
+ { "edieresis", 444, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 667, NULL },
+ { "asterisk", 500, NULL },
+ { "odieresis", 500, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 500, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "udieresis", 500, NULL },
+ { "Zcaron", 556, NULL },
+ { "Scommaaccent", 500, NULL },
+ { "threequarters", 750, NULL },
+ { "guillemotright", 500, NULL },
+ { "Ccedilla", 667, NULL },
+ { "ydieresis", 444, NULL },
+ { "tilde", 333, NULL },
+ { "at", 920, NULL },
+ { "eacute", 444, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 675, NULL },
+ { "zero", 500, NULL },
+ { "eth", 500, NULL },
+ { "Scedilla", 500, NULL },
+ { "Ograve", 722, NULL },
+ { "Racute", 611, NULL },
+ { "partialdiff", 476, NULL },
+ { "uacute", 500, NULL },
+ { "braceleft", 400, NULL },
+ { "Thorn", 611, NULL },
+ { "zcaron", 389, NULL },
+ { "scommaaccent", 389, NULL },
+ { "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
+ { "Ocircumflex", 722, NULL },
+ { "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 500, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 556, NULL },
+ { "Eogonek", 611, NULL },
+ { "thorn", 500, NULL },
+ { "degree", 400, NULL },
+ { "registered", 760, NULL },
+ { "radical", 453, NULL },
+ { "Aring", 611, NULL },
+ { "percent", 833, NULL },
+ { "six", 500, NULL },
+ { "paragraph", 523, NULL },
+ { "dcaron", 544, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 500, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 333, NULL },
+ { "Lacute", 556, NULL },
+ { "ocircumflex", 500, NULL },
+ { "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 300, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
+ { "asciicircum", 422, NULL },
+ { "aring", 500, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 500, NULL },
+ { "bracketright", 389, NULL },
+ { "Iacute", 333, NULL },
+ { "ampersand", 778, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 667, NULL },
+ { "plus", 675, NULL },
+ { "uring", 500, NULL },
+ { "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 556, NULL },
+ { "ohungarumlaut", 500, NULL },
+ { "threesuperior", 300, NULL },
+ { "acute", 333, NULL },
+ { "section", 500, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 556, NULL },
+ { "ncaron", 500, NULL },
+ { "florin", 500, NULL },
+ { "yacute", 444, NULL },
+ { "Rcommaaccent", 611, NULL },
+ { "fi", 500, NULL },
+ { "fl", 500, NULL },
+ { "Acircumflex", 611, NULL },
+ { "Cacute", 667, NULL },
+ { "Icircumflex", 333, NULL },
+ { "guillemotleft", 500, NULL },
+ { "germandbls", 500, NULL },
+ { "Amacron", 611, NULL },
+ { "seven", 500, NULL },
+ { "Sacute", 500, NULL },
+ { "ordmasculine", 310, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 333, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 556, NULL },
+ { "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 611, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 400, NULL },
+ { "quotedblright", 556, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 500, NULL },
+ { "currency", 500, NULL },
+ { "logicalnot", 675, NULL },
+ { "zdotaccent", 389, NULL },
+ { "Atilde", 611, NULL },
+ { "breve", 333, NULL },
+ { "bar", 275, NULL },
+ { "fraction", 167, NULL },
+ { "less", 675, NULL },
+ { "ecaron", 444, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 250, NULL },
+ { "Rcaron", 611, NULL },
+ { "Kcommaaccent", 667, NULL },
+ { "greater", 675, NULL },
+ { "atilde", 500, NULL },
+ { "brokenbar", 275, NULL },
+ { "quoteleft", 333, NULL },
+ { "Edotaccent", 611, NULL },
+ { "onesuperior", 300, NULL }
+};
+
+static BuiltinFontWidth timesRomanWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 250, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 564, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
+ { "asciitilde", 541, NULL },
+ { "colon", 278, NULL },
+ { "onehalf", 750, NULL },
+ { "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 500, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 500, NULL },
+ { "minus", 564, NULL },
+ { "Iogonek", 333, NULL },
+ { "zacute", 444, NULL },
+ { "yen", 500, NULL },
+ { "space", 250, NULL },
+ { "Omacron", 722, NULL },
+ { "questiondown", 444, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 722, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lcaron", 344, NULL },
+ { "A", 722, NULL },
+ { "B", 667, NULL },
+ { "C", 667, NULL },
+ { "aogonek", 444, NULL },
+ { "D", 722, NULL },
+ { "E", 611, NULL },
+ { "onequarter", 750, NULL },
+ { "F", 556, NULL },
+ { "G", 722, NULL },
+ { "H", 722, NULL },
+ { "I", 333, NULL },
+ { "J", 389, NULL },
+ { "K", 722, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 611, NULL },
+ { "periodcentered", 250, NULL },
+ { "M", 889, NULL },
+ { "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 722, NULL },
+ { "P", 556, NULL },
+ { "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 667, NULL },
+ { "Aacute", 722, NULL },
+ { "caron", 333, NULL },
+ { "S", 556, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 444, NULL },
+ { "V", 722, NULL },
+ { "W", 944, NULL },
+ { "X", 722, NULL },
+ { "question", 444, NULL },
+ { "equal", 564, NULL },
+ { "Y", 722, NULL },
+ { "Z", 611, NULL },
+ { "four", 500, NULL },
+ { "a", 444, NULL },
+ { "Gcommaaccent", 722, NULL },
+ { "b", 500, NULL },
+ { "c", 444, NULL },
+ { "d", 500, NULL },
+ { "e", 444, NULL },
+ { "f", 333, NULL },
+ { "g", 500, NULL },
+ { "bullet", 350, NULL },
+ { "h", 500, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 722, NULL },
+ { "dagger", 500, NULL },
+ { "j", 278, NULL },
+ { "k", 500, NULL },
+ { "l", 278, NULL },
+ { "m", 778, NULL },
+ { "n", 500, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 500, NULL },
+ { "ordfeminine", 276, NULL },
+ { "ring", 333, NULL },
+ { "p", 500, NULL },
+ { "q", 500, NULL },
+ { "uhungarumlaut", 500, NULL },
+ { "r", 333, NULL },
+ { "twosuperior", 300, NULL },
+ { "aacute", 444, NULL },
+ { "s", 389, NULL },
+ { "OE", 889, NULL },
+ { "t", 278, NULL },
+ { "divide", 564, NULL },
+ { "u", 500, NULL },
+ { "Ccaron", 667, NULL },
+ { "v", 500, NULL },
+ { "w", 722, NULL },
+ { "x", 500, NULL },
+ { "y", 500, NULL },
+ { "z", 444, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 333, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 408, NULL },
+ { "gcommaaccent", 500, NULL },
+ { "mu", 500, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 556, NULL },
+ { "Lslash", 611, NULL },
+ { "semicolon", 278, NULL },
+ { "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
+ { "Ecircumflex", 611, NULL },
+ { "gbreve", 500, NULL },
+ { "trademark", 980, NULL },
+ { "daggerdbl", 500, NULL },
+ { "nacute", 500, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 722, NULL },
+ { "Emacron", 611, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 389, NULL },
+ { "AE", 889, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 444, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 180, NULL },
+ { "eight", 500, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 500, NULL },
+ { "oe", 722, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 444, NULL },
+ { "Adieresis", 722, NULL },
+ { "copyright", 760, NULL },
+ { "Egrave", 611, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 611, NULL },
+ { "otilde", 500, NULL },
+ { "Idieresis", 333, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "emacron", 444, NULL },
+ { "Odieresis", 722, NULL },
+ { "ucircumflex", 500, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 333, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 722, NULL },
+ { "umacron", 500, NULL },
+ { "abreve", 444, NULL },
+ { "Eacute", 611, NULL },
+ { "adieresis", 444, NULL },
+ { "egrave", 444, NULL },
+ { "edieresis", 444, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 667, NULL },
+ { "asterisk", 500, NULL },
+ { "odieresis", 500, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 500, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "udieresis", 500, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 556, NULL },
+ { "threequarters", 750, NULL },
+ { "guillemotright", 500, NULL },
+ { "Ccedilla", 667, NULL },
+ { "ydieresis", 500, NULL },
+ { "tilde", 333, NULL },
+ { "at", 921, NULL },
+ { "eacute", 444, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 564, NULL },
+ { "zero", 500, NULL },
+ { "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
+ { "Ograve", 722, NULL },
+ { "Racute", 667, NULL },
+ { "partialdiff", 476, NULL },
+ { "uacute", 500, NULL },
+ { "braceleft", 480, NULL },
+ { "Thorn", 556, NULL },
+ { "zcaron", 444, NULL },
+ { "scommaaccent", 389, NULL },
+ { "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
+ { "Ocircumflex", 722, NULL },
+ { "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 500, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 611, NULL },
+ { "thorn", 500, NULL },
+ { "degree", 400, NULL },
+ { "registered", 760, NULL },
+ { "radical", 453, NULL },
+ { "Aring", 722, NULL },
+ { "percent", 833, NULL },
+ { "six", 500, NULL },
+ { "paragraph", 453, NULL },
+ { "dcaron", 588, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 500, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 333, NULL },
+ { "Lacute", 611, NULL },
+ { "ocircumflex", 500, NULL },
+ { "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 326, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
+ { "asciicircum", 469, NULL },
+ { "aring", 444, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 500, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 333, NULL },
+ { "ampersand", 778, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 564, NULL },
+ { "uring", 500, NULL },
+ { "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 722, NULL },
+ { "ohungarumlaut", 500, NULL },
+ { "threesuperior", 300, NULL },
+ { "acute", 333, NULL },
+ { "section", 500, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 444, NULL },
+ { "ncaron", 500, NULL },
+ { "florin", 500, NULL },
+ { "yacute", 500, NULL },
+ { "Rcommaaccent", 667, NULL },
+ { "fi", 556, NULL },
+ { "fl", 556, NULL },
+ { "Acircumflex", 722, NULL },
+ { "Cacute", 667, NULL },
+ { "Icircumflex", 333, NULL },
+ { "guillemotleft", 500, NULL },
+ { "germandbls", 500, NULL },
+ { "Amacron", 722, NULL },
+ { "seven", 500, NULL },
+ { "Sacute", 556, NULL },
+ { "ordmasculine", 310, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 333, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 444, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 611, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 480, NULL },
+ { "quotedblright", 444, NULL },
+ { "amacron", 444, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 500, NULL },
+ { "currency", 500, NULL },
+ { "logicalnot", 564, NULL },
+ { "zdotaccent", 444, NULL },
+ { "Atilde", 722, NULL },
+ { "breve", 333, NULL },
+ { "bar", 200, NULL },
+ { "fraction", 167, NULL },
+ { "less", 564, NULL },
+ { "ecaron", 444, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 250, NULL },
+ { "Rcaron", 667, NULL },
+ { "Kcommaaccent", 722, NULL },
+ { "greater", 564, NULL },
+ { "atilde", 444, NULL },
+ { "brokenbar", 200, NULL },
+ { "quoteleft", 333, NULL },
+ { "Edotaccent", 611, NULL },
+ { "onesuperior", 300, NULL }
+};
+
+static BuiltinFontWidth zapfDingbatsWidthsTab[] = {
+ { "a81", 438, NULL },
+ { "a82", 138, NULL },
+ { "a83", 277, NULL },
+ { "a84", 415, NULL },
+ { "a85", 509, NULL },
+ { "a86", 410, NULL },
+ { "a87", 234, NULL },
+ { "a88", 234, NULL },
+ { "a89", 390, NULL },
+ { "a140", 788, NULL },
+ { "a141", 788, NULL },
+ { "a142", 788, NULL },
+ { "a143", 788, NULL },
+ { "a144", 788, NULL },
+ { "a145", 788, NULL },
+ { "a146", 788, NULL },
+ { "a147", 788, NULL },
+ { "a148", 788, NULL },
+ { "a149", 788, NULL },
+ { "a90", 390, NULL },
+ { "a91", 276, NULL },
+ { "a92", 276, NULL },
+ { "space", 278, NULL },
+ { "a93", 317, NULL },
+ { "a94", 317, NULL },
+ { "a95", 334, NULL },
+ { "a96", 334, NULL },
+ { "a97", 392, NULL },
+ { "a98", 392, NULL },
+ { "a99", 668, NULL },
+ { "a150", 788, NULL },
+ { "a151", 788, NULL },
+ { "a152", 788, NULL },
+ { "a153", 788, NULL },
+ { "a154", 788, NULL },
+ { "a155", 788, NULL },
+ { "a156", 788, NULL },
+ { "a157", 788, NULL },
+ { "a158", 788, NULL },
+ { "a159", 788, NULL },
+ { "a160", 894, NULL },
+ { "a161", 838, NULL },
+ { "a162", 924, NULL },
+ { "a163", 1016, NULL },
+ { "a164", 458, NULL },
+ { "a165", 924, NULL },
+ { "a166", 918, NULL },
+ { "a167", 927, NULL },
+ { "a168", 928, NULL },
+ { "a169", 928, NULL },
+ { "a170", 834, NULL },
+ { "a171", 873, NULL },
+ { "a172", 828, NULL },
+ { "a173", 924, NULL },
+ { "a174", 917, NULL },
+ { "a175", 930, NULL },
+ { "a176", 931, NULL },
+ { "a177", 463, NULL },
+ { "a178", 883, NULL },
+ { "a179", 836, NULL },
+ { "a180", 867, NULL },
+ { "a181", 696, NULL },
+ { "a182", 874, NULL },
+ { "a183", 760, NULL },
+ { "a184", 946, NULL },
+ { "a185", 865, NULL },
+ { "a186", 967, NULL },
+ { "a187", 831, NULL },
+ { "a188", 873, NULL },
+ { "a189", 927, NULL },
+ { "a1", 974, NULL },
+ { "a2", 961, NULL },
+ { "a3", 980, NULL },
+ { "a4", 719, NULL },
+ { "a5", 789, NULL },
+ { "a6", 494, NULL },
+ { "a7", 552, NULL },
+ { "a8", 537, NULL },
+ { "a9", 577, NULL },
+ { "a190", 970, NULL },
+ { "a191", 918, NULL },
+ { "a192", 748, NULL },
+ { "a193", 836, NULL },
+ { "a194", 771, NULL },
+ { "a195", 888, NULL },
+ { "a196", 748, NULL },
+ { "a197", 771, NULL },
+ { "a198", 888, NULL },
+ { "a199", 867, NULL },
+ { "a10", 692, NULL },
+ { "a11", 960, NULL },
+ { "a12", 939, NULL },
+ { "a13", 549, NULL },
+ { "a14", 855, NULL },
+ { "a15", 911, NULL },
+ { "a16", 933, NULL },
+ { "a17", 945, NULL },
+ { "a18", 974, NULL },
+ { "a19", 755, NULL },
+ { "a20", 846, NULL },
+ { "a21", 762, NULL },
+ { "a22", 761, NULL },
+ { "a23", 571, NULL },
+ { "a24", 677, NULL },
+ { "a25", 763, NULL },
+ { "a26", 760, NULL },
+ { "a27", 759, NULL },
+ { "a28", 754, NULL },
+ { "a29", 786, NULL },
+ { "a30", 788, NULL },
+ { "a31", 788, NULL },
+ { "a32", 790, NULL },
+ { "a33", 793, NULL },
+ { "a34", 794, NULL },
+ { "a35", 816, NULL },
+ { "a36", 823, NULL },
+ { "a37", 789, NULL },
+ { "a38", 841, NULL },
+ { "a39", 823, NULL },
+ { "a40", 833, NULL },
+ { "a41", 816, NULL },
+ { "a42", 831, NULL },
+ { "a43", 923, NULL },
+ { "a44", 744, NULL },
+ { "a45", 723, NULL },
+ { "a46", 749, NULL },
+ { "a47", 790, NULL },
+ { "a48", 792, NULL },
+ { "a49", 695, NULL },
+ { "a100", 668, NULL },
+ { "a101", 732, NULL },
+ { "a102", 544, NULL },
+ { "a103", 544, NULL },
+ { "a104", 910, NULL },
+ { "a105", 911, NULL },
+ { "a106", 667, NULL },
+ { "a107", 760, NULL },
+ { "a108", 760, NULL },
+ { "a109", 626, NULL },
+ { "a50", 776, NULL },
+ { "a51", 768, NULL },
+ { "a52", 792, NULL },
+ { "a53", 759, NULL },
+ { "a54", 707, NULL },
+ { "a55", 708, NULL },
+ { "a56", 682, NULL },
+ { "a57", 701, NULL },
+ { "a58", 826, NULL },
+ { "a59", 815, NULL },
+ { "a110", 694, NULL },
+ { "a111", 595, NULL },
+ { "a112", 776, NULL },
+ { "a117", 690, NULL },
+ { "a118", 791, NULL },
+ { "a119", 790, NULL },
+ { "a60", 789, NULL },
+ { "a61", 789, NULL },
+ { "a62", 707, NULL },
+ { "a63", 687, NULL },
+ { "a64", 696, NULL },
+ { "a65", 689, NULL },
+ { "a66", 786, NULL },
+ { "a67", 787, NULL },
+ { "a68", 713, NULL },
+ { "a69", 791, NULL },
+ { "a200", 696, NULL },
+ { "a201", 874, NULL },
+ { "a120", 788, NULL },
+ { "a121", 788, NULL },
+ { "a202", 974, NULL },
+ { "a122", 788, NULL },
+ { "a203", 762, NULL },
+ { "a123", 788, NULL },
+ { "a204", 759, NULL },
+ { "a124", 788, NULL },
+ { "a205", 509, NULL },
+ { "a125", 788, NULL },
+ { "a206", 410, NULL },
+ { "a126", 788, NULL },
+ { "a127", 788, NULL },
+ { "a128", 788, NULL },
+ { "a129", 788, NULL },
+ { "a70", 785, NULL },
+ { "a71", 791, NULL },
+ { "a72", 873, NULL },
+ { "a73", 761, NULL },
+ { "a74", 762, NULL },
+ { "a75", 759, NULL },
+ { "a76", 892, NULL },
+ { "a77", 892, NULL },
+ { "a78", 788, NULL },
+ { "a79", 784, NULL },
+ { "a130", 788, NULL },
+ { "a131", 788, NULL },
+ { "a132", 788, NULL },
+ { "a133", 788, NULL },
+ { "a134", 788, NULL },
+ { "a135", 788, NULL },
+ { "a136", 788, NULL },
+ { "a137", 788, NULL },
+ { "a138", 788, NULL },
+ { "a139", 788, NULL }
+};
+
+BuiltinFont builtinFonts[] = {
+ { "Courier", standardEncoding, 629, -157, { -23, -250, 715, 805}, NULL },
+ { "Courier-Bold", standardEncoding, 629, -157, {-113, -250, 749, 801}, NULL },
+ { "Courier-BoldOblique", standardEncoding, 629, -157, { -57, -250, 869, 801}, NULL },
+ { "Courier-Oblique", standardEncoding, 629, -157, { -27, -250, 849, 805}, NULL },
+ { "Helvetica", standardEncoding, 718, -207, {-166, -225, 1000, 931}, NULL },
+ { "Helvetica-Bold", standardEncoding, 718, -207, {-170, -228, 1003, 962}, NULL },
+ { "Helvetica-BoldOblique", standardEncoding, 718, -207, {-174, -228, 1114, 962}, NULL },
+ { "Helvetica-Oblique", standardEncoding, 718, -207, {-170, -225, 1116, 931}, NULL },
+ { "Symbol", symbolEncoding, 1010, -293, {-180, -293, 1090, 1010}, NULL },
+ { "Times-Bold", standardEncoding, 683, -217, {-168, -218, 1000, 935}, NULL },
+ { "Times-BoldItalic", standardEncoding, 683, -217, {-200, -218, 996, 921}, NULL },
+ { "Times-Italic", standardEncoding, 683, -217, {-169, -217, 1010, 883}, NULL },
+ { "Times-Roman", standardEncoding, 683, -217, {-168, -218, 1000, 898}, NULL },
+ { "ZapfDingbats", zapfDingbatsEncoding, 820, -143, { -1, -143, 981, 820}, NULL }
+};
+
+BuiltinFont *builtinFontSubst[] = {
+ &builtinFonts[0],
+ &builtinFonts[3],
+ &builtinFonts[1],
+ &builtinFonts[2],
+ &builtinFonts[4],
+ &builtinFonts[7],
+ &builtinFonts[5],
+ &builtinFonts[6],
+ &builtinFonts[12],
+ &builtinFonts[11],
+ &builtinFonts[9],
+ &builtinFonts[10]
+};
+
+void initBuiltinFontTables() {
+ builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 315);
+ builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 315);
+ builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 315);
+ builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 315);
+ builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 315);
+ builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 316);
+ builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 315);
+ builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 315);
+ builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 190);
+ builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 315);
+ builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 315);
+ builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 315);
+ builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 315);
+ builtinFonts[13].widths = new BuiltinFontWidths(zapfDingbatsWidthsTab, 202);
+}
+
+void freeBuiltinFontTables() {
+ int i;
+
+ for (i = 0; i < 14; ++i) {
+ delete builtinFonts[i].widths;
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFontTables.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFontTables.h
new file mode 100644
index 00000000000..eb45549efd2
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/BuiltinFontTables.h
@@ -0,0 +1,23 @@
+//========================================================================
+//
+// BuiltinFontTables.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef BUILTINFONTTABLES_H
+#define BUILTINFONTTABLES_H
+
+#include "BuiltinFont.h"
+
+#define nBuiltinFonts 14
+#define nBuiltinFontSubsts 12
+
+extern BuiltinFont builtinFonts[nBuiltinFonts];
+extern BuiltinFont *builtinFontSubst[nBuiltinFontSubsts];
+
+extern void initBuiltinFontTables();
+extern void freeBuiltinFontTables();
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CMap.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/CMap.cc
new file mode 100644
index 00000000000..6731ab5a1fa
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CMap.cc
@@ -0,0 +1,598 @@
+//========================================================================
+//
+// CMap.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2008, 2009 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "goo/gmem.h"
+#include "goo/gfile.h"
+#include "goo/GooString.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "PSTokenizer.h"
+#include "CMap.h"
+#include "Object.h"
+
+//------------------------------------------------------------------------
+
+struct CMapVectorEntry {
+ GBool isVector;
+ union {
+ CMapVectorEntry *vector;
+ CID cid;
+ };
+};
+
+//------------------------------------------------------------------------
+
+static int getCharFromFile(void *data) {
+ return fgetc((FILE *)data);
+}
+
+static int getCharFromStream(void *data) {
+ return ((Stream *)data)->getChar();
+}
+
+//------------------------------------------------------------------------
+
+CMap *CMap::parse(CMapCache *cache, GooString *collectionA, Object *obj) {
+ CMap *cMap;
+ GooString *cMapNameA;
+
+ if (obj->isName()) {
+ cMapNameA = new GooString(obj->getName());
+ if (!(cMap = globalParams->getCMap(collectionA, cMapNameA))) {
+ error(errSyntaxError, -1,
+ "Unknown CMap '{0:t}' for character collection '{1:t}'",
+ cMapNameA, collectionA);
+ }
+ delete cMapNameA;
+ } else if (obj->isStream()) {
+ if (!(cMap = CMap::parse(NULL, collectionA, obj->getStream()))) {
+ error(errSyntaxError, -1, "Invalid CMap in Type 0 font");
+ }
+ } else {
+ error(errSyntaxError, -1, "Invalid Encoding in Type 0 font");
+ return NULL;
+ }
+ return cMap;
+}
+
+CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
+ GooString *cMapNameA) {
+ FILE *f;
+ CMap *cMap;
+
+ if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
+
+ // Check for an identity CMap.
+ if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
+ return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
+ }
+ if (!cMapNameA->cmp("Identity-V")) {
+ return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
+ }
+
+ error(errSyntaxError, -1,
+ "Couldn't find '{0:t}' CMap file for '{1:t}' collection",
+ cMapNameA, collectionA);
+ return NULL;
+ }
+
+ cMap = new CMap(collectionA->copy(), cMapNameA->copy());
+ cMap->parse2(cache, &getCharFromFile, f);
+
+ fclose(f);
+
+ return cMap;
+}
+
+CMap *CMap::parse(CMapCache *cache, GooString *collectionA, Stream *str) {
+ Object obj1;
+ CMap *cMap;
+
+ cMap = new CMap(collectionA->copy(), NULL);
+
+ if (!str->getDict()->lookup("UseCMap", &obj1)->isNull()) {
+ cMap->useCMap(cache, &obj1);
+ }
+ obj1.free();
+
+ str->reset();
+ cMap->parse2(cache, &getCharFromStream, str);
+ str->close();
+ return cMap;
+}
+
+CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
+ GooString *cMapNameA, Stream *stream) {
+ FILE *f = NULL;
+ CMap *cmap;
+ PSTokenizer *pst;
+ char tok1[256], tok2[256], tok3[256];
+ int n1, n2, n3;
+ Guint start, end, code;
+
+ if (stream) {
+ stream->reset();
+ pst = new PSTokenizer(&getCharFromStream, stream);
+ } else {
+ if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
+
+ // Check for an identity CMap.
+ if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
+ return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
+ }
+ if (!cMapNameA->cmp("Identity-V")) {
+ return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
+ }
+
+ error(errSyntaxError, -1, "Couldn't find '{0:t}' CMap file for '{1:t}' collection",
+ cMapNameA, collectionA);
+ return NULL;
+ }
+ pst = new PSTokenizer(&getCharFromFile, f);
+ }
+
+ cmap = new CMap(collectionA->copy(), cMapNameA->copy());
+
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ while (pst->getToken(tok2, sizeof(tok2), &n2)) {
+ if (!strcmp(tok2, "usecmap")) {
+ if (tok1[0] == '/') {
+ cmap->useCMap(cache, tok1 + 1);
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok1, "/WMode")) {
+ cmap->wMode = atoi(tok2);
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidchar")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidchar")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidchar")) {
+ error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ n1 >= 4 && (n1 & 1) == 0)) {
+ error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+ continue;
+ }
+ tok1[n1 - 1] = '\0';
+ if (sscanf(tok1 + 1, "%x", &code) != 1) {
+ error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+ continue;
+ }
+ n1 = (n1 - 2) / 2;
+ cmap->addCIDs(code, code, n1, (CID)atoi(tok2));
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidrange")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidrange")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidrange") ||
+ !pst->getToken(tok3, sizeof(tok3), &n3) ||
+ !strcmp(tok3, "endcidrange")) {
+ error(errSyntaxError, -1, "Illegal entry in cidrange block in CMap");
+ break;
+ }
+ if (tok1[0] == '<' && tok2[0] == '<' &&
+ n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
+ tok1[n1 - 1] = tok2[n1 - 1] = '\0';
+ sscanf(tok1 + 1, "%x", &start);
+ sscanf(tok2 + 1, "%x", &end);
+ n1 = (n1 - 2) / 2;
+ cmap->addCIDs(start, end, n1, (CID)atoi(tok3));
+ }
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else {
+ strcpy(tok1, tok2);
+ }
+ }
+ delete pst;
+
+ if (f) {
+ fclose(f);
+ }
+
+ return cmap;
+}
+
+void CMap::parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data) {
+ PSTokenizer *pst;
+ char tok1[256], tok2[256], tok3[256];
+ int n1, n2, n3;
+ Guint start, end, code;
+
+ pst = new PSTokenizer(getCharFunc, data);
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ while (pst->getToken(tok2, sizeof(tok2), &n2)) {
+ if (!strcmp(tok2, "usecmap")) {
+ if (tok1[0] == '/') {
+ useCMap(cache, tok1 + 1);
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok1, "/WMode")) {
+ wMode = atoi(tok2);
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidchar")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidchar")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidchar")) {
+ error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ n1 >= 4 && (n1 & 1) == 0)) {
+ error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+ continue;
+ }
+ tok1[n1 - 1] = '\0';
+ if (sscanf(tok1 + 1, "%x", &code) != 1) {
+ error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+ continue;
+ }
+ n1 = (n1 - 2) / 2;
+ addCIDs(code, code, n1, (CID)atoi(tok2));
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidrange")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidrange")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidrange") ||
+ !pst->getToken(tok3, sizeof(tok3), &n3) ||
+ !strcmp(tok3, "endcidrange")) {
+ error(errSyntaxError, -1, "Illegal entry in cidrange block in CMap");
+ break;
+ }
+ if (tok1[0] == '<' && tok2[0] == '<' &&
+ n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
+ tok1[n1 - 1] = tok2[n1 - 1] = '\0';
+ sscanf(tok1 + 1, "%x", &start);
+ sscanf(tok2 + 1, "%x", &end);
+ n1 = (n1 - 2) / 2;
+ addCIDs(start, end, n1, (CID)atoi(tok3));
+ }
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else {
+ strcpy(tok1, tok2);
+ }
+ }
+ delete pst;
+}
+
+CMap::CMap(GooString *collectionA, GooString *cMapNameA) {
+ int i;
+
+ collection = collectionA;
+ cMapName = cMapNameA;
+ isIdent = gFalse;
+ wMode = 0;
+ vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
+ for (i = 0; i < 256; ++i) {
+ vector[i].isVector = gFalse;
+ vector[i].cid = 0;
+ }
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+CMap::CMap(GooString *collectionA, GooString *cMapNameA, int wModeA) {
+ collection = collectionA;
+ cMapName = cMapNameA;
+ isIdent = gTrue;
+ wMode = wModeA;
+ vector = NULL;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+void CMap::useCMap(CMapCache *cache, char *useName) {
+ GooString *useNameStr;
+ CMap *subCMap;
+
+ useNameStr = new GooString(useName);
+ // if cache is non-NULL, we already have a lock, and we can use
+ // CMapCache::getCMap() directly; otherwise, we need to use
+ // GlobalParams::getCMap() in order to acqure the lock need to use
+ // GlobalParams::getCMap
+ if (cache) {
+ subCMap = cache->getCMap(collection, useNameStr, NULL);
+ } else {
+ subCMap = globalParams->getCMap(collection, useNameStr);
+ }
+ delete useNameStr;
+ if (!subCMap) {
+ return;
+ }
+ isIdent = subCMap->isIdent;
+ if (subCMap->vector) {
+ copyVector(vector, subCMap->vector);
+ }
+ subCMap->decRefCnt();
+}
+
+void CMap::useCMap(CMapCache *cache, Object *obj) {
+ CMap *subCMap;
+
+ subCMap = CMap::parse(cache, collection, obj);
+ if (!subCMap) {
+ return;
+ }
+ isIdent = subCMap->isIdent;
+ if (subCMap->vector) {
+ copyVector(vector, subCMap->vector);
+ }
+ subCMap->decRefCnt();
+}
+
+void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
+ int i, j;
+
+ for (i = 0; i < 256; ++i) {
+ if (src[i].isVector) {
+ if (!dest[i].isVector) {
+ dest[i].isVector = gTrue;
+ dest[i].vector =
+ (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
+ for (j = 0; j < 256; ++j) {
+ dest[i].vector[j].isVector = gFalse;
+ dest[i].vector[j].cid = 0;
+ }
+ }
+ copyVector(dest[i].vector, src[i].vector);
+ } else {
+ if (dest[i].isVector) {
+ error(errSyntaxError, -1, "Collision in usecmap");
+ } else {
+ dest[i].cid = src[i].cid;
+ }
+ }
+ }
+}
+
+void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
+ CMapVectorEntry *vec;
+ CID cid;
+ int byte;
+ Guint i, j;
+
+ vec = vector;
+ for (i = nBytes - 1; i >= 1; --i) {
+ byte = (start >> (8 * i)) & 0xff;
+ if (!vec[byte].isVector) {
+ vec[byte].isVector = gTrue;
+ vec[byte].vector =
+ (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
+ for (j = 0; j < 256; ++j) {
+ vec[byte].vector[j].isVector = gFalse;
+ vec[byte].vector[j].cid = 0;
+ }
+ }
+ vec = vec[byte].vector;
+ }
+ cid = firstCID;
+ for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
+ if (vec[byte].isVector) {
+ error(errSyntaxError, -1,
+ "Invalid CID ({0:ux} - {1:ux} [{2:ud} bytes]) in CMap",
+ start, end, nBytes);
+ } else {
+ vec[byte].cid = cid;
+ }
+ ++cid;
+ }
+}
+
+CMap::~CMap() {
+ delete collection;
+ delete cMapName;
+ if (vector) {
+ freeCMapVector(vector);
+ }
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+void CMap::freeCMapVector(CMapVectorEntry *vec) {
+ int i;
+
+ for (i = 0; i < 256; ++i) {
+ if (vec[i].isVector) {
+ freeCMapVector(vec[i].vector);
+ }
+ }
+ gfree(vec);
+}
+
+void CMap::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ ++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+}
+
+void CMap::decRefCnt() {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
+ delete this;
+ }
+}
+
+GBool CMap::match(GooString *collectionA, GooString *cMapNameA) {
+ return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
+}
+
+CID CMap::getCID(char *s, int len, CharCode *c, int *nUsed) {
+ CMapVectorEntry *vec;
+ CharCode cc;
+ int n, i;
+
+ vec = vector;
+ cc = 0;
+ n = 0;
+ while (vec && n < len) {
+ i = s[n++] & 0xff;
+ cc = (cc << 8) | i;
+ if (!vec[i].isVector) {
+ *c = cc;
+ *nUsed = n;
+ return vec[i].cid;
+ }
+ vec = vec[i].vector;
+ }
+ if (isIdent && len >= 2) {
+ // identity CMap
+ *nUsed = 2;
+ *c = cc = ((s[0] & 0xff) << 8) + (s[1] & 0xff);
+ return cc;
+ }
+ *nUsed = 1;
+ *c = s[0] & 0xff;
+ return 0;
+}
+
+void CMap::setReverseMapVector(Guint startCode, CMapVectorEntry *vec,
+ Guint *rmap, Guint rmapSize, Guint ncand) {
+ int i;
+
+ if (vec == 0) return;
+ for (i = 0;i < 256;i++) {
+ if (vec[i].isVector) {
+ setReverseMapVector((startCode+i) << 8,
+ vec[i].vector,rmap,rmapSize,ncand);
+ } else {
+ Guint cid = vec[i].cid;
+
+ if (cid < rmapSize) {
+ Guint cand;
+
+ for (cand = 0;cand < ncand;cand++) {
+ Guint code = startCode+i;
+ Guint idx = cid*ncand+cand;
+ if (rmap[idx] == 0) {
+ rmap[idx] = code;
+ break;
+ } else if (rmap[idx] == code) {
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void CMap::setReverseMap(Guint *rmap, Guint rmapSize, Guint ncand) {
+ setReverseMapVector(0,vector,rmap,rmapSize,ncand);
+}
+
+//------------------------------------------------------------------------
+
+CMapCache::CMapCache() {
+ int i;
+
+ for (i = 0; i < cMapCacheSize; ++i) {
+ cache[i] = NULL;
+ }
+}
+
+CMapCache::~CMapCache() {
+ int i;
+
+ for (i = 0; i < cMapCacheSize; ++i) {
+ if (cache[i]) {
+ cache[i]->decRefCnt();
+ }
+ }
+}
+
+CMap *CMapCache::getCMap(GooString *collection, GooString *cMapName, Stream *stream) {
+ CMap *cmap;
+ int i, j;
+
+ if (cache[0] && cache[0]->match(collection, cMapName)) {
+ cache[0]->incRefCnt();
+ return cache[0];
+ }
+ for (i = 1; i < cMapCacheSize; ++i) {
+ if (cache[i] && cache[i]->match(collection, cMapName)) {
+ cmap = cache[i];
+ for (j = i; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = cmap;
+ cmap->incRefCnt();
+ return cmap;
+ }
+ }
+ if ((cmap = CMap::parse(this, collection, cMapName, stream))) {
+ if (cache[cMapCacheSize - 1]) {
+ cache[cMapCacheSize - 1]->decRefCnt();
+ }
+ for (j = cMapCacheSize - 1; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = cmap;
+ cmap->incRefCnt();
+ return cmap;
+ }
+ return NULL;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CMap.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CMap.h
new file mode 100644
index 00000000000..f4f5a9141c8
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CMap.h
@@ -0,0 +1,145 @@
+//========================================================================
+//
+// CMap.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef CMAP_H
+#define CMAP_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "goo/gtypes.h"
+#include "CharTypes.h"
+
+#if MULTITHREADED
+#include "goo/GooMutex.h"
+#endif
+
+class GooString;
+class Object;
+struct CMapVectorEntry;
+class CMapCache;
+class Stream;
+
+//------------------------------------------------------------------------
+
+class CMap {
+public:
+
+ // Parse a CMap from <obj>, which can be a name or a stream. Sets
+ // the initial reference count to 1. Returns NULL on failure.
+ static CMap *parse(CMapCache *cache, GooString *collectionA, Object *obj);
+
+ // Create the CMap specified by <collection> and <cMapName>. Sets
+ // the initial reference count to 1. Returns NULL on failure.
+ static CMap *parse(CMapCache *cache, GooString *collectionA,
+ GooString *cMapNameA);
+
+ // Parse a CMap from <str>. Sets the initial reference count to 1.
+ // Returns NULL on failure.
+ static CMap *parse(CMapCache *cache, GooString *collectionA, Stream *str);
+
+ // Create the CMap specified by <collection> and <cMapName>. Sets
+ // the initial reference count to 1.
+ // Stream is a stream containing the CMap, can be NULL and
+ // this means the CMap will be searched in the CMap files
+ // Returns NULL on failure.
+ static CMap *parse(CMapCache *cache, GooString *collectionA,
+ GooString *cMapNameA, Stream *stream);
+
+ ~CMap();
+
+ void incRefCnt();
+ void decRefCnt();
+
+ // Return collection name (<registry>-<ordering>).
+ GooString *getCollection() { return collection; }
+
+ GooString *getCMapName() { return cMapName; }
+
+ // Return true if this CMap matches the specified <collectionA>, and
+ // <cMapNameA>.
+ GBool match(GooString *collectionA, GooString *cMapNameA);
+
+ // Return the CID corresponding to the character code starting at
+ // <s>, which contains <len> bytes. Sets *<c> to the char code, and
+ // *<nUsed> to the number of bytes used by the char code.
+ CID getCID(char *s, int len, CharCode *c, int *nUsed);
+
+ // Return the writing mode (0=horizontal, 1=vertical).
+ int getWMode() { return wMode; }
+
+ void setReverseMap(Guint *rmap, Guint rmapSize, Guint ncand);
+
+private:
+
+ void parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data);
+ CMap(GooString *collectionA, GooString *cMapNameA);
+ CMap(GooString *collectionA, GooString *cMapNameA, int wModeA);
+ void useCMap(CMapCache *cache, char *useName);
+ void useCMap(CMapCache *cache, Object *obj);
+ void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src);
+ void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID);
+ void freeCMapVector(CMapVectorEntry *vec);
+ void setReverseMapVector(Guint startCode, CMapVectorEntry *vec,
+ Guint *rmap, Guint rmapSize, Guint ncand);
+
+ GooString *collection;
+ GooString *cMapName;
+ GBool isIdent; // true if this CMap is an identity mapping,
+ // or is based on one (via usecmap)
+ int wMode; // writing mode (0=horizontal, 1=vertical)
+ CMapVectorEntry *vector; // vector for first byte (NULL for
+ // identity CMap)
+ int refCnt;
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+//------------------------------------------------------------------------
+
+#define cMapCacheSize 4
+
+class CMapCache {
+public:
+
+ CMapCache();
+ ~CMapCache();
+
+ // Get the <cMapName> CMap for the specified character collection.
+ // Increments its reference count; there will be one reference for
+ // the cache plus one for the caller of this function.
+ // Stream is a stream containing the CMap, can be NULL and
+ // this means the CMap will be searched in the CMap files
+ // Returns NULL on failure.
+ CMap *getCMap(GooString *collection, GooString *cMapName, Stream *stream);
+
+private:
+
+ CMap *cache[cMapCacheSize];
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CachedFile.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/CachedFile.cc
new file mode 100644
index 00000000000..b0ae8388113
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CachedFile.cc
@@ -0,0 +1,257 @@
+//========================================================================
+//
+// CachedFile.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2009 Stefan Thomas <thomas@eload24.com>
+// Copyright 2010, 2011 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Julien Nabet <serval2412@yahoo.fr>
+//
+//========================================================================
+
+#include <config.h>
+#include "CachedFile.h"
+
+//------------------------------------------------------------------------
+// CachedFile
+//------------------------------------------------------------------------
+
+CachedFile::CachedFile(CachedFileLoader *cachedFileLoaderA, GooString *uriA)
+{
+ uri = uriA;
+ loader = cachedFileLoaderA;
+
+ streamPos = 0;
+ chunks = new std::vector<Chunk>();
+ length = 0;
+
+ length = loader->init(uri, this);
+ refCnt = 1;
+
+ if (length != ((size_t) -1)) {
+ chunks->resize(length/CachedFileChunkSize + 1);
+ }
+ else {
+ error(errInternal, -1, "Failed to initialize file cache for '{0:t}'.", uri);
+ chunks->resize(0);
+ }
+}
+
+CachedFile::~CachedFile()
+{
+ delete uri;
+ delete loader;
+ delete chunks;
+}
+
+void CachedFile::incRefCnt() {
+ refCnt++;
+}
+
+void CachedFile::decRefCnt() {
+ if (--refCnt == 0)
+ delete this;
+}
+
+long int CachedFile::tell() {
+ return streamPos;
+}
+
+int CachedFile::seek(long int offset, int origin)
+{
+ if (origin == SEEK_SET) {
+ streamPos = offset;
+ } else if (origin == SEEK_CUR) {
+ streamPos += offset;
+ } else {
+ streamPos = length + offset;
+ }
+
+ if (streamPos > length) {
+ streamPos = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+int CachedFile::cache(const std::vector<ByteRange> &origRanges)
+{
+ std::vector<int> loadChunks;
+ int numChunks = length/CachedFileChunkSize + 1;
+ std::vector<bool> chunkNeeded(numChunks);
+ int startChunk, endChunk;
+ std::vector<ByteRange> chunk_ranges, all;
+ ByteRange range;
+ const std::vector<ByteRange> *ranges = &origRanges;
+
+ if (ranges->empty()) {
+ range.offset = 0;
+ range.length = length;
+ all.push_back(range);
+ ranges = &all;
+ }
+
+ for (int i = 0; i < numChunks; ++i)
+ chunkNeeded[i] = false;
+ for (size_t i = 0; i < ranges->size(); i++) {
+
+ if ((*ranges)[i].length == 0) continue;
+ if ((*ranges)[i].offset >= length) continue;
+
+ size_t start = (*ranges)[i].offset;
+ size_t end = start + (*ranges)[i].length - 1;
+ if (end >= length) end = length - 1;
+
+ startChunk = start / CachedFileChunkSize;
+ endChunk = end / CachedFileChunkSize;
+ for (int chunk = startChunk; chunk <= endChunk; chunk++) {
+ if ((*chunks)[chunk].state == chunkStateNew) {
+ chunkNeeded[chunk] = true;
+ }
+ }
+ }
+
+ int chunk = 0;
+ while (chunk < numChunks) {
+ while (!chunkNeeded[chunk] && (++chunk != numChunks)) ;
+ if (chunk == numChunks) break;
+ startChunk = chunk;
+ loadChunks.push_back(chunk);
+
+ while ((++chunk != numChunks) && chunkNeeded[chunk]) {
+ loadChunks.push_back(chunk);
+ }
+ endChunk = chunk - 1;
+
+ range.offset = startChunk * CachedFileChunkSize;
+ range.length = (endChunk - startChunk + 1) * CachedFileChunkSize;
+
+ chunk_ranges.push_back(range);
+ }
+
+ if (chunk_ranges.size() > 0) {
+ CachedFileWriter writer =
+ CachedFileWriter(this, &loadChunks);
+ return loader->load(chunk_ranges, &writer);
+ }
+
+ return 0;
+}
+
+size_t CachedFile::read(void *ptr, size_t unitsize, size_t count)
+{
+ size_t bytes = unitsize*count;
+ if (length < (streamPos + bytes)) {
+ bytes = length - streamPos;
+ }
+
+ if (bytes == 0) return 0;
+
+ // Load data
+ if (cache(streamPos, bytes) != 0) return 0;
+
+ // Copy data to buffer
+ size_t toCopy = bytes;
+ while (toCopy) {
+ int chunk = streamPos / CachedFileChunkSize;
+ int offset = streamPos % CachedFileChunkSize;
+ size_t len = CachedFileChunkSize-offset;
+
+ if (len > toCopy)
+ len = toCopy;
+
+ memcpy(ptr, (*chunks)[chunk].data + offset, len);
+ streamPos += len;
+ toCopy -= len;
+ ptr = (char*)ptr + len;
+ }
+
+ return bytes;
+}
+
+int CachedFile::cache(size_t offset, size_t length)
+{
+ std::vector<ByteRange> r;
+ ByteRange range;
+ range.offset = offset;
+ range.length = length;
+ r.push_back(range);
+ return cache(r);
+}
+
+//------------------------------------------------------------------------
+// CachedFileWriter
+//------------------------------------------------------------------------
+
+CachedFileWriter::CachedFileWriter(CachedFile *cachedFileA, std::vector<int> *chunksA)
+{
+ cachedFile = cachedFileA;
+ chunks = chunksA;
+
+ if (chunks) {
+ offset = 0;
+ it = (*chunks).begin();
+ }
+}
+
+CachedFileWriter::~CachedFileWriter()
+{
+}
+
+size_t CachedFileWriter::write(const char *ptr, size_t size)
+{
+ const char *cp = ptr;
+ size_t len = size;
+ size_t nfree, ncopy;
+ size_t written = 0;
+ size_t chunk;
+
+ if (!len) return 0;
+
+ while (len) {
+ if (chunks) {
+ if (offset == CachedFileChunkSize) {
+ ++it;
+ if (it == (*chunks).end()) return written;
+ offset = 0;
+ }
+ chunk = *it;
+ } else {
+ offset = cachedFile->length % CachedFileChunkSize;
+ chunk = cachedFile->length / CachedFileChunkSize;
+ }
+
+ if (chunk >= cachedFile->chunks->size()) {
+ cachedFile->chunks->resize(chunk + 1);
+ }
+
+ nfree = CachedFileChunkSize - offset;
+ ncopy = (len >= nfree) ? nfree : len;
+ memcpy(&((*cachedFile->chunks)[chunk].data[offset]), cp, ncopy);
+ len -= ncopy;
+ cp += ncopy;
+ offset += ncopy;
+ written += ncopy;
+
+ if (!chunks) {
+ cachedFile->length += ncopy;
+ }
+
+ if (offset == CachedFileChunkSize) {
+ (*cachedFile->chunks)[chunk].state = CachedFile::chunkStateLoaded;
+ }
+ }
+
+ if ((chunk == (cachedFile->length / CachedFileChunkSize)) &&
+ (offset == (cachedFile->length % CachedFileChunkSize))) {
+ (*cachedFile->chunks)[chunk].state = CachedFile::chunkStateLoaded;
+ }
+
+ return written;
+}
+
+//------------------------------------------------------------------------
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CachedFile.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CachedFile.h
new file mode 100644
index 00000000000..b99ea1ecad4
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CachedFile.h
@@ -0,0 +1,146 @@
+//========================================================================
+//
+// CachedFile.h
+//
+// Caching files support.
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2009 Stefan Thomas <thomas@eload24.com>
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef CACHEDFILE_H
+#define CACHEDFILE_H
+
+#include "poppler-config.h"
+
+#include "goo/gtypes.h"
+#include "Object.h"
+#include "Stream.h"
+
+#include <vector>
+
+//------------------------------------------------------------------------
+
+#define CachedFileChunkSize 8192 // This should be a multiple of cachedStreamBufSize
+
+class GooString;
+class CachedFileLoader;
+
+//------------------------------------------------------------------------
+// CachedFile
+//
+// CachedFile gives FILE-like access to a document at a specified URI.
+// In the constructor, you specify a CachedFileLoader that handles loading
+// the data from the document. The CachedFile requests no more data then it
+// needs from the CachedFileLoader.
+//------------------------------------------------------------------------
+
+class CachedFile {
+
+friend class CachedFileWriter;
+
+public:
+
+ CachedFile(CachedFileLoader *cacheLoader, GooString *uri);
+
+ Guint getLength() { return length; }
+ long int tell();
+ int seek(long int offset, int origin);
+ size_t read(void * ptr, size_t unitsize, size_t count);
+ size_t write(const char *ptr, size_t size, size_t fromByte);
+ int cache(const std::vector<ByteRange> &ranges);
+
+ // Reference counting.
+ void incRefCnt();
+ void decRefCnt();
+
+private:
+
+ ~CachedFile();
+
+ enum ChunkState {
+ chunkStateNew = 0,
+ chunkStateLoaded
+ };
+
+ typedef struct {
+ ChunkState state;
+ char data[CachedFileChunkSize];
+ } Chunk;
+
+ int cache(size_t offset, size_t length);
+
+ CachedFileLoader *loader;
+ GooString *uri;
+
+ size_t length;
+ size_t streamPos;
+
+ std::vector<Chunk> *chunks;
+
+ int refCnt; // reference count
+
+};
+
+//------------------------------------------------------------------------
+// CachedFileWriter
+//
+// CachedFileWriter handles sequential writes to a CachedFile.
+// On construction, you specify the CachedFile and the chunks of it to which data
+// should be written.
+//------------------------------------------------------------------------
+
+class CachedFileWriter {
+
+public:
+
+ // Construct a CachedFile Writer.
+ // The caller is responsible for deleting the cachedFile and chunksA.
+ CachedFileWriter(CachedFile *cachedFile, std::vector<int> *chunksA);
+
+ ~CachedFileWriter();
+
+ // Writes size bytes from ptr to cachedFile, returns number of bytes written.
+ size_t write(const char *ptr, size_t size);
+
+private:
+
+ CachedFile *cachedFile;
+ std::vector<int> *chunks;
+ std::vector<int>::iterator it;
+ size_t offset;
+
+};
+
+//------------------------------------------------------------------------
+// CachedFileLoader
+//
+// CachedFileLoader is an abstact class that specifies the interface for
+// loadng data from an URI into a CachedFile.
+//------------------------------------------------------------------------
+
+class CachedFileLoader {
+
+public:
+
+ virtual ~CachedFileLoader() {};
+
+ // Initializes the file load.
+ // Returns the length of the file.
+ // The caller is responsible for deleting uri and cachedFile.
+ virtual size_t init(GooString *uri, CachedFile *cachedFile) = 0;
+
+ // Loads speficified byte ranges and passes it to the writer to store them.
+ // Returns 0 on success, Anything but 0 on failure.
+ // The caller is responsible for deleting the writer.
+ virtual int load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer) = 0;
+
+};
+
+//------------------------------------------------------------------------
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoFontEngine.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoFontEngine.cc
new file mode 100644
index 00000000000..1d611b59d3c
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoFontEngine.cc
@@ -0,0 +1,832 @@
+//========================================================================
+//
+// CairoFontEngine.cc
+//
+// Copyright 2003 Glyph & Cog, LLC
+// Copyright 2004 Red Hat, Inc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005-2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
+// Copyright (C) 2005, 2009, 2012, 2013, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006, 2007, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2008, 2009 Chris Wilson <chris@chris-wilson.co.uk>
+// Copyright (C) 2008, 2012, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2009 Darren Kenny <darren.kenny@sun.com>
+// Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+// Copyright (C) 2010 Jan Kümmel <jan+freedesktop@snorc.org>
+// Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2015 Jason Crain <jason@aquaticape.us>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#include "config.h"
+#include <string.h>
+#include "CairoFontEngine.h"
+#include "CairoOutputDev.h"
+#include "GlobalParams.h"
+#include <fofi/FoFiTrueType.h>
+#include <fofi/FoFiType1C.h>
+#include "goo/gfile.h"
+#include "Error.h"
+#include "XRef.h"
+#include "Gfx.h"
+#include "Page.h"
+
+#if HAVE_FCNTL_H && HAVE_SYS_MMAN_H && HAVE_SYS_STAT_H
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#define CAN_CHECK_OPEN_FACES 1
+#endif
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#if MULTITHREADED
+# define fontEngineLocker() MutexLocker locker(&mutex)
+#else
+# define fontEngineLocker()
+#endif
+
+//------------------------------------------------------------------------
+// CairoFont
+//------------------------------------------------------------------------
+
+CairoFont::CairoFont(Ref ref,
+ cairo_font_face_t *cairo_font_face,
+ int *codeToGID,
+ Guint codeToGIDLen,
+ GBool substitute,
+ GBool printing) : ref(ref),
+ cairo_font_face(cairo_font_face),
+ codeToGID(codeToGID),
+ codeToGIDLen(codeToGIDLen),
+ substitute(substitute),
+ printing(printing) { }
+
+CairoFont::~CairoFont() {
+ cairo_font_face_destroy (cairo_font_face);
+ gfree(codeToGID);
+}
+
+GBool
+CairoFont::matches(Ref &other, GBool printingA) {
+ return (other.num == ref.num && other.gen == ref.gen);
+}
+
+cairo_font_face_t *
+CairoFont::getFontFace(void) {
+ return cairo_font_face;
+}
+
+unsigned long
+CairoFont::getGlyph(CharCode code,
+ Unicode *u, int uLen) {
+ FT_UInt gid;
+
+ if (codeToGID && code < codeToGIDLen) {
+ gid = (FT_UInt)codeToGID[code];
+ } else {
+ gid = (FT_UInt)code;
+ }
+ return gid;
+}
+
+double
+CairoFont::getSubstitutionCorrection(GfxFont *gfxFont)
+{
+ double w1, w2;
+ CharCode code;
+ char *name;
+
+ // for substituted fonts: adjust the font matrix -- compare the
+ // width of 'm' in the original font and the substituted font
+ if (isSubstitute() && !gfxFont->isCIDFont()) {
+ for (code = 0; code < 256; ++code) {
+ if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
+ name[0] == 'm' && name[1] == '\0') {
+ break;
+ }
+ }
+ if (code < 256) {
+ w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
+ {
+ cairo_matrix_t m;
+ cairo_matrix_init_identity(&m);
+ cairo_font_options_t *options = cairo_font_options_create();
+ cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
+ cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF);
+ cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options);
+
+ cairo_text_extents_t extents;
+ cairo_scaled_font_text_extents(scaled_font, "m", &extents);
+
+ cairo_scaled_font_destroy(scaled_font);
+ cairo_font_options_destroy(options);
+ w2 = extents.x_advance;
+ }
+ if (!gfxFont->isSymbolic()) {
+ // if real font is substantially narrower than substituted
+ // font, reduce the font size accordingly
+ if (w1 > 0.01 && w1 < 0.9 * w2) {
+ w1 /= w2;
+ return w1;
+ }
+ }
+ }
+ }
+ return 1.0;
+}
+
+//------------------------------------------------------------------------
+// CairoFreeTypeFont
+//------------------------------------------------------------------------
+
+static cairo_user_data_key_t _ft_cairo_key;
+
+static void
+_ft_done_face_uncached (void *closure)
+{
+ FT_Face face = (FT_Face) closure;
+ FT_Done_Face (face);
+}
+
+static GBool
+_ft_new_face_uncached (FT_Library lib,
+ const char *filename,
+ char *font_data,
+ int font_data_len,
+ FT_Face *face_out,
+ cairo_font_face_t **font_face_out)
+{
+ FT_Face face;
+ cairo_font_face_t *font_face;
+
+ if (font_data == NULL) {
+ if (FT_New_Face (lib, filename, 0, &face))
+ return gFalse;
+ } else {
+ if (FT_New_Memory_Face (lib, (unsigned char *)font_data, font_data_len, 0, &face))
+ return gFalse;
+ }
+
+ font_face = cairo_ft_font_face_create_for_ft_face (face,
+ FT_LOAD_NO_HINTING |
+ FT_LOAD_NO_BITMAP);
+ if (cairo_font_face_set_user_data (font_face,
+ &_ft_cairo_key,
+ face,
+ _ft_done_face_uncached))
+ {
+ _ft_done_face_uncached (face);
+ cairo_font_face_destroy (font_face);
+ return gFalse;
+ }
+
+ *face_out = face;
+ *font_face_out = font_face;
+ return gTrue;
+}
+
+#if CAN_CHECK_OPEN_FACES
+static struct _ft_face_data {
+ struct _ft_face_data *prev, *next, **head;
+
+ int fd;
+ unsigned long hash;
+ size_t size;
+ unsigned char *bytes;
+
+ FT_Library lib;
+ FT_Face face;
+ cairo_font_face_t *font_face;
+} *_ft_open_faces;
+
+static unsigned long
+_djb_hash (const unsigned char *bytes, size_t len)
+{
+ unsigned long hash = 5381;
+ while (len--) {
+ unsigned char c = *bytes++;
+ hash *= 33;
+ hash ^= c;
+ }
+ return hash;
+}
+
+static GBool
+_ft_face_data_equal (struct _ft_face_data *a, struct _ft_face_data *b)
+{
+ if (a->lib != b->lib)
+ return gFalse;
+ if (a->size != b->size)
+ return gFalse;
+ if (a->hash != b->hash)
+ return gFalse;
+
+ return memcmp (a->bytes, b->bytes, a->size) == 0;
+}
+
+static void
+_ft_done_face (void *closure)
+{
+ struct _ft_face_data *data = (struct _ft_face_data *) closure;
+
+ if (data->next)
+ data->next->prev = data->prev;
+ if (data->prev)
+ data->prev->next = data->next;
+ else
+ _ft_open_faces = data->next;
+
+ if (data->fd != -1) {
+#if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
+ munmap ((char*)data->bytes, data->size);
+#else
+ munmap (data->bytes, data->size);
+#endif
+ close (data->fd);
+ } else {
+ gfree (data->bytes);
+ }
+
+ FT_Done_Face (data->face);
+ gfree (data);
+}
+
+static GBool
+_ft_new_face (FT_Library lib,
+ const char *filename,
+ char *font_data,
+ int font_data_len,
+ FT_Face *face_out,
+ cairo_font_face_t **font_face_out)
+{
+ struct _ft_face_data *l;
+ struct stat st;
+ struct _ft_face_data tmpl;
+
+ tmpl.fd = -1;
+
+ if (font_data == NULL) {
+ /* if we fail to mmap the file, just pass it to FreeType instead */
+ tmpl.fd = open (filename, O_RDONLY);
+ if (tmpl.fd == -1)
+ return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
+
+ if (fstat (tmpl.fd, &st) == -1) {
+ close (tmpl.fd);
+ return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
+ }
+
+ tmpl.bytes = (unsigned char *) mmap (NULL, st.st_size,
+ PROT_READ, MAP_PRIVATE,
+ tmpl.fd, 0);
+ if (tmpl.bytes == MAP_FAILED) {
+ close (tmpl.fd);
+ return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
+ }
+ tmpl.size = st.st_size;
+ } else {
+ tmpl.bytes = (unsigned char*) font_data;
+ tmpl.size = font_data_len;
+ }
+
+ /* check to see if this is a duplicate of any of the currently open fonts */
+ tmpl.lib = lib;
+ tmpl.hash = _djb_hash (tmpl.bytes, tmpl.size);
+
+ for (l = _ft_open_faces; l; l = l->next) {
+ if (_ft_face_data_equal (l, &tmpl)) {
+ if (tmpl.fd != -1) {
+#if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
+ munmap ((char*)tmpl.bytes, tmpl.size);
+#else
+ munmap (tmpl.bytes, tmpl.size);
+#endif
+ close (tmpl.fd);
+ } else {
+ gfree (tmpl.bytes);
+ }
+ *face_out = l->face;
+ *font_face_out = cairo_font_face_reference (l->font_face);
+ return gTrue;
+ }
+ }
+
+ /* not a dup, open and insert into list */
+ if (FT_New_Memory_Face (lib,
+ (FT_Byte *) tmpl.bytes, tmpl.size,
+ 0, &tmpl.face))
+ {
+ if (tmpl.fd != -1) {
+#if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4)
+ munmap ((char*)tmpl.bytes, tmpl.size);
+#else
+ munmap (tmpl.bytes, tmpl.size);
+#endif
+
+ close (tmpl.fd);
+ }
+ return gFalse;
+ }
+
+ l = (struct _ft_face_data *) gmallocn (1, sizeof (struct _ft_face_data));
+ *l = tmpl;
+ l->prev = NULL;
+ l->next = _ft_open_faces;
+ if (_ft_open_faces)
+ _ft_open_faces->prev = l;
+ _ft_open_faces = l;
+
+ l->font_face = cairo_ft_font_face_create_for_ft_face (tmpl.face,
+ FT_LOAD_NO_HINTING |
+ FT_LOAD_NO_BITMAP);
+ if (cairo_font_face_set_user_data (l->font_face,
+ &_ft_cairo_key,
+ l,
+ _ft_done_face))
+ {
+ cairo_font_face_destroy (l->font_face);
+ _ft_done_face (l);
+ return gFalse;
+ }
+
+ *face_out = l->face;
+ *font_face_out = l->font_face;
+ return gTrue;
+}
+#else
+#define _ft_new_face _ft_new_face_uncached
+#endif
+
+CairoFreeTypeFont::CairoFreeTypeFont(Ref ref,
+ cairo_font_face_t *cairo_font_face,
+ int *codeToGID,
+ Guint codeToGIDLen,
+ GBool substitute) : CairoFont(ref,
+ cairo_font_face,
+ codeToGID,
+ codeToGIDLen,
+ substitute,
+ gTrue) { }
+
+CairoFreeTypeFont::~CairoFreeTypeFont() { }
+
+CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
+ FT_Library lib, GBool useCIDs) {
+ Object refObj, strObj;
+ GooString *fileName;
+ char *fileNameC;
+ char *font_data;
+ int font_data_len;
+ int i, n;
+ GfxFontType fontType;
+ GfxFontLoc *fontLoc;
+ char **enc;
+ const char *name;
+ FoFiTrueType *ff;
+ FoFiType1C *ff1c;
+ Ref ref;
+ FT_Face face;
+ cairo_font_face_t *font_face;
+
+ int *codeToGID;
+ Guint codeToGIDLen;
+
+ codeToGID = NULL;
+ codeToGIDLen = 0;
+ font_data = NULL;
+ font_data_len = 0;
+ fileName = NULL;
+ fileNameC = NULL;
+
+ GBool substitute = gFalse;
+
+ ref = *gfxFont->getID();
+ fontType = gfxFont->getType();
+
+ if (!(fontLoc = gfxFont->locateFont(xref, NULL))) {
+ error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+
+ // embedded font
+ if (fontLoc->locType == gfxFontLocEmbedded) {
+ font_data = gfxFont->readEmbFontFile(xref, &font_data_len);
+ if (NULL == font_data)
+ goto err2;
+
+ // external font
+ } else { // gfxFontLocExternal
+ fileName = fontLoc->path;
+ fontType = fontLoc->fontType;
+ substitute = gTrue;
+ }
+
+ if (fileName != NULL) {
+ fileNameC = fileName->getCString();
+ }
+
+ switch (fontType) {
+ case fontType1:
+ case fontType1C:
+ case fontType1COT:
+ if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+ error(errSyntaxError, -1, "could not create type1 face");
+ goto err2;
+ }
+
+ enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
+
+ codeToGID = (int *)gmallocn(256, sizeof(int));
+ codeToGIDLen = 256;
+ for (i = 0; i < 256; ++i) {
+ codeToGID[i] = 0;
+ if ((name = enc[i])) {
+ codeToGID[i] = FT_Get_Name_Index(face, (char*)name);
+ if (codeToGID[i] == 0) {
+ name = GfxFont::getAlternateName(name);
+ if (name) {
+ codeToGID[i] = FT_Get_Name_Index(face, (char*)name);
+ }
+ }
+ }
+ }
+ break;
+ case fontCIDType2:
+ case fontCIDType2OT:
+ codeToGID = NULL;
+ n = 0;
+ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
+ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
+ if (n) {
+ codeToGID = (int *)gmallocn(n, sizeof(int));
+ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
+ n * sizeof(int));
+ }
+ } else {
+ if (font_data != NULL) {
+ ff = FoFiTrueType::make(font_data, font_data_len);
+ } else {
+ ff = FoFiTrueType::load(fileNameC);
+ }
+ if (! ff)
+ goto err2;
+ codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
+ delete ff;
+ }
+ codeToGIDLen = n;
+ /* Fall through */
+ case fontTrueType:
+ if (font_data != NULL) {
+ ff = FoFiTrueType::make(font_data, font_data_len);
+ } else {
+ ff = FoFiTrueType::load(fileNameC);
+ }
+ if (! ff) {
+ error(errSyntaxError, -1, "failed to load truetype font\n");
+ goto err2;
+ }
+ /* This might be set already for the CIDType2 case */
+ if (fontType == fontTrueType) {
+ codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
+ codeToGIDLen = 256;
+ }
+ delete ff;
+ if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+ error(errSyntaxError, -1, "could not create truetype face\n");
+ goto err2;
+ }
+ break;
+
+ case fontCIDType0:
+ case fontCIDType0C:
+
+ codeToGID = NULL;
+ codeToGIDLen = 0;
+
+ if (!useCIDs)
+ {
+ if (font_data != NULL) {
+ ff1c = FoFiType1C::make(font_data, font_data_len);
+ } else {
+ ff1c = FoFiType1C::load(fileNameC);
+ }
+ if (ff1c) {
+ codeToGID = ff1c->getCIDToGIDMap((int *)&codeToGIDLen);
+ delete ff1c;
+ }
+ }
+
+ if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+ error(errSyntaxError, -1, "could not create cid face\n");
+ goto err2;
+ }
+ break;
+
+ default:
+ fprintf (stderr, "font type %d not handled\n", (int)fontType);
+ goto err2;
+ break;
+ }
+
+ delete fontLoc;
+ return new CairoFreeTypeFont(ref,
+ font_face,
+ codeToGID, codeToGIDLen,
+ substitute);
+
+ err2:
+ /* hmm? */
+ delete fontLoc;
+ gfree (codeToGID);
+ gfree (font_data);
+ fprintf (stderr, "some font thing failed\n");
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+// CairoType3Font
+//------------------------------------------------------------------------
+
+static const cairo_user_data_key_t type3_font_key = {0};
+
+typedef struct _type3_font_info {
+ GfxFont *font;
+ PDFDoc *doc;
+ CairoFontEngine *fontEngine;
+ GBool printing;
+ XRef *xref;
+} type3_font_info_t;
+
+static void
+_free_type3_font_info(void *closure)
+{
+ type3_font_info_t *info = (type3_font_info_t *) closure;
+
+ info->font->decRefCnt();
+ free (info);
+}
+
+static cairo_status_t
+_init_type3_glyph (cairo_scaled_font_t *scaled_font,
+ cairo_t *cr,
+ cairo_font_extents_t *extents)
+{
+ type3_font_info_t *info;
+ GfxFont *font;
+ double *mat;
+
+ info = (type3_font_info_t *)
+ cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+ &type3_font_key);
+ font = info->font;
+ mat = font->getFontBBox();
+ extents->ascent = mat[3]; /* y2 */
+ extents->descent = -mat[3]; /* -y1 */
+ extents->height = extents->ascent + extents->descent;
+ extents->max_x_advance = mat[2] - mat[1]; /* x2 - x1 */
+ extents->max_y_advance = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_render_type3_glyph (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *metrics)
+{
+ Dict *charProcs;
+ Object charProc;
+ CairoOutputDev *output_dev;
+ cairo_matrix_t matrix, invert_y_axis;
+ double *mat;
+ double wx, wy;
+ PDFRectangle box;
+ type3_font_info_t *info;
+ GfxFont *font;
+ Dict *resDict;
+ Gfx *gfx;
+
+ info = (type3_font_info_t *)
+ cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+ &type3_font_key);
+
+ font = info->font;
+ resDict = ((Gfx8BitFont *)font)->getResources();
+ charProcs = ((Gfx8BitFont *)(info->font))->getCharProcs();
+ if (!charProcs)
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ if ((int)glyph >= charProcs->getLength())
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ mat = font->getFontMatrix();
+ matrix.xx = mat[0];
+ matrix.yx = mat[1];
+ matrix.xy = mat[2];
+ matrix.yy = mat[3];
+ matrix.x0 = mat[4];
+ matrix.y0 = mat[5];
+ cairo_matrix_init_scale (&invert_y_axis, 1, -1);
+ cairo_matrix_multiply (&matrix, &matrix, &invert_y_axis);
+ cairo_transform (cr, &matrix);
+
+ output_dev = new CairoOutputDev();
+ output_dev->setCairo(cr);
+ output_dev->setPrinting(info->printing);
+
+ mat = font->getFontBBox();
+ box.x1 = mat[0];
+ box.y1 = mat[1];
+ box.x2 = mat[2];
+ box.y2 = mat[3];
+ gfx = new Gfx(info->doc, output_dev, resDict, &box, NULL);
+ output_dev->startDoc(info->doc, info->fontEngine);
+ output_dev->startPage (1, gfx->getState(), gfx->getXRef());
+ output_dev->setInType3Char(gTrue);
+ gfx->display(charProcs->getVal(glyph, &charProc));
+
+ output_dev->getType3GlyphWidth (&wx, &wy);
+ cairo_matrix_transform_distance (&matrix, &wx, &wy);
+ metrics->x_advance = wx;
+ metrics->y_advance = wy;
+ if (output_dev->hasType3GlyphBBox()) {
+ double *bbox = output_dev->getType3GlyphBBox();
+
+ cairo_matrix_transform_point (&matrix, &bbox[0], &bbox[1]);
+ cairo_matrix_transform_point (&matrix, &bbox[2], &bbox[3]);
+ metrics->x_bearing = bbox[0];
+ metrics->y_bearing = bbox[1];
+ metrics->width = bbox[2] - bbox[0];
+ metrics->height = bbox[3] - bbox[1];
+ }
+
+ delete gfx;
+ delete output_dev;
+ charProc.free();
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc,
+ CairoFontEngine *fontEngine,
+ GBool printing, XRef *xref) {
+ Object refObj, strObj;
+ type3_font_info_t *info;
+ cairo_font_face_t *font_face;
+ Ref ref;
+ int *codeToGID;
+ Guint codeToGIDLen;
+ int i, j;
+ char **enc;
+ Dict *charProcs;
+ char *name;
+
+ charProcs = ((Gfx8BitFont *)gfxFont)->getCharProcs();
+ info = (type3_font_info_t *) malloc(sizeof(*info));
+ ref = *gfxFont->getID();
+ font_face = cairo_user_font_face_create();
+ cairo_user_font_face_set_init_func (font_face, _init_type3_glyph);
+ cairo_user_font_face_set_render_glyph_func (font_face, _render_type3_glyph);
+ gfxFont->incRefCnt();
+ info->font = gfxFont;
+ info->doc = doc;
+ info->fontEngine = fontEngine;
+ info->printing = printing;
+ info->xref = xref;
+
+ cairo_font_face_set_user_data (font_face, &type3_font_key, (void *) info, _free_type3_font_info);
+
+ enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
+ codeToGID = (int *)gmallocn(256, sizeof(int));
+ codeToGIDLen = 256;
+ for (i = 0; i < 256; ++i) {
+ codeToGID[i] = 0;
+ if (charProcs && (name = enc[i])) {
+ for (j = 0; j < charProcs->getLength(); j++) {
+ if (strcmp(name, charProcs->getKey(j)) == 0) {
+ codeToGID[i] = j;
+ }
+ }
+ }
+ }
+
+ return new CairoType3Font(ref, doc, font_face, codeToGID, codeToGIDLen, printing, xref);
+}
+
+CairoType3Font::CairoType3Font(Ref ref,
+ PDFDoc *doc,
+ cairo_font_face_t *cairo_font_face,
+ int *codeToGID,
+ Guint codeToGIDLen,
+ GBool printing, XRef *xref) : CairoFont(ref,
+ cairo_font_face,
+ codeToGID,
+ codeToGIDLen,
+ gFalse,
+ printing),
+ doc(doc) { }
+
+CairoType3Font::~CairoType3Font() { }
+
+GBool
+CairoType3Font::matches(Ref &other, GBool printingA) {
+ return (other.num == ref.num && other.gen == ref.gen && printing == printingA);
+}
+
+
+//------------------------------------------------------------------------
+// CairoFontEngine
+//------------------------------------------------------------------------
+
+CairoFontEngine::CairoFontEngine(FT_Library libA) {
+ int i;
+
+ lib = libA;
+ for (i = 0; i < cairoFontCacheSize; ++i) {
+ fontCache[i] = NULL;
+ }
+
+ FT_Int major, minor, patch;
+ // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
+ FT_Library_Version(lib, &major, &minor, &patch);
+ useCIDs = major > 2 ||
+ (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+CairoFontEngine::~CairoFontEngine() {
+ int i;
+
+ for (i = 0; i < cairoFontCacheSize; ++i) {
+ if (fontCache[i])
+ delete fontCache[i];
+ }
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+CairoFont *
+CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref) {
+ int i, j;
+ Ref ref;
+ CairoFont *font;
+ GfxFontType fontType;
+
+ fontEngineLocker();
+ ref = *gfxFont->getID();
+
+ for (i = 0; i < cairoFontCacheSize; ++i) {
+ font = fontCache[i];
+ if (font && font->matches(ref, printing)) {
+ for (j = i; j > 0; --j) {
+ fontCache[j] = fontCache[j-1];
+ }
+ fontCache[0] = font;
+ return font;
+ }
+ }
+
+ fontType = gfxFont->getType();
+ if (fontType == fontType3)
+ font = CairoType3Font::create (gfxFont, doc, this, printing, xref);
+ else
+ font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs);
+
+ //XXX: if font is null should we still insert it into the cache?
+ if (fontCache[cairoFontCacheSize - 1]) {
+ delete fontCache[cairoFontCacheSize - 1];
+ }
+ for (j = cairoFontCacheSize - 1; j > 0; --j) {
+ fontCache[j] = fontCache[j-1];
+ }
+ fontCache[0] = font;
+ return font;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoFontEngine.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoFontEngine.h
new file mode 100644
index 00000000000..8c0dba116d5
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoFontEngine.h
@@ -0,0 +1,129 @@
+//========================================================================
+//
+// CairoFontEngine.h
+//
+// Copyright 2003 Glyph & Cog, LLC
+// Copyright 2004 Red Hat, Inc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2006, 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2008 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef CAIROFONTENGINE_H
+#define CAIROFONTENGINE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "goo/gtypes.h"
+#include <cairo-ft.h>
+
+#include "GfxFont.h"
+#include "PDFDoc.h"
+
+class CairoFontEngine;
+
+class CairoFont {
+public:
+ CairoFont(Ref ref,
+ cairo_font_face_t *face,
+ int *codeToGID,
+ Guint codeToGIDLen,
+ GBool substitute,
+ GBool printing);
+ virtual ~CairoFont();
+
+ virtual GBool matches(Ref &other, GBool printing);
+ cairo_font_face_t *getFontFace(void);
+ unsigned long getGlyph(CharCode code, Unicode *u, int uLen);
+ double getSubstitutionCorrection(GfxFont *gfxFont);
+
+ GBool isSubstitute() { return substitute; }
+protected:
+ Ref ref;
+ cairo_font_face_t *cairo_font_face;
+
+ int *codeToGID;
+ Guint codeToGIDLen;
+
+ GBool substitute;
+ GBool printing;
+};
+
+//------------------------------------------------------------------------
+
+class CairoFreeTypeFont : public CairoFont {
+public:
+ static CairoFreeTypeFont *create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs);
+ virtual ~CairoFreeTypeFont();
+
+private:
+ CairoFreeTypeFont(Ref ref, cairo_font_face_t *cairo_font_face,
+ int *codeToGID, Guint codeToGIDLen, GBool substitute);
+};
+
+//------------------------------------------------------------------------
+
+class CairoType3Font : public CairoFont {
+public:
+ static CairoType3Font *create(GfxFont *gfxFont, PDFDoc *doc,
+ CairoFontEngine *fontEngine,
+ GBool printing, XRef *xref);
+ virtual ~CairoType3Font();
+
+ virtual GBool matches(Ref &other, GBool printing);
+
+private:
+ CairoType3Font(Ref ref, PDFDoc *doc,
+ cairo_font_face_t *cairo_font_face,
+ int *codeToGID, Guint codeToGIDLen,
+ GBool printing, XRef *xref);
+ PDFDoc *doc;
+};
+
+//------------------------------------------------------------------------
+
+#define cairoFontCacheSize 64
+
+//------------------------------------------------------------------------
+// CairoFontEngine
+//------------------------------------------------------------------------
+
+class CairoFontEngine {
+public:
+
+ // Create a font engine.
+ CairoFontEngine(FT_Library libA);
+ ~CairoFontEngine();
+
+ CairoFont *getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref);
+
+private:
+ CairoFont *fontCache[cairoFontCacheSize];
+ FT_Library lib;
+ GBool useCIDs;
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoOutputDev.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoOutputDev.cc
new file mode 100644
index 00000000000..1e201d38e36
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoOutputDev.cc
@@ -0,0 +1,3315 @@
+//========================================================================
+//
+// CairoOutputDev.cc
+//
+// Copyright 2003 Glyph & Cog, LLC
+// Copyright 2004 Red Hat, Inc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005-2008 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005, 2009, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+// Copyright (C) 2006-2011, 2013, 2014 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2008 Carl Worth <cworth@cworth.org>
+// Copyright (C) 2008-2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
+// Copyright (C) 2008, 2009 Chris Wilson <chris@chris-wilson.co.uk>
+// Copyright (C) 2008, 2012 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2009, 2010 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2011-2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Patrick Pfeifer <p2000@mailinator.com>
+// Copyright (C) 2012, 2015 Jason Crain <jason@aquaticape.us>
+// Copyright (C) 2015 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <cairo.h>
+
+#include "goo/gfile.h"
+#include "goo/gtypes_p.h"
+#include "GlobalParams.h"
+#include "Error.h"
+#include "Object.h"
+#include "Gfx.h"
+#include "GfxState.h"
+#include "GfxFont.h"
+#include "Page.h"
+#include "Link.h"
+#include "FontEncodingTables.h"
+#include "PDFDocEncoding.h"
+#include <fofi/FoFiTrueType.h>
+#include <splash/SplashBitmap.h>
+#include "CairoOutputDev.h"
+#include "CairoFontEngine.h"
+#include "CairoRescaleBox.h"
+#include "UnicodeMap.h"
+#include "JBIG2Stream.h"
+//------------------------------------------------------------------------
+
+// #define LOG_CAIRO
+
+#ifdef LOG_CAIRO
+#define LOG(x) (x)
+#else
+#define LOG(x)
+#endif
+
+static inline void printMatrix(cairo_matrix_t *matrix){
+ printf("%f %f, %f %f (%f %f)\n", matrix->xx, matrix->yx,
+ matrix->xy, matrix->yy,
+ matrix->x0, matrix->y0);
+}
+
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+
+//------------------------------------------------------------------------
+// CairoImage
+//------------------------------------------------------------------------
+
+CairoImage::CairoImage (double x1, double y1, double x2, double y2) {
+ this->image = NULL;
+ this->x1 = x1;
+ this->y1 = y1;
+ this->x2 = x2;
+ this->y2 = y2;
+}
+
+CairoImage::~CairoImage () {
+ if (image)
+ cairo_surface_destroy (image);
+}
+
+void CairoImage::setImage (cairo_surface_t *image) {
+ if (this->image)
+ cairo_surface_destroy (this->image);
+ this->image = cairo_surface_reference (image);
+}
+
+//------------------------------------------------------------------------
+// CairoOutputDev
+//------------------------------------------------------------------------
+
+// We cannot tie the lifetime of an FT_Library object to that of
+// CairoOutputDev, since any FT_Faces created with it may end up with a
+// reference by Cairo which can be held long after the CairoOutputDev is
+// deleted. The simplest way to avoid problems is to never tear down the
+// FT_Library instance; to avoid leaks, just use a single global instance
+// initialized the first time it is needed.
+FT_Library CairoOutputDev::ft_lib;
+GBool CairoOutputDev::ft_lib_initialized = gFalse;
+
+CairoOutputDev::CairoOutputDev() {
+ doc = NULL;
+
+ if (!ft_lib_initialized) {
+ FT_Init_FreeType(&ft_lib);
+ ft_lib_initialized = gTrue;
+ }
+
+ fontEngine = NULL;
+ fontEngine_owner = gFalse;
+ glyphs = NULL;
+ fill_pattern = NULL;
+ fill_color.r = fill_color.g = fill_color.b = 0;
+ stroke_pattern = NULL;
+ stroke_color.r = stroke_color.g = stroke_color.b = 0;
+ stroke_opacity = 1.0;
+ fill_opacity = 1.0;
+ textClipPath = NULL;
+ strokePathClip = NULL;
+ cairo = NULL;
+ currentFont = NULL;
+ prescaleImages = gTrue;
+ printing = gTrue;
+ use_show_text_glyphs = gFalse;
+ inUncoloredPattern = gFalse;
+ inType3Char = gFalse;
+ t3_glyph_has_bbox = gFalse;
+ text_matrix_valid = gTrue;
+
+ groupColorSpaceStack = NULL;
+ maskStack = NULL;
+ group = NULL;
+ mask = NULL;
+ shape = NULL;
+ cairo_shape = NULL;
+ knockoutCount = 0;
+
+ text = NULL;
+ actualText = NULL;
+
+ // the SA parameter supposedly defaults to false, but Acrobat
+ // apparently hardwires it to true
+ stroke_adjust = globalParams->getStrokeAdjust();
+ align_stroke_coords = gFalse;
+ adjusted_stroke_width = gFalse;
+ xref = NULL;
+}
+
+CairoOutputDev::~CairoOutputDev() {
+ if (fontEngine_owner && fontEngine) {
+ delete fontEngine;
+ }
+
+ if (cairo)
+ cairo_destroy (cairo);
+ cairo_pattern_destroy (stroke_pattern);
+ cairo_pattern_destroy (fill_pattern);
+ if (group)
+ cairo_pattern_destroy (group);
+ if (mask)
+ cairo_pattern_destroy (mask);
+ if (shape)
+ cairo_pattern_destroy (shape);
+ if (text)
+ text->decRefCnt();
+ if (actualText)
+ delete actualText;
+}
+
+void CairoOutputDev::setCairo(cairo_t *cairo)
+{
+ if (this->cairo != NULL) {
+ cairo_status_t status = cairo_status (this->cairo);
+ if (status) {
+ error(errInternal, -1, "cairo context error: {0:s}\n", cairo_status_to_string(status));
+ }
+ cairo_destroy (this->cairo);
+ assert(!cairo_shape);
+ }
+ if (cairo != NULL) {
+ this->cairo = cairo_reference (cairo);
+ /* save the initial matrix so that we can use it for type3 fonts. */
+ //XXX: is this sufficient? could we miss changes to the matrix somehow?
+ cairo_get_matrix(cairo, &orig_matrix);
+ } else {
+ this->cairo = NULL;
+ this->cairo_shape = NULL;
+ }
+}
+
+void CairoOutputDev::setTextPage(TextPage *text)
+{
+ if (this->text)
+ this->text->decRefCnt();
+ if (actualText)
+ delete actualText;
+ if (text) {
+ this->text = text;
+ this->text->incRefCnt();
+ actualText = new ActualText(text);
+ } else {
+ this->text = NULL;
+ actualText = NULL;
+ }
+}
+
+void CairoOutputDev::startDoc(PDFDoc *docA,
+ CairoFontEngine *parentFontEngine) {
+ doc = docA;
+ if (parentFontEngine) {
+ fontEngine = parentFontEngine;
+ } else {
+ if (fontEngine) {
+ delete fontEngine;
+ }
+ fontEngine = new CairoFontEngine(ft_lib);
+ fontEngine_owner = gTrue;
+ }
+ xref = doc->getXRef();
+}
+
+void CairoOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) {
+ /* set up some per page defaults */
+ cairo_pattern_destroy(fill_pattern);
+ cairo_pattern_destroy(stroke_pattern);
+
+ fill_pattern = cairo_pattern_create_rgb(0., 0., 0.);
+ fill_color.r = fill_color.g = fill_color.b = 0;
+ stroke_pattern = cairo_pattern_reference(fill_pattern);
+ stroke_color.r = stroke_color.g = stroke_color.b = 0;
+
+ if (text)
+ text->startPage(state);
+ if (xrefA != NULL) {
+ xref = xrefA;
+ }
+}
+
+void CairoOutputDev::endPage() {
+ if (text) {
+ text->endPage();
+ text->coalesce(gTrue, 0, gFalse);
+ }
+}
+
+void CairoOutputDev::saveState(GfxState *state) {
+ LOG(printf ("save\n"));
+ cairo_save (cairo);
+ if (cairo_shape)
+ cairo_save (cairo_shape);
+
+ MaskStack *ms = new MaskStack;
+ ms->mask = cairo_pattern_reference(mask);
+ ms->mask_matrix = mask_matrix;
+ ms->next = maskStack;
+ maskStack = ms;
+}
+
+void CairoOutputDev::restoreState(GfxState *state) {
+ LOG(printf ("restore\n"));
+ cairo_restore (cairo);
+ if (cairo_shape)
+ cairo_restore (cairo_shape);
+
+ text_matrix_valid = gTrue;
+
+ /* These aren't restored by cairo_restore() since we keep them in
+ * the output device. */
+ updateFillColor(state);
+ updateStrokeColor(state);
+ updateFillOpacity(state);
+ updateStrokeOpacity(state);
+ updateBlendMode(state);
+
+ MaskStack* ms = maskStack;
+ if (ms) {
+ if (mask)
+ cairo_pattern_destroy(mask);
+ mask = ms->mask;
+ mask_matrix = ms->mask_matrix;
+ maskStack = ms->next;
+ delete ms;
+ }
+}
+
+void CairoOutputDev::updateAll(GfxState *state) {
+ updateLineDash(state);
+ updateLineJoin(state);
+ updateLineCap(state);
+ updateLineWidth(state);
+ updateFlatness(state);
+ updateMiterLimit(state);
+ updateFillColor(state);
+ updateStrokeColor(state);
+ updateFillOpacity(state);
+ updateStrokeOpacity(state);
+ updateBlendMode(state);
+ needFontUpdate = gTrue;
+ if (text)
+ text->updateFont(state);
+}
+
+void CairoOutputDev::setDefaultCTM(double *ctm) {
+ cairo_matrix_t matrix;
+ matrix.xx = ctm[0];
+ matrix.yx = ctm[1];
+ matrix.xy = ctm[2];
+ matrix.yy = ctm[3];
+ matrix.x0 = ctm[4];
+ matrix.y0 = ctm[5];
+
+ cairo_transform (cairo, &matrix);
+ if (cairo_shape)
+ cairo_transform (cairo_shape, &matrix);
+
+ OutputDev::setDefaultCTM(ctm);
+}
+
+void CairoOutputDev::updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22,
+ double m31, double m32) {
+ cairo_matrix_t matrix, invert_matrix;
+ matrix.xx = m11;
+ matrix.yx = m12;
+ matrix.xy = m21;
+ matrix.yy = m22;
+ matrix.x0 = m31;
+ matrix.y0 = m32;
+
+ /* Make sure the matrix is invertible before setting it.
+ * cairo will blow up if we give it a matrix that's not
+ * invertible, so we need to check before passing it
+ * to cairo_transform. Ignoring it is likely to give better
+ * results than not rendering anything at all. See #14398
+ *
+ * Ideally, we could do the cairo_transform
+ * and then check if anything went wrong and fix it then
+ * instead of having to invert the matrix. */
+ invert_matrix = matrix;
+ if (cairo_matrix_invert(&invert_matrix)) {
+ error(errSyntaxWarning, -1, "matrix not invertible\n");
+ return;
+ }
+
+ cairo_transform (cairo, &matrix);
+ if (cairo_shape)
+ cairo_transform (cairo_shape, &matrix);
+ updateLineDash(state);
+ updateLineJoin(state);
+ updateLineCap(state);
+ updateLineWidth(state);
+}
+
+void CairoOutputDev::updateLineDash(GfxState *state) {
+ double *dashPattern;
+ int dashLength;
+ double dashStart;
+
+ state->getLineDash(&dashPattern, &dashLength, &dashStart);
+ cairo_set_dash (cairo, dashPattern, dashLength, dashStart);
+ if (cairo_shape)
+ cairo_set_dash (cairo_shape, dashPattern, dashLength, dashStart);
+}
+
+void CairoOutputDev::updateFlatness(GfxState *state) {
+ // cairo_set_tolerance (cairo, state->getFlatness());
+}
+
+void CairoOutputDev::updateLineJoin(GfxState *state) {
+ switch (state->getLineJoin()) {
+ case 0:
+ cairo_set_line_join (cairo, CAIRO_LINE_JOIN_MITER);
+ break;
+ case 1:
+ cairo_set_line_join (cairo, CAIRO_LINE_JOIN_ROUND);
+ break;
+ case 2:
+ cairo_set_line_join (cairo, CAIRO_LINE_JOIN_BEVEL);
+ break;
+ }
+ if (cairo_shape)
+ cairo_set_line_join (cairo_shape, cairo_get_line_join(cairo));
+}
+
+void CairoOutputDev::updateLineCap(GfxState *state) {
+ switch (state->getLineCap()) {
+ case 0:
+ cairo_set_line_cap (cairo, CAIRO_LINE_CAP_BUTT);
+ break;
+ case 1:
+ cairo_set_line_cap (cairo, CAIRO_LINE_CAP_ROUND);
+ break;
+ case 2:
+ cairo_set_line_cap (cairo, CAIRO_LINE_CAP_SQUARE);
+ break;
+ }
+ if (cairo_shape)
+ cairo_set_line_cap (cairo_shape, cairo_get_line_cap(cairo));
+}
+
+void CairoOutputDev::updateMiterLimit(GfxState *state) {
+ cairo_set_miter_limit (cairo, state->getMiterLimit());
+ if (cairo_shape)
+ cairo_set_miter_limit (cairo_shape, state->getMiterLimit());
+}
+
+void CairoOutputDev::updateLineWidth(GfxState *state) {
+ LOG(printf ("line width: %f\n", state->getLineWidth()));
+ adjusted_stroke_width = gFalse;
+ double width = state->getLineWidth();
+ if (stroke_adjust && !printing) {
+ double x, y;
+ x = y = width;
+
+ /* find out line width in device units */
+ cairo_user_to_device_distance(cairo, &x, &y);
+ if (fabs(x) <= 1.0 && fabs(y) <= 1.0) {
+ /* adjust width to at least one device pixel */
+ x = y = 1.0;
+ cairo_device_to_user_distance(cairo, &x, &y);
+ width = MIN(fabs(x),fabs(y));
+ adjusted_stroke_width = gTrue;
+ }
+ } else if (width == 0.0) {
+ /* Cairo does not support 0 line width == 1 device pixel. Find out
+ * how big pixels (device unit) are in the x and y
+ * directions. Choose the smaller of the two as our line width.
+ */
+ double x = 1.0, y = 1.0;
+ if (printing) {
+ // assume printer pixel size is 1/600 inch
+ x = 72.0/600;
+ y = 72.0/600;
+ }
+ cairo_device_to_user_distance(cairo, &x, &y);
+ width = MIN(fabs(x),fabs(y));
+ }
+ cairo_set_line_width (cairo, width);
+ if (cairo_shape)
+ cairo_set_line_width (cairo_shape, cairo_get_line_width (cairo));
+}
+
+void CairoOutputDev::updateFillColor(GfxState *state) {
+ GfxRGB color = fill_color;
+
+ if (inUncoloredPattern)
+ return;
+
+ state->getFillRGB(&fill_color);
+ if (cairo_pattern_get_type (fill_pattern) != CAIRO_PATTERN_TYPE_SOLID ||
+ color.r != fill_color.r ||
+ color.g != fill_color.g ||
+ color.b != fill_color.b)
+ {
+ cairo_pattern_destroy(fill_pattern);
+ fill_pattern = cairo_pattern_create_rgba(colToDbl(fill_color.r),
+ colToDbl(fill_color.g),
+ colToDbl(fill_color.b),
+ fill_opacity);
+
+ LOG(printf ("fill color: %d %d %d\n",
+ fill_color.r, fill_color.g, fill_color.b));
+ }
+}
+
+void CairoOutputDev::updateStrokeColor(GfxState *state) {
+ GfxRGB color = stroke_color;
+
+ if (inUncoloredPattern)
+ return;
+
+ state->getStrokeRGB(&stroke_color);
+ if (cairo_pattern_get_type (fill_pattern) != CAIRO_PATTERN_TYPE_SOLID ||
+ color.r != stroke_color.r ||
+ color.g != stroke_color.g ||
+ color.b != stroke_color.b)
+ {
+ cairo_pattern_destroy(stroke_pattern);
+ stroke_pattern = cairo_pattern_create_rgba(colToDbl(stroke_color.r),
+ colToDbl(stroke_color.g),
+ colToDbl(stroke_color.b),
+ stroke_opacity);
+
+ LOG(printf ("stroke color: %d %d %d\n",
+ stroke_color.r, stroke_color.g, stroke_color.b));
+ }
+}
+
+void CairoOutputDev::updateFillOpacity(GfxState *state) {
+ double opacity = fill_opacity;
+
+ if (inUncoloredPattern)
+ return;
+
+ fill_opacity = state->getFillOpacity();
+ if (opacity != fill_opacity) {
+ cairo_pattern_destroy(fill_pattern);
+ fill_pattern = cairo_pattern_create_rgba(colToDbl(fill_color.r),
+ colToDbl(fill_color.g),
+ colToDbl(fill_color.b),
+ fill_opacity);
+
+ LOG(printf ("fill opacity: %f\n", fill_opacity));
+ }
+}
+
+void CairoOutputDev::updateStrokeOpacity(GfxState *state) {
+ double opacity = stroke_opacity;
+
+ if (inUncoloredPattern)
+ return;
+
+ stroke_opacity = state->getStrokeOpacity();
+ if (opacity != stroke_opacity) {
+ cairo_pattern_destroy(stroke_pattern);
+ stroke_pattern = cairo_pattern_create_rgba(colToDbl(stroke_color.r),
+ colToDbl(stroke_color.g),
+ colToDbl(stroke_color.b),
+ stroke_opacity);
+
+ LOG(printf ("stroke opacity: %f\n", stroke_opacity));
+ }
+}
+
+void CairoOutputDev::updateFillColorStop(GfxState *state, double offset) {
+ if (inUncoloredPattern)
+ return;
+
+ state->getFillRGB(&fill_color);
+
+ cairo_pattern_add_color_stop_rgba(fill_pattern, offset,
+ colToDbl(fill_color.r),
+ colToDbl(fill_color.g),
+ colToDbl(fill_color.b),
+ fill_opacity);
+ LOG(printf ("fill color stop: %f (%d, %d, %d)\n",
+ offset, fill_color.r, fill_color.g, fill_color.b));
+}
+
+void CairoOutputDev::updateBlendMode(GfxState *state) {
+ switch (state->getBlendMode()) {
+ default:
+ case gfxBlendNormal:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_OVER);
+ break;
+ case gfxBlendMultiply:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_MULTIPLY);
+ break;
+ case gfxBlendScreen:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_SCREEN);
+ break;
+ case gfxBlendOverlay:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_OVERLAY);
+ break;
+ case gfxBlendDarken:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_DARKEN);
+ break;
+ case gfxBlendLighten:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_LIGHTEN);
+ break;
+ case gfxBlendColorDodge:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_COLOR_DODGE);
+ break;
+ case gfxBlendColorBurn:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_COLOR_BURN);
+ break;
+ case gfxBlendHardLight:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_HARD_LIGHT);
+ break;
+ case gfxBlendSoftLight:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_SOFT_LIGHT);
+ break;
+ case gfxBlendDifference:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_DIFFERENCE);
+ break;
+ case gfxBlendExclusion:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_EXCLUSION);
+ break;
+ case gfxBlendHue:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_HUE);
+ break;
+ case gfxBlendSaturation:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_SATURATION);
+ break;
+ case gfxBlendColor:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_COLOR);
+ break;
+ case gfxBlendLuminosity:
+ cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_LUMINOSITY);
+ break;
+ }
+ LOG(printf ("blend mode: %d\n", (int)state->getBlendMode()));
+}
+
+void CairoOutputDev::updateFont(GfxState *state) {
+ cairo_font_face_t *font_face;
+ cairo_matrix_t matrix, invert_matrix;
+
+ LOG(printf ("updateFont() font=%s\n", state->getFont()->getName()->getCString()));
+
+ needFontUpdate = gFalse;
+
+ //FIXME: use cairo font engine?
+ if (text)
+ text->updateFont(state);
+
+ currentFont = fontEngine->getFont (state->getFont(), doc, printing, xref);
+
+ if (!currentFont)
+ return;
+
+ font_face = currentFont->getFontFace();
+ cairo_set_font_face (cairo, font_face);
+
+ use_show_text_glyphs = state->getFont()->hasToUnicodeCMap() &&
+ cairo_surface_has_show_text_glyphs (cairo_get_target (cairo));
+
+ double fontSize = state->getFontSize();
+ double *m = state->getTextMat();
+ /* NOTE: adjusting by a constant is hack. The correct solution
+ * is probably to use user-fonts and compute the scale on a per
+ * glyph basis instead of for the entire font */
+ double w = currentFont->getSubstitutionCorrection(state->getFont());
+ matrix.xx = m[0] * fontSize * state->getHorizScaling() * w;
+ matrix.yx = m[1] * fontSize * state->getHorizScaling() * w;
+ matrix.xy = -m[2] * fontSize;
+ matrix.yy = -m[3] * fontSize;
+ matrix.x0 = 0;
+ matrix.y0 = 0;
+
+ LOG(printf ("font matrix: %f %f %f %f\n", matrix.xx, matrix.yx, matrix.xy, matrix.yy));
+
+ /* Make sure the font matrix is invertible before setting it. cairo
+ * will blow up if we give it a matrix that's not invertible, so we
+ * need to check before passing it to cairo_set_font_matrix. Ignoring it
+ * is likely to give better results than not rendering anything at
+ * all. See #18254.
+ */
+ invert_matrix = matrix;
+ if (cairo_matrix_invert(&invert_matrix)) {
+ error(errSyntaxWarning, -1, "font matrix not invertible");
+ text_matrix_valid = gFalse;
+ return;
+ }
+
+ cairo_set_font_matrix (cairo, &matrix);
+ text_matrix_valid = gTrue;
+}
+
+/* Tolerance in pixels for checking if strokes are horizontal or vertical
+ * lines in device space */
+#define STROKE_COORD_TOLERANCE 0.5
+
+/* Align stroke coordinate i if the point is the start or end of a
+ * horizontal or vertical line */
+void CairoOutputDev::alignStrokeCoords(GfxSubpath *subpath, int i, double *x, double *y)
+{
+ double x1, y1, x2, y2;
+ GBool align = gFalse;
+
+ x1 = subpath->getX(i);
+ y1 = subpath->getY(i);
+ cairo_user_to_device (cairo, &x1, &y1);
+
+ // Does the current coord and prev coord form a horiz or vert line?
+ if (i > 0 && !subpath->getCurve(i - 1)) {
+ x2 = subpath->getX(i - 1);
+ y2 = subpath->getY(i - 1);
+ cairo_user_to_device (cairo, &x2, &y2);
+ if (fabs(x2 - x1) < STROKE_COORD_TOLERANCE || fabs(y2 - y1) < STROKE_COORD_TOLERANCE)
+ align = gTrue;
+ }
+
+ // Does the current coord and next coord form a horiz or vert line?
+ if (i < subpath->getNumPoints() - 1 && !subpath->getCurve(i + 1)) {
+ x2 = subpath->getX(i + 1);
+ y2 = subpath->getY(i + 1);
+ cairo_user_to_device (cairo, &x2, &y2);
+ if (fabs(x2 - x1) < STROKE_COORD_TOLERANCE || fabs(y2 - y1) < STROKE_COORD_TOLERANCE)
+ align = gTrue;
+ }
+
+ *x = subpath->getX(i);
+ *y = subpath->getY(i);
+ if (align) {
+ /* see http://www.cairographics.org/FAQ/#sharp_lines */
+ cairo_user_to_device (cairo, x, y);
+ *x = floor(*x) + 0.5;
+ *y = floor(*y) + 0.5;
+ cairo_device_to_user (cairo, x, y);
+ }
+}
+
+#undef STROKE_COORD_TOLERANCE
+
+void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) {
+ GfxSubpath *subpath;
+ int i, j;
+ double x, y;
+ cairo_new_path (cairo);
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ if (subpath->getNumPoints() > 0) {
+ if (align_stroke_coords) {
+ alignStrokeCoords(subpath, 0, &x, &y);
+ } else {
+ x = subpath->getX(0);
+ y = subpath->getY(0);
+ }
+ cairo_move_to (cairo, x, y);
+ j = 1;
+ while (j < subpath->getNumPoints()) {
+ if (subpath->getCurve(j)) {
+ if (align_stroke_coords) {
+ alignStrokeCoords(subpath, j + 2, &x, &y);
+ } else {
+ x = subpath->getX(j+2);
+ y = subpath->getY(j+2);
+ }
+ cairo_curve_to( cairo,
+ subpath->getX(j), subpath->getY(j),
+ subpath->getX(j+1), subpath->getY(j+1),
+ x, y);
+
+ j += 3;
+ } else {
+ if (align_stroke_coords) {
+ alignStrokeCoords(subpath, j, &x, &y);
+ } else {
+ x = subpath->getX(j);
+ y = subpath->getY(j);
+ }
+ cairo_line_to (cairo, x, y);
+ ++j;
+ }
+ }
+ if (subpath->isClosed()) {
+ LOG (printf ("close\n"));
+ cairo_close_path (cairo);
+ }
+ }
+ }
+}
+
+void CairoOutputDev::stroke(GfxState *state) {
+ if (inType3Char) {
+ GfxGray gray;
+ state->getFillGray(&gray);
+ if (colToDbl(gray) > 0.5)
+ return;
+ }
+
+ if (adjusted_stroke_width)
+ align_stroke_coords = gTrue;
+ doPath (cairo, state, state->getPath());
+ align_stroke_coords = gFalse;
+ cairo_set_source (cairo, stroke_pattern);
+ LOG(printf ("stroke\n"));
+ cairo_stroke (cairo);
+ if (cairo_shape) {
+ doPath (cairo_shape, state, state->getPath());
+ cairo_stroke (cairo_shape);
+ }
+}
+
+void CairoOutputDev::fill(GfxState *state) {
+ if (inType3Char) {
+ GfxGray gray;
+ state->getFillGray(&gray);
+ if (colToDbl(gray) > 0.5)
+ return;
+ }
+
+ doPath (cairo, state, state->getPath());
+ cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
+ cairo_set_source (cairo, fill_pattern);
+ LOG(printf ("fill\n"));
+ //XXX: how do we get the path
+ if (mask) {
+ cairo_save (cairo);
+ cairo_clip (cairo);
+ cairo_set_matrix (cairo, &mask_matrix);
+ cairo_mask (cairo, mask);
+ cairo_restore (cairo);
+ } else if (strokePathClip) {
+ fillToStrokePathClip(state);
+ } else {
+ cairo_fill (cairo);
+ }
+ if (cairo_shape) {
+ cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_WINDING);
+ doPath (cairo_shape, state, state->getPath());
+ cairo_fill (cairo_shape);
+ }
+}
+
+void CairoOutputDev::eoFill(GfxState *state) {
+ doPath (cairo, state, state->getPath());
+ cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_source (cairo, fill_pattern);
+ LOG(printf ("fill-eo\n"));
+ cairo_fill (cairo);
+
+ if (cairo_shape) {
+ cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_EVEN_ODD);
+ doPath (cairo_shape, state, state->getPath());
+ cairo_fill (cairo_shape);
+ }
+
+}
+
+GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat, Object *str,
+ double *pmat, int paintType, int /*tilingType*/, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep)
+{
+ PDFRectangle box;
+ Gfx *gfx;
+ cairo_pattern_t *pattern;
+ cairo_surface_t *surface;
+ cairo_matrix_t matrix;
+ cairo_matrix_t pattern_matrix;
+ cairo_t *old_cairo;
+ double xMin, yMin, xMax, yMax;
+ double width, height;
+ int surface_width, surface_height;
+ StrokePathClip *strokePathTmp;
+ GBool adjusted_stroke_width_tmp;
+
+ width = bbox[2] - bbox[0];
+ height = bbox[3] - bbox[1];
+
+ if (xStep != width || yStep != height)
+ return gFalse;
+ /* TODO: implement the other cases here too */
+
+ // Find the width and height of the transformed pattern
+ cairo_get_matrix (cairo, &matrix);
+ cairo_matrix_init (&pattern_matrix, mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ cairo_matrix_multiply (&matrix, &matrix, &pattern_matrix);
+
+ double widthX = width, widthY = 0;
+ cairo_matrix_transform_distance (&matrix, &widthX, &widthY);
+ surface_width = ceil (sqrt (widthX * widthX + widthY * widthY));
+
+ double heightX = 0, heightY = height;
+ cairo_matrix_transform_distance (&matrix, &heightX, &heightY);
+ surface_height = ceil (sqrt (heightX * heightX + heightY * heightY));
+
+ surface = cairo_surface_create_similar (cairo_get_target (cairo),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ surface_width, surface_height);
+ if (cairo_surface_status (surface))
+ return gFalse;
+
+ old_cairo = cairo;
+ cairo = cairo_create (surface);
+ cairo_surface_destroy (surface);
+ cairo_scale (cairo, surface_width / width, surface_height / height);
+
+ box.x1 = bbox[0]; box.y1 = bbox[1];
+ box.x2 = bbox[2]; box.y2 = bbox[3];
+ strokePathTmp = strokePathClip;
+ strokePathClip = NULL;
+ adjusted_stroke_width_tmp = adjusted_stroke_width;
+ gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gfxA->getXRef());
+ if (paintType == 2)
+ inUncoloredPattern = gTrue;
+ gfx->display(str);
+ if (paintType == 2)
+ inUncoloredPattern = gFalse;
+ delete gfx;
+ strokePathClip = strokePathTmp;
+ adjusted_stroke_width = adjusted_stroke_width_tmp;
+
+ pattern = cairo_pattern_create_for_surface (cairo_get_target (cairo));
+ cairo_destroy (cairo);
+ cairo = old_cairo;
+ if (cairo_pattern_status (pattern))
+ return gFalse;
+
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ cairo_rectangle (cairo, xMin, yMin, xMax - xMin, yMax - yMin);
+
+ cairo_matrix_init_scale (&matrix, surface_width / width, surface_height / height);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ cairo_transform (cairo, &pattern_matrix);
+ cairo_set_source (cairo, pattern);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+ if (strokePathClip) {
+ fillToStrokePathClip(state);
+ } else {
+ cairo_fill (cairo);
+ }
+
+ cairo_pattern_destroy (pattern);
+
+ return gTrue;
+}
+
+GBool CairoOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) {
+ double x0, y0, x1, y1;
+ double dx, dy;
+
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+
+ cairo_pattern_destroy(fill_pattern);
+ fill_pattern = cairo_pattern_create_linear (x0 + tMin * dx, y0 + tMin * dy,
+ x0 + tMax * dx, y0 + tMax * dy);
+ if (!shading->getExtend0() && !shading->getExtend1())
+ cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_NONE);
+ else
+ cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_PAD);
+
+ LOG (printf ("axial-sh\n"));
+
+ // TODO: use the actual stops in the shading in the case
+ // of linear interpolation (Type 2 Exponential functions with N=1)
+ return gFalse;
+}
+
+GBool CairoOutputDev::axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading)
+{
+ return (shading->getExtend0() == shading->getExtend1());
+}
+
+GBool CairoOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) {
+ double x0, y0, r0, x1, y1, r1;
+ double dx, dy, dr;
+
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ dr = r1 - r0;
+ cairo_pattern_destroy(fill_pattern);
+ fill_pattern = cairo_pattern_create_radial (x0 + sMin * dx,
+ y0 + sMin * dy,
+ r0 + sMin * dr,
+ x0 + sMax * dx,
+ y0 + sMax * dy,
+ r0 + sMax * dr);
+ if (shading->getExtend0() && shading->getExtend1())
+ cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_PAD);
+ else
+ cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_NONE);
+
+ LOG (printf ("radial-sh\n"));
+
+ return gFalse;
+}
+
+GBool CairoOutputDev::radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading)
+{
+ return (shading->getExtend0() == shading->getExtend1());
+}
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+GBool CairoOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+{
+ double x0, y0, x1, y1, x2, y2;
+ GfxColor color[3];
+ int i, j;
+ GfxRGB rgb;
+
+ cairo_pattern_destroy(fill_pattern);
+ fill_pattern = cairo_pattern_create_mesh ();
+
+ for (i = 0; i < shading->getNTriangles(); i++) {
+ if (shading->isParameterized()) {
+ double color0, color1, color2;
+ shading->getTriangle(i, &x0, &y0, &color0,
+ &x1, &y1, &color1,
+ &x2, &y2, &color2);
+ shading->getParameterizedColor(color0, &color[0]);
+ shading->getParameterizedColor(color1, &color[1]);
+ shading->getParameterizedColor(color2, &color[2]);
+ } else {
+ shading->getTriangle(i,
+ &x0, &y0, &color[0],
+ &x1, &y1, &color[1],
+ &x2, &y2, &color[2]);
+
+ }
+
+ cairo_mesh_pattern_begin_patch (fill_pattern);
+
+ cairo_mesh_pattern_move_to (fill_pattern, x0, y0);
+ cairo_mesh_pattern_line_to (fill_pattern, x1, y1);
+ cairo_mesh_pattern_line_to (fill_pattern, x2, y2);
+
+ for (j = 0; j < 3; j++) {
+ shading->getColorSpace()->getRGB(&color[j], &rgb);
+ cairo_mesh_pattern_set_corner_color_rgb (fill_pattern, j,
+ colToDbl(rgb.r),
+ colToDbl(rgb.g),
+ colToDbl(rgb.b));
+ }
+
+ cairo_mesh_pattern_end_patch (fill_pattern);
+ }
+
+ double xMin, yMin, xMax, yMax;
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMin, yMax);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMax, yMin);
+ state->closePath();
+ fill(state);
+ state->clearPath();
+
+ return gTrue;
+}
+
+GBool CairoOutputDev::patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
+{
+ int i, j, k;
+
+ cairo_pattern_destroy(fill_pattern);
+ fill_pattern = cairo_pattern_create_mesh ();
+
+ for (i = 0; i < shading->getNPatches(); i++) {
+ GfxPatch *patch = shading->getPatch(i);
+ GfxColor color;
+ GfxRGB rgb;
+
+ cairo_mesh_pattern_begin_patch (fill_pattern);
+
+ cairo_mesh_pattern_move_to (fill_pattern, patch->x[0][0], patch->y[0][0]);
+ cairo_mesh_pattern_curve_to (fill_pattern,
+ patch->x[0][1], patch->y[0][1],
+ patch->x[0][2], patch->y[0][2],
+ patch->x[0][3], patch->y[0][3]);
+
+ cairo_mesh_pattern_curve_to (fill_pattern,
+ patch->x[1][3], patch->y[1][3],
+ patch->x[2][3], patch->y[2][3],
+ patch->x[3][3], patch->y[3][3]);
+
+ cairo_mesh_pattern_curve_to (fill_pattern,
+ patch->x[3][2], patch->y[3][2],
+ patch->x[3][1], patch->y[3][1],
+ patch->x[3][0], patch->y[3][0]);
+
+ cairo_mesh_pattern_curve_to (fill_pattern,
+ patch->x[2][0], patch->y[2][0],
+ patch->x[1][0], patch->y[1][0],
+ patch->x[0][0], patch->y[0][0]);
+
+ cairo_mesh_pattern_set_control_point (fill_pattern, 0, patch->x[1][1], patch->y[1][1]);
+ cairo_mesh_pattern_set_control_point (fill_pattern, 1, patch->x[1][2], patch->y[1][2]);
+ cairo_mesh_pattern_set_control_point (fill_pattern, 2, patch->x[2][2], patch->y[2][2]);
+ cairo_mesh_pattern_set_control_point (fill_pattern, 3, patch->x[2][1], patch->y[2][1]);
+
+ for (j = 0; j < 4; j++) {
+ int u, v;
+
+ switch (j) {
+ case 0:
+ u = 0; v = 0;
+ break;
+ case 1:
+ u = 0; v = 1;
+ break;
+ case 2:
+ u = 1; v = 1;
+ break;
+ case 3:
+ u = 1; v = 0;
+ break;
+ }
+
+ if (shading->isParameterized()) {
+ shading->getParameterizedColor (patch->color[u][v].c[0], &color);
+ } else {
+ for (k = 0; k < shading->getColorSpace()->getNComps(); k++) {
+ // simply cast to the desired type; that's all what is needed.
+ color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
+ }
+ }
+
+ shading->getColorSpace()->getRGB(&color, &rgb);
+ cairo_mesh_pattern_set_corner_color_rgb (fill_pattern, j,
+ colToDbl(rgb.r),
+ colToDbl(rgb.g),
+ colToDbl(rgb.b));
+ }
+ cairo_mesh_pattern_end_patch (fill_pattern);
+ }
+
+ double xMin, yMin, xMax, yMax;
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMin, yMax);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMax, yMin);
+ state->closePath();
+ fill(state);
+ state->clearPath();
+
+ return gTrue;
+}
+#endif /* CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) */
+
+void CairoOutputDev::clip(GfxState *state) {
+ doPath (cairo, state, state->getPath());
+ cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
+ cairo_clip (cairo);
+ LOG (printf ("clip\n"));
+ if (cairo_shape) {
+ doPath (cairo_shape, state, state->getPath());
+ cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_WINDING);
+ cairo_clip (cairo_shape);
+ }
+}
+
+void CairoOutputDev::eoClip(GfxState *state) {
+ doPath (cairo, state, state->getPath());
+ cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip (cairo);
+ LOG (printf ("clip-eo\n"));
+ if (cairo_shape) {
+ doPath (cairo_shape, state, state->getPath());
+ cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip (cairo_shape);
+ }
+
+}
+
+void CairoOutputDev::clipToStrokePath(GfxState *state) {
+ LOG(printf("clip-to-stroke-path\n"));
+ strokePathClip = (StrokePathClip*)gmalloc (sizeof(*strokePathClip));
+ strokePathClip->path = state->getPath()->copy();
+ cairo_get_matrix (cairo, &strokePathClip->ctm);
+ strokePathClip->line_width = cairo_get_line_width (cairo);
+ strokePathClip->dash_count = cairo_get_dash_count (cairo);
+ if (strokePathClip->dash_count) {
+ strokePathClip->dashes = (double*) gmallocn (sizeof(double), strokePathClip->dash_count);
+ cairo_get_dash (cairo, strokePathClip->dashes, &strokePathClip->dash_offset);
+ } else {
+ strokePathClip->dashes = NULL;
+ }
+ strokePathClip->cap = cairo_get_line_cap (cairo);
+ strokePathClip->join = cairo_get_line_join (cairo);
+ strokePathClip->miter = cairo_get_miter_limit (cairo);
+}
+
+void CairoOutputDev::fillToStrokePathClip(GfxState *state) {
+ cairo_save (cairo);
+
+ cairo_set_matrix (cairo, &strokePathClip->ctm);
+ cairo_set_line_width (cairo, strokePathClip->line_width);
+ strokePathClip->dash_count = cairo_get_dash_count (cairo);
+ cairo_set_dash (cairo, strokePathClip->dashes, strokePathClip->dash_count, strokePathClip->dash_offset);
+ cairo_set_line_cap (cairo, strokePathClip->cap);
+ cairo_set_line_join (cairo, strokePathClip->join);
+ cairo_set_miter_limit (cairo, strokePathClip->miter);
+ doPath (cairo, state, strokePathClip->path);
+ cairo_stroke (cairo);
+
+ cairo_restore (cairo);
+
+ delete strokePathClip->path;
+ if (strokePathClip->dashes)
+ gfree (strokePathClip->dashes);
+ gfree (strokePathClip);
+ strokePathClip = NULL;
+}
+
+void CairoOutputDev::beginString(GfxState *state, GooString *s)
+{
+ int len = s->getLength();
+
+ if (needFontUpdate)
+ updateFont(state);
+
+ if (!currentFont)
+ return;
+
+ glyphs = (cairo_glyph_t *) gmallocn (len, sizeof (cairo_glyph_t));
+ glyphCount = 0;
+ if (use_show_text_glyphs) {
+ clusters = (cairo_text_cluster_t *) gmallocn (len, sizeof (cairo_text_cluster_t));
+ clusterCount = 0;
+ utf8Max = len*2; // start with twice the number of glyphs. we will realloc if we need more.
+ utf8 = (char *) gmalloc (utf8Max);
+ utf8Count = 0;
+ }
+}
+
+void CairoOutputDev::drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode code, int nBytes, Unicode *u, int uLen)
+{
+ if (currentFont) {
+ glyphs[glyphCount].index = currentFont->getGlyph (code, u, uLen);
+ glyphs[glyphCount].x = x - originX;
+ glyphs[glyphCount].y = y - originY;
+ glyphCount++;
+ if (use_show_text_glyphs) {
+ GooString enc("UTF-8");
+ UnicodeMap *utf8Map = globalParams->getUnicodeMap(&enc);
+ if (utf8Max - utf8Count < uLen*6) {
+ // utf8 encoded characters can be up to 6 bytes
+ if (utf8Max > uLen*6)
+ utf8Max *= 2;
+ else
+ utf8Max += 2*uLen*6;
+ utf8 = (char *) grealloc (utf8, utf8Max);
+ }
+ clusters[clusterCount].num_bytes = 0;
+ for (int i = 0; i < uLen; i++) {
+ int size = utf8Map->mapUnicode(u[i], utf8 + utf8Count, utf8Max - utf8Count);
+ utf8Count += size;
+ clusters[clusterCount].num_bytes += size;
+ }
+ clusters[clusterCount].num_glyphs = 1;
+ clusterCount++;
+ }
+ }
+
+ if (!text)
+ return;
+ actualText->addChar (state, x, y, dx, dy, code, nBytes, u, uLen);
+}
+
+void CairoOutputDev::endString(GfxState *state)
+{
+ int render;
+
+ if (!currentFont)
+ return;
+
+ // endString can be called without a corresponding beginString. If this
+ // happens glyphs will be null so don't draw anything, just return.
+ // XXX: OutputDevs should probably not have to deal with this...
+ if (!glyphs)
+ return;
+
+ // ignore empty strings and invisible text -- this is used by
+ // Acrobat Capture
+ render = state->getRender();
+ if (render == 3 || glyphCount == 0 || !text_matrix_valid) {
+ goto finish;
+ }
+
+ if (!(render & 1)) {
+ LOG (printf ("fill string\n"));
+ cairo_set_source (cairo, fill_pattern);
+ if (use_show_text_glyphs)
+ cairo_show_text_glyphs (cairo, utf8, utf8Count, glyphs, glyphCount, clusters, clusterCount, (cairo_text_cluster_flags_t)0);
+ else
+ cairo_show_glyphs (cairo, glyphs, glyphCount);
+ if (cairo_shape)
+ cairo_show_glyphs (cairo_shape, glyphs, glyphCount);
+ }
+
+ // stroke
+ if ((render & 3) == 1 || (render & 3) == 2) {
+ LOG (printf ("stroke string\n"));
+ cairo_set_source (cairo, stroke_pattern);
+ cairo_glyph_path (cairo, glyphs, glyphCount);
+ cairo_stroke (cairo);
+ if (cairo_shape) {
+ cairo_glyph_path (cairo_shape, glyphs, glyphCount);
+ cairo_stroke (cairo_shape);
+ }
+ }
+
+ // clip
+ if ((render & 4)) {
+ LOG (printf ("clip string\n"));
+ // append the glyph path to textClipPath.
+
+ // set textClipPath as the currentPath
+ if (textClipPath) {
+ cairo_append_path (cairo, textClipPath);
+ if (cairo_shape) {
+ cairo_append_path (cairo_shape, textClipPath);
+ }
+ cairo_path_destroy (textClipPath);
+ }
+
+ // append the glyph path
+ cairo_glyph_path (cairo, glyphs, glyphCount);
+
+ // move the path back into textClipPath
+ // and clear the current path
+ textClipPath = cairo_copy_path (cairo);
+ cairo_new_path (cairo);
+ if (cairo_shape) {
+ cairo_new_path (cairo_shape);
+ }
+ }
+
+finish:
+ gfree (glyphs);
+ glyphs = NULL;
+ if (use_show_text_glyphs) {
+ gfree (clusters);
+ clusters = NULL;
+ gfree (utf8);
+ utf8 = NULL;
+ }
+}
+
+
+GBool CairoOutputDev::beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen) {
+
+ cairo_save (cairo);
+ double *ctm;
+ cairo_matrix_t matrix;
+
+ ctm = state->getCTM();
+ matrix.xx = ctm[0];
+ matrix.yx = ctm[1];
+ matrix.xy = ctm[2];
+ matrix.yy = ctm[3];
+ matrix.x0 = ctm[4];
+ matrix.y0 = ctm[5];
+ /* Restore the original matrix and then transform to matrix needed for the
+ * type3 font. This is ugly but seems to work. Perhaps there is a better way to do it?*/
+ cairo_set_matrix(cairo, &orig_matrix);
+ cairo_transform(cairo, &matrix);
+ if (cairo_shape) {
+ cairo_save (cairo_shape);
+ cairo_set_matrix(cairo_shape, &orig_matrix);
+ cairo_transform(cairo_shape, &matrix);
+ }
+ cairo_pattern_destroy(stroke_pattern);
+ cairo_pattern_reference(fill_pattern);
+ stroke_pattern = fill_pattern;
+ return gFalse;
+}
+
+void CairoOutputDev::endType3Char(GfxState *state) {
+ cairo_restore (cairo);
+ if (cairo_shape) {
+ cairo_restore (cairo_shape);
+ }
+}
+
+void CairoOutputDev::type3D0(GfxState *state, double wx, double wy) {
+ t3_glyph_wx = wx;
+ t3_glyph_wy = wy;
+}
+
+void CairoOutputDev::type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury) {
+ t3_glyph_wx = wx;
+ t3_glyph_wy = wy;
+ t3_glyph_bbox[0] = llx;
+ t3_glyph_bbox[1] = lly;
+ t3_glyph_bbox[2] = urx;
+ t3_glyph_bbox[3] = ury;
+ t3_glyph_has_bbox = gTrue;
+}
+
+void CairoOutputDev::beginTextObject(GfxState *state) {
+}
+
+void CairoOutputDev::endTextObject(GfxState *state) {
+ if (textClipPath) {
+ // clip the accumulated text path
+ cairo_append_path (cairo, textClipPath);
+ cairo_clip (cairo);
+ if (cairo_shape) {
+ cairo_append_path (cairo_shape, textClipPath);
+ cairo_clip (cairo_shape);
+ }
+ cairo_path_destroy (textClipPath);
+ textClipPath = NULL;
+ }
+}
+
+void CairoOutputDev::beginActualText(GfxState *state, GooString *text)
+{
+ if (this->text)
+ actualText->begin(state, text);
+}
+
+void CairoOutputDev::endActualText(GfxState *state)
+{
+ if (text)
+ actualText->end(state);
+}
+
+static inline int splashRound(SplashCoord x) {
+ return (int)floor(x + 0.5);
+}
+
+static inline int splashCeil(SplashCoord x) {
+ return (int)ceil(x);
+}
+
+static inline int splashFloor(SplashCoord x) {
+ return (int)floor(x);
+}
+
+static
+cairo_surface_t *cairo_surface_create_similar_clip (cairo_t *cairo, cairo_content_t content)
+{
+ cairo_pattern_t *pattern;
+ cairo_surface_t *surface = NULL;
+
+ cairo_push_group_with_content (cairo, content);
+ pattern = cairo_pop_group (cairo);
+ cairo_pattern_get_surface (pattern, &surface);
+ cairo_surface_reference (surface);
+ cairo_pattern_destroy (pattern);
+ return surface;
+}
+
+
+
+void CairoOutputDev::beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/,
+ GfxColorSpace * blendingColorSpace,
+ GBool /*isolated*/, GBool knockout,
+ GBool forSoftMask) {
+ /* push color space */
+ ColorSpaceStack* css = new ColorSpaceStack;
+ css->cs = blendingColorSpace;
+ css->knockout = knockout;
+ cairo_get_matrix(cairo, &css->group_matrix);
+ css->next = groupColorSpaceStack;
+ groupColorSpaceStack = css;
+
+ LOG(printf ("begin transparency group. knockout: %s\n", knockout ? "yes":"no"));
+
+ if (knockout) {
+ knockoutCount++;
+ if (!cairo_shape) {
+ /* create a surface for tracking the shape */
+ cairo_surface_t *cairo_shape_surface = cairo_surface_create_similar_clip (cairo, CAIRO_CONTENT_ALPHA);
+ cairo_shape = cairo_create (cairo_shape_surface);
+ cairo_surface_destroy (cairo_shape_surface);
+
+ /* the color doesn't matter as long as it is opaque */
+ cairo_set_source_rgb (cairo_shape, 0, 0, 0);
+ cairo_matrix_t matrix;
+ cairo_get_matrix (cairo, &matrix);
+ //printMatrix(&matrix);
+ cairo_set_matrix (cairo_shape, &matrix);
+ } else {
+ cairo_reference (cairo_shape);
+ }
+ }
+ if (groupColorSpaceStack->next && groupColorSpaceStack->next->knockout) {
+ /* we need to track the shape */
+ cairo_push_group (cairo_shape);
+ }
+ if (0 && forSoftMask)
+ cairo_push_group_with_content (cairo, CAIRO_CONTENT_ALPHA);
+ else
+ cairo_push_group (cairo);
+
+ /* push_group has an implicit cairo_save() */
+ if (knockout) {
+ /*XXX: let's hope this matches the semantics needed */
+ cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
+ } else {
+ cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
+ }
+}
+
+void CairoOutputDev::endTransparencyGroup(GfxState * /*state*/) {
+ if (group)
+ cairo_pattern_destroy(group);
+ group = cairo_pop_group (cairo);
+
+ LOG(printf ("end transparency group\n"));
+
+ if (groupColorSpaceStack->next && groupColorSpaceStack->next->knockout) {
+ if (shape)
+ cairo_pattern_destroy(shape);
+ shape = cairo_pop_group (cairo_shape);
+ }
+}
+
+void CairoOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) {
+ LOG(printf ("paint transparency group\n"));
+
+ cairo_save (cairo);
+ cairo_set_matrix (cairo, &groupColorSpaceStack->group_matrix);
+ cairo_set_source (cairo, group);
+
+ if (!mask) {
+ //XXX: deal with mask && shape case
+ if (shape) {
+ cairo_save (cairo);
+
+ /* OPERATOR_SOURCE w/ a mask is defined as (src IN mask) ADD (dest OUT mask)
+ * however our source has already been clipped to mask so we only need to
+ * do ADD and OUT */
+
+ /* clear the shape mask */
+ cairo_set_source (cairo, shape);
+ cairo_set_operator (cairo, CAIRO_OPERATOR_DEST_OUT);
+ cairo_paint (cairo);
+
+ cairo_set_operator (cairo, CAIRO_OPERATOR_ADD);
+ cairo_set_source (cairo, group);
+ cairo_paint (cairo);
+
+ cairo_restore (cairo);
+
+ cairo_pattern_destroy (shape);
+ shape = NULL;
+ } else {
+ cairo_paint_with_alpha (cairo, fill_opacity);
+ }
+ cairo_status_t status = cairo_status(cairo);
+ if (status)
+ printf("BAD status: %s\n", cairo_status_to_string(status));
+ } else {
+ if (fill_opacity < 1.0) {
+ cairo_push_group(cairo);
+ }
+ cairo_save(cairo);
+ cairo_set_matrix(cairo, &mask_matrix);
+ cairo_mask(cairo, mask);
+ cairo_restore(cairo);
+ if (fill_opacity < 1.0) {
+ cairo_pop_group_to_source(cairo);
+ cairo_paint_with_alpha (cairo, fill_opacity);
+ }
+ cairo_pattern_destroy(mask);
+ mask = NULL;
+ }
+
+ popTransparencyGroup();
+ cairo_restore(cairo);
+}
+
+static int luminocity(uint32_t x)
+{
+ int r = (x >> 16) & 0xff;
+ int g = (x >> 8) & 0xff;
+ int b = (x >> 0) & 0xff;
+ // an arbitrary integer approximation of .3*r + .59*g + .11*b
+ int y = (r*19661+g*38666+b*7209 + 32829)>>16;
+ return y;
+}
+
+
+/* XXX: do we need to deal with shape here? */
+void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha,
+ Function * transferFunc, GfxColor * backdropColor) {
+ cairo_pattern_destroy(mask);
+
+ LOG(printf ("set softMask\n"));
+
+ if (!alpha || transferFunc) {
+ /* We need to mask according to the luminocity of the group.
+ * So we paint the group to an image surface convert it to a luminocity map
+ * and then use that as the mask. */
+
+ /* Get clip extents in device space */
+ double x1, y1, x2, y2, x_min, y_min, x_max, y_max;
+ cairo_clip_extents(cairo, &x1, &y1, &x2, &y2);
+ cairo_user_to_device(cairo, &x1, &y1);
+ cairo_user_to_device(cairo, &x2, &y2);
+ x_min = MIN(x1, x2);
+ y_min = MIN(y1, y2);
+ x_max = MAX(x1, x2);
+ y_max = MAX(y1, y2);
+ cairo_clip_extents(cairo, &x1, &y1, &x2, &y2);
+ cairo_user_to_device(cairo, &x1, &y2);
+ cairo_user_to_device(cairo, &x2, &y1);
+ x_min = MIN(x_min,MIN(x1, x2));
+ y_min = MIN(y_min,MIN(y1, y2));
+ x_max = MAX(x_max,MAX(x1, x2));
+ y_max = MAX(y_max,MAX(y1, y2));
+
+ int width = (int)(ceil(x_max) - floor(x_min));
+ int height = (int)(ceil(y_max) - floor(y_min));
+
+ /* Get group device offset */
+ double x_offset, y_offset;
+ if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) {
+ cairo_surface_get_device_offset(cairo_get_group_target(cairo), &x_offset, &y_offset);
+ } else {
+ cairo_surface_t *pats;
+ cairo_pattern_get_surface(group, &pats);
+ cairo_surface_get_device_offset(pats, &x_offset, &y_offset);
+ }
+
+ /* Adjust extents by group offset */
+ x_min += x_offset;
+ y_min += y_offset;
+
+ cairo_surface_t *source = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ cairo_t *maskCtx = cairo_create(source);
+
+ //XXX: hopefully this uses the correct color space */
+ if (!alpha && groupColorSpaceStack->cs) {
+ GfxRGB backdropColorRGB;
+ groupColorSpaceStack->cs->getRGB(backdropColor, &backdropColorRGB);
+ /* paint the backdrop */
+ cairo_set_source_rgb(maskCtx,
+ colToDbl(backdropColorRGB.r),
+ colToDbl(backdropColorRGB.g),
+ colToDbl(backdropColorRGB.b));
+ }
+ cairo_paint(maskCtx);
+
+ /* Copy source ctm to mask ctm and translate origin so that the
+ * mask appears it the same location on the source surface. */
+ cairo_matrix_t mat, tmat;
+ cairo_matrix_init_translate(&tmat, -x_min, -y_min);
+ cairo_get_matrix(cairo, &mat);
+ cairo_matrix_multiply(&mat, &mat, &tmat);
+ cairo_set_matrix(maskCtx, &mat);
+
+ /* make the device offset of the new mask match that of the group */
+ cairo_surface_set_device_offset(source, x_offset, y_offset);
+
+ /* paint the group */
+ cairo_set_source(maskCtx, group);
+ cairo_paint(maskCtx);
+
+ /* XXX status = cairo_status(maskCtx); */
+ cairo_destroy(maskCtx);
+
+ /* convert to a luminocity map */
+ uint32_t *source_data = (uint32_t*)cairo_image_surface_get_data(source);
+ /* get stride in units of 32 bits */
+ int stride = cairo_image_surface_get_stride(source)/4;
+ for (int y=0; y<height; y++) {
+ for (int x=0; x<width; x++) {
+ int lum = alpha ? fill_opacity : luminocity(source_data[y*stride + x]);
+ if (transferFunc) {
+ double lum_in, lum_out;
+ lum_in = lum/256.0;
+ transferFunc->transform(&lum_in, &lum_out);
+ lum = (int)(lum_out * 255.0 + 0.5);
+ }
+ source_data[y*stride + x] = lum << 24;
+ }
+ }
+ cairo_surface_mark_dirty (source);
+
+ /* setup the new mask pattern */
+ mask = cairo_pattern_create_for_surface(source);
+ cairo_get_matrix(cairo, &mask_matrix);
+
+ if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) {
+ cairo_pattern_set_matrix(mask, &mat);
+ } else {
+ cairo_matrix_t patMatrix;
+ cairo_pattern_get_matrix(group, &patMatrix);
+ /* Apply x_min, y_min offset to it appears in the same location as source. */
+ cairo_matrix_multiply(&patMatrix, &patMatrix, &tmat);
+ cairo_pattern_set_matrix(mask, &patMatrix);
+ }
+
+ cairo_surface_destroy(source);
+ } else if (alpha) {
+ mask = cairo_pattern_reference(group);
+ cairo_get_matrix(cairo, &mask_matrix);
+ }
+
+ popTransparencyGroup();
+}
+
+void CairoOutputDev::popTransparencyGroup() {
+ /* pop color space */
+ ColorSpaceStack *css = groupColorSpaceStack;
+ if (css->knockout) {
+ knockoutCount--;
+ if (!knockoutCount) {
+ /* we don't need to track the shape anymore because
+ * we are not above any knockout groups */
+ cairo_destroy(cairo_shape);
+ cairo_shape = NULL;
+ }
+ }
+ groupColorSpaceStack = css->next;
+ delete css;
+}
+
+
+void CairoOutputDev::clearSoftMask(GfxState * /*state*/) {
+ if (mask)
+ cairo_pattern_destroy(mask);
+ mask = NULL;
+}
+
+/* Taken from cairo/doc/tutorial/src/singular.c */
+static void
+get_singular_values (const cairo_matrix_t *matrix,
+ double *major,
+ double *minor)
+{
+ double xx = matrix->xx, xy = matrix->xy;
+ double yx = matrix->yx, yy = matrix->yy;
+
+ double a = xx*xx+yx*yx;
+ double b = xy*xy+yy*yy;
+ double k = xx*xy+yx*yy;
+
+ double f = (a+b) * .5;
+ double g = (a-b) * .5;
+ double delta = sqrt (g*g + k*k);
+
+ if (major)
+ *major = sqrt (f + delta);
+ if (minor)
+ *minor = sqrt (f - delta);
+}
+
+void CairoOutputDev::getScaledSize(const cairo_matrix_t *matrix,
+ int orig_width,
+ int orig_height,
+ int *scaledWidth,
+ int *scaledHeight)
+{
+ double xScale;
+ double yScale;
+ if (orig_width > orig_height)
+ get_singular_values (matrix, &xScale, &yScale);
+ else
+ get_singular_values (matrix, &yScale, &xScale);
+
+ int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */
+ if (xScale >= 0) {
+ tx = splashRound(matrix->x0 - 0.01);
+ tx2 = splashRound(matrix->x0 + xScale + 0.01) - 1;
+ } else {
+ tx = splashRound(matrix->x0 + 0.01) - 1;
+ tx2 = splashRound(matrix->x0 + xScale - 0.01);
+ }
+ *scaledWidth = abs(tx2 - tx) + 1;
+ //scaledWidth = splashRound(fabs(xScale));
+ if (*scaledWidth == 0) {
+ // technically, this should draw nothing, but it generally seems
+ // better to draw a one-pixel-wide stripe rather than throwing it
+ // away
+ *scaledWidth = 1;
+ }
+ if (yScale >= 0) {
+ ty = splashFloor(matrix->y0 + 0.01);
+ ty2 = splashCeil(matrix->y0 + yScale - 0.01);
+ } else {
+ ty = splashCeil(matrix->y0 - 0.01);
+ ty2 = splashFloor(matrix->y0 + yScale + 0.01);
+ }
+ *scaledHeight = abs(ty2 - ty);
+ if (*scaledHeight == 0) {
+ *scaledHeight = 1;
+ }
+}
+
+cairo_filter_t
+CairoOutputDev::getFilterForSurface(cairo_surface_t *image,
+ GBool interpolate)
+{
+ if (interpolate)
+ return CAIRO_FILTER_BILINEAR;
+
+ int orig_width = cairo_image_surface_get_width (image);
+ int orig_height = cairo_image_surface_get_height (image);
+ if (orig_width == 0 || orig_height == 0)
+ return CAIRO_FILTER_NEAREST;
+
+ /* When printing, don't change the interpolation. */
+ if (printing)
+ return CAIRO_FILTER_NEAREST;
+
+ cairo_matrix_t matrix;
+ cairo_get_matrix(cairo, &matrix);
+ int scaled_width, scaled_height;
+ getScaledSize (&matrix, orig_width, orig_height, &scaled_width, &scaled_height);
+
+ /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */
+ if (scaled_width / orig_width >= 4 || scaled_height / orig_height >= 4)
+ return CAIRO_FILTER_NEAREST;
+
+ return CAIRO_FILTER_BILINEAR;
+}
+
+void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg) {
+
+ /* FIXME: Doesn't the image mask support any colorspace? */
+ cairo_set_source (cairo, fill_pattern);
+
+ /* work around a cairo bug when scaling 1x1 surfaces */
+ if (width == 1 && height == 1) {
+ ImageStream *imgStr;
+ Guchar pix;
+ int invert_bit;
+
+ imgStr = new ImageStream(str, width, 1, 1);
+ imgStr->reset();
+ imgStr->getPixel(&pix);
+ imgStr->close();
+ delete imgStr;
+
+ invert_bit = invert ? 1 : 0;
+ if (pix ^ invert_bit)
+ return;
+
+ cairo_save (cairo);
+ cairo_rectangle (cairo, 0., 0., width, height);
+ cairo_fill (cairo);
+ cairo_restore (cairo);
+ if (cairo_shape) {
+ cairo_save (cairo_shape);
+ cairo_rectangle (cairo_shape, 0., 0., width, height);
+ cairo_fill (cairo_shape);
+ cairo_restore (cairo_shape);
+ }
+ return;
+ }
+
+ /* shape is 1.0 for painted areas, 0.0 for unpainted ones */
+
+ cairo_matrix_t matrix;
+ cairo_get_matrix (cairo, &matrix);
+ //XXX: it is possible that we should only do sub pixel positioning if
+ // we are rendering fonts */
+ if (!printing && prescaleImages
+ /* not rotated */
+ && matrix.xy == 0 && matrix.yx == 0
+ /* axes not flipped / not 180 deg rotated */
+ && matrix.xx > 0 && (upsideDown() ? -1 : 1) * matrix.yy > 0) {
+ drawImageMaskPrescaled(state, ref, str, width, height, invert, interpolate, inlineImg);
+ } else {
+ drawImageMaskRegular(state, ref, str, width, height, invert, interpolate, inlineImg);
+ }
+
+}
+
+void CairoOutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix) {
+
+ /* FIXME: Doesn't the image mask support any colorspace? */
+ cairo_set_source (cairo, fill_pattern);
+
+ /* work around a cairo bug when scaling 1x1 surfaces */
+ if (width == 1 && height == 1) {
+ ImageStream *imgStr;
+ Guchar pix;
+ int invert_bit;
+
+ imgStr = new ImageStream(str, width, 1, 1);
+ imgStr->reset();
+ imgStr->getPixel(&pix);
+ imgStr->close();
+ delete imgStr;
+
+ invert_bit = invert ? 1 : 0;
+ if (!(pix ^ invert_bit)) {
+ cairo_save (cairo);
+ cairo_rectangle (cairo, 0., 0., width, height);
+ cairo_fill (cairo);
+ cairo_restore (cairo);
+ if (cairo_shape) {
+ cairo_save (cairo_shape);
+ cairo_rectangle (cairo_shape, 0., 0., width, height);
+ cairo_fill (cairo_shape);
+ cairo_restore (cairo_shape);
+ }
+ }
+ } else {
+ cairo_push_group_with_content (cairo, CAIRO_CONTENT_ALPHA);
+
+ /* shape is 1.0 for painted areas, 0.0 for unpainted ones */
+
+ cairo_matrix_t matrix;
+ cairo_get_matrix (cairo, &matrix);
+ //XXX: it is possible that we should only do sub pixel positioning if
+ // we are rendering fonts */
+ if (!printing && prescaleImages && matrix.xy == 0.0 && matrix.yx == 0.0) {
+ drawImageMaskPrescaled(state, ref, str, width, height, invert, gFalse, inlineImg);
+ } else {
+ drawImageMaskRegular(state, ref, str, width, height, invert, gFalse, inlineImg);
+ }
+
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ cairo_set_source_rgb (cairo, 1, 1, 1);
+ cairo_set_matrix (cairo, &mask_matrix);
+ cairo_mask (cairo, mask);
+ }
+
+ if (mask)
+ cairo_pattern_destroy (mask);
+ mask = cairo_pop_group (cairo);
+ }
+
+ saveState(state);
+ double bbox[4] = {0,0,1,1}; // dummy
+ beginTransparencyGroup(state, bbox, state->getFillColorSpace(),
+ gTrue, gFalse, gFalse);
+}
+
+void CairoOutputDev::unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) {
+ double bbox[4] = {0,0,1,1}; // dummy
+
+ endTransparencyGroup(state);
+ restoreState(state);
+ paintTransparencyGroup(state, bbox);
+ clearSoftMask(state);
+}
+
+void CairoOutputDev::drawImageMaskRegular(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg) {
+ unsigned char *buffer;
+ unsigned char *dest;
+ cairo_surface_t *image;
+ cairo_pattern_t *pattern;
+ int x, y, i, bit;
+ ImageStream *imgStr;
+ Guchar *pix;
+ cairo_matrix_t matrix;
+ int invert_bit;
+ int row_stride;
+ cairo_filter_t filter;
+
+ /* TODO: Do we want to cache these? */
+ imgStr = new ImageStream(str, width, 1, 1);
+ imgStr->reset();
+
+ image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
+ if (cairo_surface_status (image))
+ goto cleanup;
+
+ buffer = cairo_image_surface_get_data (image);
+ row_stride = cairo_image_surface_get_stride (image);
+
+ invert_bit = invert ? 1 : 0;
+
+ for (y = 0; y < height; y++) {
+ pix = imgStr->getLine();
+ dest = buffer + y * row_stride;
+ i = 0;
+ bit = 0;
+ for (x = 0; x < width; x++) {
+ if (bit == 0)
+ dest[i] = 0;
+ if (!(pix[x] ^ invert_bit)) {
+#ifdef WORDS_BIGENDIAN
+ dest[i] |= (1 << (7 - bit));
+#else
+ dest[i] |= (1 << bit);
+#endif
+ }
+ bit++;
+ if (bit > 7) {
+ bit = 0;
+ i++;
+ }
+ }
+ }
+
+ filter = getFilterForSurface (image, interpolate);
+
+ cairo_surface_mark_dirty (image);
+ pattern = cairo_pattern_create_for_surface (image);
+ cairo_surface_destroy (image);
+ if (cairo_pattern_status (pattern))
+ goto cleanup;
+
+ LOG (printf ("drawImageMask %dx%d\n", width, height));
+
+ cairo_pattern_set_filter (pattern, filter);
+
+ if (!printing)
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+
+ cairo_matrix_init_translate (&matrix, 0, height);
+ cairo_matrix_scale (&matrix, width, -height);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ if (cairo_pattern_status (pattern)) {
+ cairo_pattern_destroy (pattern);
+ goto cleanup;
+ }
+
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ mask = cairo_pattern_reference (pattern);
+ cairo_get_matrix (cairo, &mask_matrix);
+ } else if (!printing) {
+ cairo_save (cairo);
+ cairo_rectangle (cairo, 0., 0., 1., 1.);
+ cairo_clip (cairo);
+ cairo_mask (cairo, pattern);
+ cairo_restore (cairo);
+ } else {
+ cairo_mask (cairo, pattern);
+ }
+
+ if (cairo_shape) {
+ cairo_save (cairo_shape);
+ cairo_set_source (cairo_shape, pattern);
+ if (!printing) {
+ cairo_rectangle (cairo_shape, 0., 0., 1., 1.);
+ cairo_fill (cairo_shape);
+ } else {
+ cairo_mask (cairo_shape, pattern);
+ }
+ cairo_restore (cairo_shape);
+ }
+
+ cairo_pattern_destroy (pattern);
+
+cleanup:
+ imgStr->close();
+ delete imgStr;
+}
+
+
+void CairoOutputDev::drawImageMaskPrescaled(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg) {
+ unsigned char *buffer;
+ cairo_surface_t *image;
+ cairo_pattern_t *pattern;
+ ImageStream *imgStr;
+ Guchar *pix;
+ cairo_matrix_t matrix;
+ int invert_bit;
+ int row_stride;
+
+ /* cairo does a very poor job of scaling down images so we scale them ourselves */
+
+ LOG (printf ("drawImageMaskPrescaled %dx%d\n", width, height));
+
+ /* this scaling code is adopted from the splash image scaling code */
+ cairo_get_matrix(cairo, &matrix);
+#if 0
+ printf("[%f %f], [%f %f], %f %f\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.x0, matrix.y0);
+#endif
+ /* this whole computation should be factored out */
+ double xScale = matrix.xx;
+ double yScale = matrix.yy;
+ int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */
+ int scaledHeight;
+ int scaledWidth;
+ if (xScale >= 0) {
+ tx = splashRound(matrix.x0 - 0.01);
+ tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1;
+ } else {
+ tx = splashRound(matrix.x0 + 0.01) - 1;
+ tx2 = splashRound(matrix.x0 + xScale - 0.01);
+ }
+ scaledWidth = abs(tx2 - tx) + 1;
+ //scaledWidth = splashRound(fabs(xScale));
+ if (scaledWidth == 0) {
+ // technically, this should draw nothing, but it generally seems
+ // better to draw a one-pixel-wide stripe rather than throwing it
+ // away
+ scaledWidth = 1;
+ }
+ if (yScale >= 0) {
+ ty = splashFloor(matrix.y0 + 0.01);
+ ty2 = splashCeil(matrix.y0 + yScale - 0.01);
+ } else {
+ ty = splashCeil(matrix.y0 - 0.01);
+ ty2 = splashFloor(matrix.y0 + yScale + 0.01);
+ }
+ scaledHeight = abs(ty2 - ty);
+ if (scaledHeight == 0) {
+ scaledHeight = 1;
+ }
+#if 0
+ printf("xscale: %g, yscale: %g\n", xScale, yScale);
+ printf("width: %d, height: %d\n", width, height);
+ printf("scaledWidth: %d, scaledHeight: %d\n", scaledWidth, scaledHeight);
+#endif
+
+ /* compute the required padding */
+ /* Padding is used to preserve the aspect ratio.
+ We compute total_pad to make (height+total_pad)/scaledHeight as close to height/yScale as possible */
+ int head_pad = 0;
+ int tail_pad = 0;
+ int total_pad = splashRound(height*(scaledHeight/fabs(yScale)) - height);
+
+ /* compute the two pieces of padding */
+ if (total_pad > 0) {
+ //XXX: i'm not positive fabs() is correct
+ float tail_error = fabs(matrix.y0 - ty);
+ float head_error = fabs(ty2 - (matrix.y0 + yScale));
+ float tail_fraction = tail_error/(tail_error + head_error);
+ tail_pad = splashRound(total_pad*tail_fraction);
+ head_pad = total_pad - tail_pad;
+ } else {
+ tail_pad = 0;
+ head_pad = 0;
+ }
+ int origHeight = height;
+ height += tail_pad;
+ height += head_pad;
+#if 0
+ printf("head_pad: %d tail_pad: %d\n", head_pad, tail_pad);
+ printf("origHeight: %d height: %d\n", origHeight, height);
+ printf("ty: %d, ty2: %d\n", ty, ty2);
+#endif
+
+ /* TODO: Do we want to cache these? */
+ imgStr = new ImageStream(str, width, 1, 1);
+ imgStr->reset();
+
+ invert_bit = invert ? 1 : 0;
+
+ image = cairo_image_surface_create (CAIRO_FORMAT_A8, scaledWidth, scaledHeight);
+ if (cairo_surface_status (image)) {
+ imgStr->close();
+ delete imgStr;
+ return;
+ }
+
+ buffer = cairo_image_surface_get_data (image);
+ row_stride = cairo_image_surface_get_stride (image);
+
+ int yp = height / scaledHeight;
+ int yq = height % scaledHeight;
+ int xp = width / scaledWidth;
+ int xq = width % scaledWidth;
+ int yt = 0;
+ int origHeight_c = origHeight;
+ /* use MIN() because yp might be > origHeight because of padding */
+ unsigned char *pixBuf = (unsigned char *)malloc(MIN(yp+1, origHeight)*width);
+ int lastYStep = 1;
+ int total = 0;
+ for (int y = 0; y < scaledHeight; y++) {
+ // y scale Bresenham
+ int yStep = yp;
+ yt += yq;
+
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+
+ // read row (s) from image ignoring the padding as appropriate
+ {
+ int n = (yp > 0) ? yStep : lastYStep;
+ total += n;
+ if (n > 0) {
+ unsigned char *p = pixBuf;
+ int head_pad_count = head_pad;
+ int origHeight_count = origHeight;
+ int tail_pad_count = tail_pad;
+ for (int i=0; i<n; i++) {
+ // get row
+ if (head_pad_count) {
+ head_pad_count--;
+ } else if (origHeight_count) {
+ pix = imgStr->getLine();
+ for (int j=0; j<width; j++) {
+ if (pix[j] ^ invert_bit)
+ p[j] = 0;
+ else
+ p[j] = 255;
+ }
+ origHeight_count--;
+ p += width;
+ } else if (tail_pad_count) {
+ tail_pad_count--;
+ } else {
+ printf("%d %d\n", n, total);
+ assert(0 && "over run\n");
+ }
+ }
+ }
+ }
+
+ lastYStep = yStep;
+ int k1 = y;
+
+ int xt = 0;
+ int xSrc = 0;
+ int x1 = k1;
+ int n = yStep > 0 ? yStep : 1;
+ int origN = n;
+
+ /* compute the size of padding and pixels that will be used for this row */
+ int head_pad_size = MIN(n, head_pad);
+ n -= head_pad_size;
+ head_pad -= MIN(head_pad_size, yStep);
+
+ int pix_size = MIN(n, origHeight);
+ n -= pix_size;
+ origHeight -= MIN(pix_size, yStep);
+
+ int tail_pad_size = MIN(n, tail_pad);
+ n -= tail_pad_size;
+ tail_pad -= MIN(tail_pad_size, yStep);
+ if (n != 0) {
+ printf("n = %d (%d %d %d)\n", n, head_pad_size, pix_size, tail_pad_size);
+ assert(n == 0);
+ }
+
+ for (int x = 0; x < scaledWidth; ++x) {
+ int xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+ int m = xStep > 0 ? xStep : 1;
+ float pixAcc0 = 0;
+ /* could m * head_pad_size * tail_pad_size overflow? */
+ if (invert_bit) {
+ pixAcc0 += m * head_pad_size * tail_pad_size * 255;
+ } else {
+ pixAcc0 += m * head_pad_size * tail_pad_size * 0;
+ }
+ /* Accumulate all of the source pixels for the destination pixel */
+ for (int i = 0; i < pix_size; ++i) {
+ for (int j = 0; j< m; ++j) {
+ if (xSrc + i*width + j > MIN(yp + 1, origHeight_c)*width) {
+ printf("%d > %d (%d %d %d %d) (%d %d %d)\n", xSrc + i*width + j, MIN(yp + 1, origHeight_c)*width, xSrc, i , width, j, yp, origHeight_c, width);
+ printf("%d %d %d\n", head_pad_size, pix_size, tail_pad_size);
+ assert(0 && "bad access\n");
+ }
+ pixAcc0 += pixBuf[xSrc + i*width + j];
+ }
+ }
+ buffer[y * row_stride + x] = splashFloor(pixAcc0 / (origN*m));
+ xSrc += xStep;
+ x1 += 1;
+ }
+
+ }
+ free(pixBuf);
+
+ cairo_surface_mark_dirty (image);
+ pattern = cairo_pattern_create_for_surface (image);
+ cairo_surface_destroy (image);
+ if (cairo_pattern_status (pattern)) {
+ imgStr->close();
+ delete imgStr;
+ return;
+ }
+
+ /* we should actually be using CAIRO_FILTER_NEAREST here. However,
+ * cairo doesn't yet do minifaction filtering causing scaled down
+ * images with CAIRO_FILTER_NEAREST to look really bad */
+ cairo_pattern_set_filter (pattern,
+ interpolate ? CAIRO_FILTER_BEST : CAIRO_FILTER_FAST);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ cairo_matrix_init_translate (&matrix, 0, scaledHeight);
+ cairo_matrix_scale (&matrix, scaledWidth, -scaledHeight);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ if (cairo_pattern_status (pattern)) {
+ cairo_pattern_destroy (pattern);
+ imgStr->close();
+ delete imgStr;
+ return;
+ }
+
+ mask = cairo_pattern_reference (pattern);
+ cairo_get_matrix (cairo, &mask_matrix);
+ } else {
+ cairo_save (cairo);
+
+ /* modify our current transformation so that the prescaled image
+ * goes where it is supposed to */
+ cairo_get_matrix(cairo, &matrix);
+ cairo_scale(cairo, 1.0/matrix.xx, 1.0/matrix.yy);
+ // get integer co-ords
+ cairo_translate (cairo, tx - matrix.x0, ty2 - matrix.y0);
+ if (yScale > 0)
+ cairo_scale(cairo, 1, -1);
+
+ cairo_rectangle (cairo, 0., 0., scaledWidth, scaledHeight);
+ cairo_clip (cairo);
+ cairo_mask (cairo, pattern);
+
+ //cairo_get_matrix(cairo, &matrix);
+ //printf("mask at: [%f %f], [%f %f], %f %f\n\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.x0, matrix.y0);
+ cairo_restore(cairo);
+ }
+
+ if (cairo_shape) {
+ cairo_save (cairo_shape);
+
+ /* modify our current transformation so that the prescaled image
+ * goes where it is supposed to */
+ cairo_get_matrix(cairo_shape, &matrix);
+ cairo_scale(cairo_shape, 1.0/matrix.xx, 1.0/matrix.yy);
+ // get integer co-ords
+ cairo_translate (cairo_shape, tx - matrix.x0, ty2 - matrix.y0);
+ if (yScale > 0)
+ cairo_scale(cairo_shape, 1, -1);
+
+ cairo_rectangle (cairo_shape, 0., 0., scaledWidth, scaledHeight);
+ cairo_fill (cairo_shape);
+
+ cairo_restore(cairo_shape);
+ }
+
+ cairo_pattern_destroy (pattern);
+
+ imgStr->close();
+ delete imgStr;
+}
+
+void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref,
+ Stream *str, int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr, int maskWidth,
+ int maskHeight, GBool maskInvert,
+ GBool maskInterpolate)
+{
+ ImageStream *maskImgStr, *imgStr;
+ int row_stride;
+ unsigned char *maskBuffer, *buffer;
+ unsigned char *maskDest;
+ unsigned int *dest;
+ cairo_surface_t *maskImage, *image;
+ cairo_pattern_t *maskPattern, *pattern;
+ cairo_matrix_t matrix;
+ cairo_matrix_t maskMatrix;
+ Guchar *pix;
+ int x, y;
+ int invert_bit;
+ cairo_filter_t filter;
+ cairo_filter_t maskFilter;
+
+ maskImgStr = new ImageStream(maskStr, maskWidth, 1, 1);
+ maskImgStr->reset();
+
+ maskImage = cairo_image_surface_create (CAIRO_FORMAT_A8, maskWidth, maskHeight);
+ if (cairo_surface_status (maskImage)) {
+ maskImgStr->close();
+ delete maskImgStr;
+ return;
+ }
+
+ maskBuffer = cairo_image_surface_get_data (maskImage);
+ row_stride = cairo_image_surface_get_stride (maskImage);
+
+ invert_bit = maskInvert ? 1 : 0;
+
+ for (y = 0; y < maskHeight; y++) {
+ pix = maskImgStr->getLine();
+ maskDest = maskBuffer + y * row_stride;
+ for (x = 0; x < maskWidth; x++) {
+ if (pix[x] ^ invert_bit)
+ *maskDest++ = 0;
+ else
+ *maskDest++ = 255;
+ }
+ }
+
+ maskImgStr->close();
+ delete maskImgStr;
+
+ maskFilter = getFilterForSurface (maskImage, maskInterpolate);
+
+ cairo_surface_mark_dirty (maskImage);
+ maskPattern = cairo_pattern_create_for_surface (maskImage);
+ cairo_surface_destroy (maskImage);
+ if (cairo_pattern_status (maskPattern))
+ return;
+
+#if 0
+ /* ICCBased color space doesn't do any color correction
+ * so check its underlying color space as well */
+ int is_identity_transform;
+ is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
+ (colorMap->getColorSpace()->getMode() == csICCBased &&
+ ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB);
+#endif
+
+ /* TODO: Do we want to cache these? */
+ imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+ image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+ if (cairo_surface_status (image))
+ goto cleanup;
+
+ buffer = cairo_image_surface_get_data (image);
+ row_stride = cairo_image_surface_get_stride (image);
+ for (y = 0; y < height; y++) {
+ dest = (unsigned int *) (buffer + y * row_stride);
+ pix = imgStr->getLine();
+ colorMap->getRGBLine (pix, dest, width);
+ }
+
+ filter = getFilterForSurface (image, interpolate);
+
+ cairo_surface_mark_dirty (image);
+ pattern = cairo_pattern_create_for_surface (image);
+ cairo_surface_destroy (image);
+ if (cairo_pattern_status (pattern))
+ goto cleanup;
+
+ LOG (printf ("drawMaskedImage %dx%d\n", width, height));
+
+ cairo_pattern_set_filter (pattern, filter);
+ cairo_pattern_set_filter (maskPattern, maskFilter);
+
+ if (!printing) {
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+ cairo_pattern_set_extend (maskPattern, CAIRO_EXTEND_PAD);
+ }
+
+ cairo_matrix_init_translate (&matrix, 0, height);
+ cairo_matrix_scale (&matrix, width, -height);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ if (cairo_pattern_status (pattern)) {
+ cairo_pattern_destroy (pattern);
+ cairo_pattern_destroy (maskPattern);
+ goto cleanup;
+ }
+
+ cairo_matrix_init_translate (&maskMatrix, 0, maskHeight);
+ cairo_matrix_scale (&maskMatrix, maskWidth, -maskHeight);
+ cairo_pattern_set_matrix (maskPattern, &maskMatrix);
+ if (cairo_pattern_status (maskPattern)) {
+ cairo_pattern_destroy (maskPattern);
+ cairo_pattern_destroy (pattern);
+ goto cleanup;
+ }
+
+ if (!printing) {
+ cairo_save (cairo);
+ cairo_set_source (cairo, pattern);
+ cairo_rectangle (cairo, 0., 0., 1., 1.);
+ cairo_clip (cairo);
+ cairo_mask (cairo, maskPattern);
+ cairo_restore (cairo);
+ } else {
+ cairo_set_source (cairo, pattern);
+ cairo_mask (cairo, maskPattern);
+ }
+
+ if (cairo_shape) {
+ cairo_save (cairo_shape);
+ cairo_set_source (cairo_shape, pattern);
+ if (!printing) {
+ cairo_rectangle (cairo_shape, 0., 0., 1., 1.);
+ cairo_fill (cairo_shape);
+ } else {
+ cairo_mask (cairo_shape, pattern);
+ }
+ cairo_restore (cairo_shape);
+ }
+
+ cairo_pattern_destroy (maskPattern);
+ cairo_pattern_destroy (pattern);
+
+cleanup:
+ imgStr->close();
+ delete imgStr;
+}
+
+
+//XXX: is this affect by AIS(alpha is shape)?
+void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate)
+{
+ ImageStream *maskImgStr, *imgStr;
+ int row_stride;
+ unsigned char *maskBuffer, *buffer;
+ unsigned char *maskDest;
+ unsigned int *dest;
+ cairo_surface_t *maskImage, *image;
+ cairo_pattern_t *maskPattern, *pattern;
+ cairo_matrix_t maskMatrix, matrix;
+ Guchar *pix;
+ int y;
+ cairo_filter_t filter;
+ cairo_filter_t maskFilter;
+
+ maskImgStr = new ImageStream(maskStr, maskWidth,
+ maskColorMap->getNumPixelComps(),
+ maskColorMap->getBits());
+ maskImgStr->reset();
+
+ maskImage = cairo_image_surface_create (CAIRO_FORMAT_A8, maskWidth, maskHeight);
+ if (cairo_surface_status (maskImage)) {
+ maskImgStr->close();
+ delete maskImgStr;
+ return;
+ }
+
+ maskBuffer = cairo_image_surface_get_data (maskImage);
+ row_stride = cairo_image_surface_get_stride (maskImage);
+ for (y = 0; y < maskHeight; y++) {
+ maskDest = (unsigned char *) (maskBuffer + y * row_stride);
+ pix = maskImgStr->getLine();
+ maskColorMap->getGrayLine (pix, maskDest, maskWidth);
+ }
+
+ maskImgStr->close();
+ delete maskImgStr;
+
+ maskFilter = getFilterForSurface (maskImage, maskInterpolate);
+
+ cairo_surface_mark_dirty (maskImage);
+ maskPattern = cairo_pattern_create_for_surface (maskImage);
+ cairo_surface_destroy (maskImage);
+ if (cairo_pattern_status (maskPattern))
+ return;
+
+#if 0
+ /* ICCBased color space doesn't do any color correction
+ * so check its underlying color space as well */
+ int is_identity_transform;
+ is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
+ (colorMap->getColorSpace()->getMode() == csICCBased &&
+ ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB);
+#endif
+
+ /* TODO: Do we want to cache these? */
+ imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+ image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+ if (cairo_surface_status (image))
+ goto cleanup;
+
+ buffer = cairo_image_surface_get_data (image);
+ row_stride = cairo_image_surface_get_stride (image);
+ for (y = 0; y < height; y++) {
+ dest = (unsigned int *) (buffer + y * row_stride);
+ pix = imgStr->getLine();
+ colorMap->getRGBLine (pix, dest, width);
+ }
+
+ filter = getFilterForSurface (image, interpolate);
+
+ cairo_surface_mark_dirty (image);
+
+ setMimeData(state, str, ref, colorMap, image);
+
+ pattern = cairo_pattern_create_for_surface (image);
+ cairo_surface_destroy (image);
+ if (cairo_pattern_status (pattern))
+ goto cleanup;
+
+ LOG (printf ("drawSoftMaskedImage %dx%d\n", width, height));
+
+ cairo_pattern_set_filter (pattern, filter);
+ cairo_pattern_set_filter (maskPattern, maskFilter);
+
+ if (!printing) {
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+ cairo_pattern_set_extend (maskPattern, CAIRO_EXTEND_PAD);
+ }
+
+ cairo_matrix_init_translate (&matrix, 0, height);
+ cairo_matrix_scale (&matrix, width, -height);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ if (cairo_pattern_status (pattern)) {
+ cairo_pattern_destroy (pattern);
+ cairo_pattern_destroy (maskPattern);
+ goto cleanup;
+ }
+
+ cairo_matrix_init_translate (&maskMatrix, 0, maskHeight);
+ cairo_matrix_scale (&maskMatrix, maskWidth, -maskHeight);
+ cairo_pattern_set_matrix (maskPattern, &maskMatrix);
+ if (cairo_pattern_status (maskPattern)) {
+ cairo_pattern_destroy (maskPattern);
+ cairo_pattern_destroy (pattern);
+ goto cleanup;
+ }
+
+ if (fill_opacity != 1.0)
+ cairo_push_group (cairo);
+ else
+ cairo_save (cairo);
+
+ cairo_set_source (cairo, pattern);
+ if (!printing) {
+ cairo_rectangle (cairo, 0., 0., 1., 1.);
+ cairo_clip (cairo);
+ }
+ cairo_mask (cairo, maskPattern);
+
+ if (fill_opacity != 1.0) {
+ cairo_pop_group_to_source (cairo);
+ cairo_save (cairo);
+ if (!printing) {
+ cairo_rectangle (cairo, 0., 0., 1., 1.);
+ cairo_clip (cairo);
+ }
+ cairo_paint_with_alpha (cairo, fill_opacity);
+ }
+ cairo_restore (cairo);
+
+ if (cairo_shape) {
+ cairo_save (cairo_shape);
+ cairo_set_source (cairo_shape, pattern);
+ if (!printing) {
+ cairo_rectangle (cairo_shape, 0., 0., 1., 1.);
+ cairo_fill (cairo_shape);
+ } else {
+ cairo_mask (cairo_shape, pattern);
+ }
+ cairo_restore (cairo_shape);
+ }
+
+ cairo_pattern_destroy (maskPattern);
+ cairo_pattern_destroy (pattern);
+
+cleanup:
+ imgStr->close();
+ delete imgStr;
+}
+
+GBool CairoOutputDev::getStreamData (Stream *str, char **buffer, int *length)
+{
+ int len, i;
+ char *strBuffer;
+
+ len = 0;
+ str->close();
+ str->reset();
+ while (str->getChar() != EOF) len++;
+ if (len == 0)
+ return gFalse;
+
+ strBuffer = (char *)gmalloc (len);
+
+ str->close();
+ str->reset();
+ for (i = 0; i < len; ++i)
+ strBuffer[i] = str->getChar();
+
+ *buffer = strBuffer;
+ *length = len;
+
+ return gTrue;
+}
+
+static GBool colorMapHasIdentityDecodeMap(GfxImageColorMap *colorMap)
+{
+ for (int i = 0; i < colorMap->getNumPixelComps(); i++) {
+ if (colorMap->getDecodeLow(i) != 0.0 || colorMap->getDecodeHigh(i) != 1.0)
+ return gFalse;
+ }
+ return gTrue;
+}
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2)
+static cairo_status_t setMimeIdFromRef(cairo_surface_t *surface,
+ const char *mime_type,
+ const char *mime_id_prefix,
+ Ref ref)
+{
+ GooString *mime_id;
+ char *idBuffer;
+ cairo_status_t status;
+
+ mime_id = new GooString;
+
+ if (mime_id_prefix)
+ mime_id->append(mime_id_prefix);
+
+ mime_id->appendf("{0:d}-{1:d}", ref.gen, ref.num);
+
+ idBuffer = copyString(mime_id->getCString());
+ status = cairo_surface_set_mime_data (surface, mime_type,
+ (const unsigned char *)idBuffer,
+ mime_id->getLength(),
+ gfree, idBuffer);
+ delete mime_id;
+ if (status)
+ gfree (idBuffer);
+ return status;
+}
+#endif
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0)
+GBool CairoOutputDev::setMimeDataForJBIG2Globals(Stream *str,
+ cairo_surface_t *image)
+{
+ JBIG2Stream *jb2Str = static_cast<JBIG2Stream *>(str);
+ Object* globalsStr = jb2Str->getGlobalsStream();
+ char *globalsBuffer;
+ int globalsLength;
+
+ // nothing to do for JBIG2 stream without Globals
+ if (!globalsStr->isStream())
+ return gTrue;
+
+ if (setMimeIdFromRef(image, CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, NULL,
+ jb2Str->getGlobalsStreamRef()))
+ return gFalse;
+
+ if (!getStreamData(globalsStr->getStream(), &globalsBuffer, &globalsLength))
+ return gFalse;
+
+ if (cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JBIG2_GLOBAL,
+ (const unsigned char*)globalsBuffer,
+ globalsLength,
+ gfree, (void*)globalsBuffer))
+ {
+ gfree (globalsBuffer);
+ return gFalse;
+ }
+
+ return gTrue;
+}
+#endif
+
+void CairoOutputDev::setMimeData(GfxState *state, Stream *str, Object *ref,
+ GfxImageColorMap *colorMap, cairo_surface_t *image)
+{
+ char *strBuffer;
+ int len;
+ Object obj;
+ GfxColorSpace *colorSpace;
+ StreamKind strKind = str->getKind();
+ const char *mime_type;
+
+ if (!printing)
+ return;
+
+ switch (strKind) {
+ case strDCT:
+ mime_type = CAIRO_MIME_TYPE_JPEG;
+ break;
+ case strJPX:
+ mime_type = CAIRO_MIME_TYPE_JP2;
+ break;
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0)
+ case strJBIG2:
+ mime_type = CAIRO_MIME_TYPE_JBIG2;
+ break;
+#endif
+ default:
+ return;
+ }
+
+ str->getDict()->lookup("ColorSpace", &obj);
+ colorSpace = GfxColorSpace::parse(NULL, &obj, this, state);
+ obj.free();
+
+ // colorspace in stream dict may be different from colorspace in jpx
+ // data
+ if (strKind == strJPX && colorSpace)
+ return;
+
+ // only embed mime data for gray, rgb, and cmyk colorspaces.
+ if (colorSpace) {
+ GfxColorSpaceMode mode = colorSpace->getMode();
+ delete colorSpace;
+ switch (mode) {
+ case csDeviceGray:
+ case csCalGray:
+ case csDeviceRGB:
+ case csCalRGB:
+ case csDeviceCMYK:
+ case csICCBased:
+ break;
+
+ case csLab:
+ case csIndexed:
+ case csSeparation:
+ case csDeviceN:
+ case csPattern:
+ return;
+ }
+ }
+
+ if (!colorMapHasIdentityDecodeMap(colorMap))
+ return;
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0)
+ if (strKind == strJBIG2 && !setMimeDataForJBIG2Globals(str, image))
+ return;
+#endif
+
+ if (getStreamData (str->getNextStream(), &strBuffer, &len)) {
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2)
+ if (ref && ref->isRef()) {
+ status = setMimeIdFromRef(image, CAIRO_MIME_TYPE_UNIQUE_ID,
+ "poppler-surface-", ref->getRef());
+ }
+#endif
+ if (!status) {
+ status = cairo_surface_set_mime_data (image, mime_type,
+ (const unsigned char *)strBuffer, len,
+ gfree, strBuffer);
+ }
+
+ if (status)
+ gfree (strBuffer);
+ }
+}
+
+class RescaleDrawImage : public CairoRescaleBox {
+private:
+ ImageStream *imgStr;
+ GfxRGB *lookup;
+ int width;
+ GfxImageColorMap *colorMap;
+ int *maskColors;
+ int current_row;
+ GBool imageError;
+
+public:
+ cairo_surface_t *getSourceImage(Stream *str,
+ int widthA, int height,
+ int scaledWidth, int scaledHeight,
+ GBool printing,
+ GfxImageColorMap *colorMapA,
+ int *maskColorsA) {
+ cairo_surface_t *image = NULL;
+ int i;
+
+ lookup = NULL;
+ colorMap = colorMapA;
+ maskColors = maskColorsA;
+ width = widthA;
+ current_row = -1;
+ imageError = gFalse;
+
+ /* TODO: Do we want to cache these? */
+ imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+#if 0
+ /* ICCBased color space doesn't do any color correction
+ * so check its underlying color space as well */
+ int is_identity_transform;
+ is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
+ (colorMap->getColorSpace()->getMode() == csICCBased &&
+ ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB);
+#endif
+
+ // special case for one-channel (monochrome/gray/separation) images:
+ // build a lookup table here
+ if (colorMap->getNumPixelComps() == 1) {
+ int n;
+ Guchar pix;
+
+ n = 1 << colorMap->getBits();
+ lookup = (GfxRGB *)gmallocn(n, sizeof(GfxRGB));
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+
+ colorMap->getRGB(&pix, &lookup[i]);
+ }
+ }
+
+ if (printing || scaledWidth >= width || scaledHeight >= height) {
+ // No downscaling. Create cairo image containing the source image data.
+ unsigned char *buffer;
+ int stride;
+
+ image = cairo_image_surface_create (maskColors ?
+ CAIRO_FORMAT_ARGB32 :
+ CAIRO_FORMAT_RGB24,
+ width, height);
+ if (cairo_surface_status (image))
+ goto cleanup;
+
+ buffer = cairo_image_surface_get_data (image);
+ stride = cairo_image_surface_get_stride (image);
+ for (int y = 0; y < height; y++) {
+ uint32_t *dest = (uint32_t *) (buffer + y * stride);
+ getRow(y, dest);
+ }
+ } else {
+ // // Downscaling required. Create cairo image the size of the
+ // rescaled image and // downscale the source image data into
+ // the cairo image. downScaleImage() will call getRow() to read
+ // source image data from the image stream. This avoids having
+ // to create an image the size of the source image which may
+ // exceed cairo's 32676x32767 image size limit (and also saves a
+ // lot of memory).
+ image = cairo_image_surface_create (maskColors ?
+ CAIRO_FORMAT_ARGB32 :
+ CAIRO_FORMAT_RGB24,
+ scaledWidth, scaledHeight);
+ if (cairo_surface_status (image))
+ goto cleanup;
+
+ downScaleImage(width, height,
+ scaledWidth, scaledHeight,
+ 0, 0, scaledWidth, scaledHeight,
+ image);
+ }
+ cairo_surface_mark_dirty (image);
+
+ cleanup:
+ gfree(lookup);
+ imgStr->close();
+ delete imgStr;
+ return image;
+ }
+
+ void getRow(int row_num, uint32_t *row_data) {
+ int i;
+ Guchar *pix;
+
+ if (row_num <= current_row)
+ return;
+
+ while (current_row < row_num) {
+ pix = imgStr->getLine();
+ current_row++;
+ }
+
+ if (unlikely(pix == NULL)) {
+ memset(row_data, 0, width*4);
+ if (!imageError) {
+ error(errInternal, -1, "Bad image stream");
+ imageError = gTrue;
+ }
+ } else if (lookup) {
+ Guchar *p = pix;
+ GfxRGB rgb;
+
+ for (i = 0; i < width; i++) {
+ rgb = lookup[*p];
+ row_data[i] =
+ ((int) colToByte(rgb.r) << 16) |
+ ((int) colToByte(rgb.g) << 8) |
+ ((int) colToByte(rgb.b) << 0);
+ p++;
+ }
+ } else {
+ colorMap->getRGBLine (pix, row_data, width);
+ }
+
+ if (maskColors) {
+ for (int x = 0; x < width; x++) {
+ bool is_opaque = false;
+ for (int i = 0; i < colorMap->getNumPixelComps(); ++i) {
+ if (pix[i] < maskColors[2*i] ||
+ pix[i] > maskColors[2*i+1]) {
+ is_opaque = true;
+ break;
+ }
+ }
+ if (is_opaque)
+ *row_data |= 0xff000000;
+ else
+ *row_data = 0;
+ row_data++;
+ pix += colorMap->getNumPixelComps();
+ }
+ }
+ }
+
+};
+
+void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+ int widthA, int heightA,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ int *maskColors, GBool inlineImg)
+{
+ cairo_surface_t *image;
+ cairo_pattern_t *pattern, *maskPattern;
+ cairo_matrix_t matrix;
+ int width, height;
+ int scaledWidth, scaledHeight;
+ cairo_filter_t filter = CAIRO_FILTER_BILINEAR;
+ RescaleDrawImage rescale;
+
+ LOG (printf ("drawImage %dx%d\n", widthA, heightA));
+
+ cairo_get_matrix(cairo, &matrix);
+ getScaledSize (&matrix, widthA, heightA, &scaledWidth, &scaledHeight);
+ image = rescale.getSourceImage(str, widthA, heightA, scaledWidth, scaledHeight, printing, colorMap, maskColors);
+ if (!image)
+ return;
+
+ width = cairo_image_surface_get_width (image);
+ height = cairo_image_surface_get_height (image);
+ if (width == widthA && height == heightA)
+ filter = getFilterForSurface (image, interpolate);
+
+ if (!inlineImg) /* don't read stream twice if it is an inline image */
+ setMimeData(state, str, ref, colorMap, image);
+
+ pattern = cairo_pattern_create_for_surface (image);
+ cairo_surface_destroy (image);
+ if (cairo_pattern_status (pattern))
+ return;
+
+ cairo_pattern_set_filter (pattern, filter);
+
+ if (!printing)
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+
+ cairo_matrix_init_translate (&matrix, 0, height);
+ cairo_matrix_scale (&matrix, width, -height);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ if (cairo_pattern_status (pattern)) {
+ cairo_pattern_destroy (pattern);
+ return;
+ }
+
+ if (!mask && fill_opacity != 1.0) {
+ maskPattern = cairo_pattern_create_rgba (1., 1., 1., fill_opacity);
+ } else if (mask) {
+ maskPattern = cairo_pattern_reference (mask);
+ } else {
+ maskPattern = NULL;
+ }
+
+ cairo_save (cairo);
+ cairo_set_source (cairo, pattern);
+ if (!printing)
+ cairo_rectangle (cairo, 0., 0., 1., 1.);
+ if (maskPattern) {
+ if (!printing)
+ cairo_clip (cairo);
+ if (mask)
+ cairo_set_matrix (cairo, &mask_matrix);
+ cairo_mask (cairo, maskPattern);
+ } else {
+ if (printing)
+ cairo_paint (cairo);
+ else
+ cairo_fill (cairo);
+ }
+ cairo_restore (cairo);
+
+ cairo_pattern_destroy (maskPattern);
+
+ if (cairo_shape) {
+ cairo_save (cairo_shape);
+ cairo_set_source (cairo_shape, pattern);
+ if (printing) {
+ cairo_paint (cairo_shape);
+ } else {
+ cairo_rectangle (cairo_shape, 0., 0., 1., 1.);
+ cairo_fill (cairo_shape);
+ }
+ cairo_restore (cairo_shape);
+ }
+
+ cairo_pattern_destroy (pattern);
+}
+
+
+//------------------------------------------------------------------------
+// ImageOutputDev
+//------------------------------------------------------------------------
+
+CairoImageOutputDev::CairoImageOutputDev()
+{
+ images = NULL;
+ numImages = 0;
+ size = 0;
+ imgDrawCbk = NULL;
+ imgDrawCbkData = NULL;
+}
+
+CairoImageOutputDev::~CairoImageOutputDev()
+{
+ int i;
+
+ for (i = 0; i < numImages; i++)
+ delete images[i];
+ gfree (images);
+}
+
+void CairoImageOutputDev::saveImage(CairoImage *image)
+{
+ if (numImages >= size) {
+ size += 16;
+ images = (CairoImage **) greallocn (images, size, sizeof (CairoImage *));
+ }
+ images[numImages++] = image;
+}
+
+void CairoImageOutputDev::getBBox(GfxState *state, int width, int height,
+ double *x1, double *y1, double *x2, double *y2)
+{
+ double *ctm = state->getCTM();
+ cairo_matrix_t matrix;
+ cairo_matrix_init(&matrix,
+ ctm[0], ctm[1],
+ -ctm[2], -ctm[3],
+ ctm[2] + ctm[4], ctm[3] + ctm[5]);
+
+ int scaledWidth, scaledHeight;
+ getScaledSize (&matrix, width, height, &scaledWidth, &scaledHeight);
+
+ if (matrix.xx >= 0) {
+ *x1 = matrix.x0;
+ } else {
+ *x1 = matrix.x0 - scaledWidth;
+ }
+ *x2 = *x1 + scaledWidth;
+
+ if (matrix.yy >= 0) {
+ *y1 = matrix.y0;
+ } else {
+ *y1 = matrix.y0 - scaledHeight;
+ }
+ *y2 = *y1 + scaledHeight;
+}
+
+void CairoImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ double x1, y1, x2, y2;
+ CairoImage *image;
+
+ getBBox(state, width, height, &x1, &y1, &x2, &y2);
+
+ image = new CairoImage (x1, y1, x2, y2);
+ saveImage (image);
+
+ if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cr = cairo_create (surface);
+ setCairo (cr);
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, width, -height);
+
+ CairoOutputDev::drawImageMask(state, ref, str, width, height, invert, interpolate, inlineImg);
+ image->setImage (surface);
+
+ setCairo (NULL);
+ cairo_surface_destroy (surface);
+ cairo_destroy (cr);
+ }
+}
+
+void CairoImageOutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ double x1, y1, x2, y2;
+ CairoImage *image;
+
+ getBBox(state, width, height, &x1, &y1, &x2, &y2);
+
+ image = new CairoImage (x1, y1, x2, y2);
+ saveImage (image);
+
+ if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cr = cairo_create (surface);
+ setCairo (cr);
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, width, -height);
+
+ CairoOutputDev::drawImageMask(state, ref, str, width, height, invert, inlineImg, gFalse);
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ cairo_mask (cairo, mask);
+ }
+ image->setImage (surface);
+
+ setCairo (NULL);
+ cairo_surface_destroy (surface);
+ cairo_destroy (cr);
+ }
+}
+
+void CairoImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ double x1, y1, x2, y2;
+ CairoImage *image;
+
+ getBBox(state, width, height, &x1, &y1, &x2, &y2);
+
+ image = new CairoImage (x1, y1, x2, y2);
+ saveImage (image);
+
+ if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cr = cairo_create (surface);
+ setCairo (cr);
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, width, -height);
+
+ CairoOutputDev::drawImage(state, ref, str, width, height, colorMap, interpolate, maskColors, inlineImg);
+ image->setImage (surface);
+
+ setCairo (NULL);
+ cairo_surface_destroy (surface);
+ cairo_destroy (cr);
+ }
+}
+
+void CairoImageOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ double x1, y1, x2, y2;
+ CairoImage *image;
+
+ getBBox(state, width, height, &x1, &y1, &x2, &y2);
+
+ image = new CairoImage (x1, y1, x2, y2);
+ saveImage (image);
+
+ if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cr = cairo_create (surface);
+ setCairo (cr);
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, width, -height);
+
+ CairoOutputDev::drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate,
+ maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate);
+ image->setImage (surface);
+
+ setCairo (NULL);
+ cairo_surface_destroy (surface);
+ cairo_destroy (cr);
+ }
+}
+
+void CairoImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GBool maskInvert, GBool maskInterpolate)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ double x1, y1, x2, y2;
+ CairoImage *image;
+
+ getBBox(state, width, height, &x1, &y1, &x2, &y2);
+
+ image = new CairoImage (x1, y1, x2, y2);
+ saveImage (image);
+
+ if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cr = cairo_create (surface);
+ setCairo (cr);
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, width, -height);
+
+ CairoOutputDev::drawMaskedImage(state, ref, str, width, height, colorMap, interpolate,
+ maskStr, maskWidth, maskHeight, maskInvert, maskInterpolate);
+ image->setImage (surface);
+
+ setCairo (NULL);
+ cairo_surface_destroy (surface);
+ cairo_destroy (cr);
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoOutputDev.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoOutputDev.h
new file mode 100644
index 00000000000..33dde0c570a
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoOutputDev.h
@@ -0,0 +1,517 @@
+//========================================================================
+//
+// CairoOutputDev.h
+//
+// Copyright 2003 Glyph & Cog, LLC
+// Copyright 2004 Red Hat, INC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005-2008 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+// Copyright (C) 2006-2011, 2013 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2008, 2009, 2011-2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
+// Copyright (C) 2010-2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2015 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef CAIROOUTPUTDEV_H
+#define CAIROOUTPUTDEV_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include <cairo-ft.h>
+#include "OutputDev.h"
+#include "TextOutputDev.h"
+#include "GfxState.h"
+
+class PDFDoc;
+class GfxState;
+class GfxPath;
+class Gfx8BitFont;
+struct GfxRGB;
+class CairoFontEngine;
+class CairoFont;
+
+//------------------------------------------------------------------------
+
+//------------------------------------------------------------------------
+// CairoImage
+//------------------------------------------------------------------------
+class CairoImage {
+public:
+ // Constructor.
+ CairoImage (double x1, double y1, double x2, double y2);
+
+ // Destructor.
+ ~CairoImage ();
+
+ // Set the image cairo surface
+ void setImage (cairo_surface_t *image);
+
+ // Get the image cairo surface
+ cairo_surface_t *getImage () const { return image; }
+
+ // Get the image rectangle
+ void getRect (double *xa1, double *ya1, double *xa2, double *ya2)
+ { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; }
+
+private:
+ cairo_surface_t *image; // image cairo surface
+ double x1, y1; // upper left corner
+ double x2, y2; // lower right corner
+};
+
+
+//------------------------------------------------------------------------
+// CairoOutputDev
+//------------------------------------------------------------------------
+
+class CairoOutputDev: public OutputDev {
+public:
+
+ // Constructor.
+ CairoOutputDev();
+
+ // Destructor.
+ virtual ~CairoOutputDev();
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gTrue; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
+ // Does this device use tilingPatternFill()? If this returns false,
+ // tiling pattern fills will be reduced to a series of other drawing
+ // operations.
+ virtual GBool useTilingPatternFill() { return gTrue; }
+
+ // Does this device use functionShadedFill(), axialShadedFill(), and
+ // radialShadedFill()? If this returns false, these shaded fills
+ // will be reduced to a series of other drawing operations.
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+ virtual GBool useShadedFills(int type) { return type <= 7; }
+#else
+ virtual GBool useShadedFills(int type) { return type < 4; }
+#endif
+
+ // Does this device use FillColorStop()?
+ virtual GBool useFillColorStop() { return gTrue; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gFalse; }
+
+ // Does this device need to clip pages to the crop box even when the
+ // box is the crop box?
+ virtual GBool needClipToCropBox() { return gTrue; }
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state, XRef *xref);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state);
+ virtual void restoreState(GfxState *state);
+
+ //----- update graphics state
+ virtual void updateAll(GfxState *state);
+ virtual void setDefaultCTM(double *ctm);
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32);
+ virtual void updateLineDash(GfxState *state);
+ virtual void updateFlatness(GfxState *state);
+ virtual void updateLineJoin(GfxState *state);
+ virtual void updateLineCap(GfxState *state);
+ virtual void updateMiterLimit(GfxState *state);
+ virtual void updateLineWidth(GfxState *state);
+ virtual void updateFillColor(GfxState *state);
+ virtual void updateStrokeColor(GfxState *state);
+ virtual void updateFillOpacity(GfxState *state);
+ virtual void updateStrokeOpacity(GfxState *state);
+ virtual void updateFillColorStop(GfxState *state, double offset);
+ virtual void updateBlendMode(GfxState *state);
+
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+ virtual void clipToStrokePath(GfxState *state);
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep);
+ virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax);
+ virtual GBool axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading);
+ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax);
+ virtual GBool radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading);
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+ virtual GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading);
+ virtual GBool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading);
+#endif
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+ virtual void eoClip(GfxState *state);
+
+ //----- text drawing
+ void beginString(GfxState *state, GooString *s);
+ void endString(GfxState *state);
+ void drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode code, int nBytes, Unicode *u, int uLen);
+ void beginActualText(GfxState *state, GooString *text);
+ void endActualText(GfxState *state);
+
+ virtual GBool beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen);
+ virtual void endType3Char(GfxState *state);
+ virtual void beginTextObject(GfxState *state);
+ virtual void endTextObject(GfxState *state);
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert, GBool interpolate,
+ GBool inlineImg);
+ virtual void setSoftMaskFromImageMask(GfxState *state,
+ Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix);
+ virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix);
+ void drawImageMaskPrescaled(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert, GBool interpolate,
+ GBool inlineImg);
+ void drawImageMaskRegular(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert, GBool interpolate,
+ GBool inlineImg);
+
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg);
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate);
+
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GBool maskInvert, GBool maskInterpolate);
+
+ //----- 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*/);
+ void popTransparencyGroup();
+ 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*/);
+
+ //----- Type 3 font operators
+ virtual void type3D0(GfxState *state, double wx, double wy);
+ virtual void type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury);
+
+ //----- special access
+
+ // Called to indicate that a new PDF document has been loaded.
+ void startDoc(PDFDoc *docA, CairoFontEngine *fontEngine = NULL);
+
+ GBool isReverseVideo() { return gFalse; }
+
+ void setCairo (cairo_t *cr);
+ void setTextPage (TextPage *text);
+ void setPrinting (GBool printing) { this->printing = printing; needFontUpdate = gTrue; }
+
+ void setInType3Char(GBool inType3Char) { this->inType3Char = inType3Char; }
+ void getType3GlyphWidth (double *wx, double *wy) { *wx = t3_glyph_wx; *wy = t3_glyph_wy; }
+ GBool hasType3GlyphBBox () { return t3_glyph_has_bbox; }
+ double *getType3GlyphBBox () { return t3_glyph_bbox; }
+
+protected:
+ void doPath(cairo_t *cairo, GfxState *state, GfxPath *path);
+ cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface);
+ void getScaledSize(const cairo_matrix_t *matrix,
+ int orig_width, int orig_height,
+ int *scaledWidth, int *scaledHeight);
+ cairo_filter_t getFilterForSurface(cairo_surface_t *image,
+ GBool interpolate);
+ GBool getStreamData (Stream *str, char **buffer, int *length);
+ void setMimeData(GfxState *state, Stream *str, Object *ref,
+ GfxImageColorMap *colorMap, cairo_surface_t *image);
+ void fillToStrokePathClip(GfxState *state);
+ void alignStrokeCoords(GfxSubpath *subpath, int i, double *x, double *y);
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0)
+ GBool setMimeDataForJBIG2Globals (Stream *str, cairo_surface_t *image);
+#endif
+
+ GfxRGB fill_color, stroke_color;
+ cairo_pattern_t *fill_pattern, *stroke_pattern;
+ double fill_opacity;
+ double stroke_opacity;
+ GBool stroke_adjust;
+ GBool adjusted_stroke_width;
+ GBool align_stroke_coords;
+ CairoFont *currentFont;
+ XRef *xref;
+
+ struct StrokePathClip {
+ GfxPath *path;
+ cairo_matrix_t ctm;
+ double line_width;
+ double *dashes;
+ int dash_count;
+ double dash_offset;
+ cairo_line_cap_t cap;
+ cairo_line_join_t join;
+ double miter;
+ } *strokePathClip;
+
+ PDFDoc *doc; // the current document
+
+ static FT_Library ft_lib;
+ static GBool ft_lib_initialized;
+
+ CairoFontEngine *fontEngine;
+ GBool fontEngine_owner;
+
+ cairo_t *cairo;
+ cairo_matrix_t orig_matrix;
+ GBool needFontUpdate; // set when the font needs to be updated
+ GBool printing;
+ GBool use_show_text_glyphs;
+ GBool text_matrix_valid;
+ cairo_surface_t *surface;
+ cairo_glyph_t *glyphs;
+ int glyphCount;
+ cairo_text_cluster_t *clusters;
+ int clusterCount;
+ char *utf8;
+ int utf8Count;
+ int utf8Max;
+ cairo_path_t *textClipPath;
+ GBool inUncoloredPattern; // inside a uncolored pattern (PaintType = 2)
+ GBool inType3Char; // inside a Type 3 CharProc
+ double t3_glyph_wx, t3_glyph_wy;
+ GBool t3_glyph_has_bbox;
+ double t3_glyph_bbox[4];
+
+ GBool prescaleImages;
+
+ TextPage *text; // text for the current page
+ ActualText *actualText;
+
+ cairo_pattern_t *group;
+ cairo_pattern_t *shape;
+ cairo_pattern_t *mask;
+ cairo_matrix_t mask_matrix;
+ cairo_surface_t *cairo_shape_surface;
+ cairo_t *cairo_shape;
+ int knockoutCount;
+ struct ColorSpaceStack {
+ GBool knockout;
+ GfxColorSpace *cs;
+ cairo_matrix_t group_matrix;
+ struct ColorSpaceStack *next;
+ } * groupColorSpaceStack;
+
+ struct MaskStack {
+ cairo_pattern_t *mask;
+ cairo_matrix_t mask_matrix;
+ struct MaskStack *next;
+ } *maskStack;
+
+};
+
+//------------------------------------------------------------------------
+// CairoImageOutputDev
+//------------------------------------------------------------------------
+
+//XXX: this should ideally not inherit from CairoOutputDev but use it instead perhaps
+class CairoImageOutputDev: public CairoOutputDev {
+public:
+
+ // Constructor.
+ CairoImageOutputDev();
+
+ // Destructor.
+ virtual ~CairoImageOutputDev();
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gTrue; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gFalse; }
+
+ // Does this device use tilingPatternFill()? If this returns false,
+ // tiling pattern fills will be reduced to a series of other drawing
+ // operations.
+ virtual GBool useTilingPatternFill() { return gTrue; }
+
+ // Does this device use functionShadedFill(), axialShadedFill(), and
+ // radialShadedFill()? If this returns false, these shaded fills
+ // will be reduced to a series of other drawing operations.
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2)
+ virtual GBool useShadedFills(int type) { return type <= 7; }
+#else
+ virtual GBool useShadedFills(int type) { return type < 4; }
+#endif
+
+ // Does this device use FillColorStop()?
+ virtual GBool useFillColorStop() { return gFalse; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gFalse; }
+
+ // Does this device need non-text content?
+ virtual GBool needNonText() { return gTrue; }
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state) { }
+ virtual void restoreState(GfxState *state) { }
+
+ //----- update graphics state
+ virtual void updateAll(GfxState *state) { }
+ virtual void setDefaultCTM(double *ctm) { }
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32) { }
+ virtual void updateLineDash(GfxState *state) { }
+ virtual void updateFlatness(GfxState *state) { }
+ virtual void updateLineJoin(GfxState *state) { }
+ virtual void updateLineCap(GfxState *state) { }
+ virtual void updateMiterLimit(GfxState *state) { }
+ virtual void updateLineWidth(GfxState *state) { }
+ virtual void updateFillColor(GfxState *state) { }
+ virtual void updateStrokeColor(GfxState *state) { }
+ virtual void updateFillOpacity(GfxState *state) { }
+ virtual void updateStrokeOpacity(GfxState *state) { }
+ virtual void updateBlendMode(GfxState *state) { }
+
+ //----- update text state
+ virtual void updateFont(GfxState *state) { }
+
+ //----- path painting
+ virtual void stroke(GfxState *state) { }
+ virtual void fill(GfxState *state) { }
+ virtual void eoFill(GfxState *state) { }
+ virtual void clipToStrokePath(GfxState *state) { }
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep) { return gTrue; }
+ virtual GBool axialShadedFill(GfxState *state,
+ GfxAxialShading *shading,
+ double tMin, double tMax) { return gTrue; }
+ virtual GBool radialShadedFill(GfxState *state,
+ GfxRadialShading *shading,
+ double sMin, double sMax) { return gTrue; }
+
+ //----- path clipping
+ virtual void clip(GfxState *state) { }
+ virtual void eoClip(GfxState *state) { }
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg);
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GBool maskInvert, GBool maskInterpolate);
+ virtual void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix);
+ virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) {}
+
+
+ //----- 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*/) {}
+
+ //----- Image list
+ // By default images are not rendred
+ void setImageDrawDecideCbk(GBool (*cbk)(int img_id, void *data),
+ void *data) { imgDrawCbk = cbk; imgDrawCbkData = data; }
+ // Iterate through list of images.
+ int getNumImages() const { return numImages; }
+ CairoImage *getImage(int i) const { return images[i]; }
+
+private:
+ void saveImage(CairoImage *image);
+ void getBBox(GfxState *state, int width, int height,
+ double *x1, double *y1, double *x2, double *y2);
+
+ CairoImage **images;
+ int numImages;
+ int size;
+ GBool (*imgDrawCbk)(int img_id, void *data);
+ void *imgDrawCbkData;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoRescaleBox.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoRescaleBox.cc
new file mode 100644
index 00000000000..3c96f45e5d3
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoRescaleBox.cc
@@ -0,0 +1,378 @@
+/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
+/*
+ * Copyright © 2009 Mozilla Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Mozilla Corporation not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Mozilla Corporation makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
+ * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Author: Jeff Muizelaar, Mozilla Corp.
+ */
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+
+/* This implements a box filter that supports non-integer box sizes */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+#include "goo/gmem.h"
+#include "goo/gtypes_p.h"
+#include "CairoRescaleBox.h"
+
+
+/* we work in fixed point where 1. == 1 << 24 */
+#define FIXED_SHIFT 24
+
+
+static void downsample_row_box_filter (
+ int start, int width,
+ uint32_t *src, uint32_t *dest,
+ int coverage[], int pixel_coverage)
+{
+ /* we need an array of the pixel contribution of each destination pixel on the boundaries.
+ * we invert the value to get the value on the other size of the box */
+ /*
+
+ value = a * contribution * 1/box_size
+ value += a * 1/box_size
+ value += a * 1/box_size
+ value += a * 1/box_size
+ value += a * (1 - contribution) * 1/box_size
+ a * (1/box_size - contribution * 1/box_size)
+
+ box size is constant
+
+
+ value = a * contribtion_a * 1/box_size + b * contribution_b * 1/box_size
+ contribution_b = (1 - contribution_a)
+ = (1 - contribution_a_next)
+ */
+
+ /* box size = ceil(src_width/dest_width) */
+ int x = 0;
+
+ /* skip to start */
+ /* XXX: it might be possible to do this directly instead of iteratively, however
+ * the iterative solution is simple */
+ while (x < start)
+ {
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage = coverage[x];
+ box -= start_coverage;
+ src++;
+ while (box >= pixel_coverage)
+ {
+ src++;
+ box -= pixel_coverage;
+ }
+ x++;
+ }
+
+ while (x < start + width)
+ {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage = coverage[x];
+
+ a = ((*src >> 24) & 0xff) * start_coverage;
+ r = ((*src >> 16) & 0xff) * start_coverage;
+ g = ((*src >> 8) & 0xff) * start_coverage;
+ b = ((*src >> 0) & 0xff) * start_coverage;
+ src++;
+ x++;
+ box -= start_coverage;
+
+ while (box >= pixel_coverage)
+ {
+ a += ((*src >> 24) & 0xff) * pixel_coverage;
+ r += ((*src >> 16) & 0xff) * pixel_coverage;
+ g += ((*src >> 8) & 0xff) * pixel_coverage;
+ b += ((*src >> 0) & 0xff) * pixel_coverage;
+ src++;
+
+ box -= pixel_coverage;
+ }
+
+ /* multiply by whatever is leftover
+ * this ensures that we don't bias down.
+ * i.e. start_coverage + n*pixel_coverage + box == 1 << 24 */
+ if (box > 0)
+ {
+ a += ((*src >> 24) & 0xff) * box;
+ r += ((*src >> 16) & 0xff) * box;
+ g += ((*src >> 8) & 0xff) * box;
+ b += ((*src >> 0) & 0xff) * box;
+ }
+
+ a >>= FIXED_SHIFT;
+ r >>= FIXED_SHIFT;
+ g >>= FIXED_SHIFT;
+ b >>= FIXED_SHIFT;
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ }
+}
+
+static void downsample_columns_box_filter (
+ int n,
+ int start_coverage,
+ int pixel_coverage,
+ uint32_t *src, uint32_t *dest)
+{
+ int stride = n;
+ while (n--) {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ uint32_t *column_src = src;
+ int box = 1 << FIXED_SHIFT;
+
+ a = ((*column_src >> 24) & 0xff) * start_coverage;
+ r = ((*column_src >> 16) & 0xff) * start_coverage;
+ g = ((*column_src >> 8) & 0xff) * start_coverage;
+ b = ((*column_src >> 0) & 0xff) * start_coverage;
+ column_src += stride;
+ box -= start_coverage;
+
+ while (box >= pixel_coverage)
+ {
+ a += ((*column_src >> 24) & 0xff) * pixel_coverage;
+ r += ((*column_src >> 16) & 0xff) * pixel_coverage;
+ g += ((*column_src >> 8) & 0xff) * pixel_coverage;
+ b += ((*column_src >> 0) & 0xff) * pixel_coverage;
+ column_src += stride;
+ box -= pixel_coverage;
+ }
+
+ if (box > 0) {
+ a += ((*column_src >> 24) & 0xff) * box;
+ r += ((*column_src >> 16) & 0xff) * box;
+ g += ((*column_src >> 8) & 0xff) * box;
+ b += ((*column_src >> 0) & 0xff) * box;
+ }
+
+ a >>= FIXED_SHIFT;
+ r >>= FIXED_SHIFT;
+ g >>= FIXED_SHIFT;
+ b >>= FIXED_SHIFT;
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ src++;
+ }
+}
+
+static int compute_coverage (int coverage[], int src_length, int dest_length)
+{
+ int i;
+ /* num = src_length/dest_length
+ total = sum(pixel) / num
+
+ pixel * 1/num == pixel * dest_length / src_length
+ */
+ /* the average contribution of each source pixel */
+ int ratio = ((1 << 24)*(long long int)dest_length)/src_length;
+ /* because ((1 << 24)*(long long int)dest_length) won't always be divisible by src_length
+ * we'll need someplace to put the other bits.
+ *
+ * We want to ensure a + n*ratio < 1<<24
+ *
+ * 1<<24
+ * */
+
+ double scale = (double)src_length/dest_length;
+
+ /* for each destination pixel compute the coverage of the left most pixel included in the box */
+ /* I have a proof of this, which this margin is too narrow to contain */
+ for (i=0; i<dest_length; i++)
+ {
+ float left_side = i*scale;
+ float right_side = (i+1)*scale;
+ float right_fract = right_side - floor (right_side);
+ float left_fract = ceil (left_side) - left_side;
+ int overage;
+ /* find out how many source pixels will be used to fill the box */
+ int count = floor (right_side) - ceil (left_side);
+ /* what's the maximum value this expression can become?
+ floor((i+1)*scale) - ceil(i*scale)
+
+ (i+1)*scale - i*scale == scale
+
+ since floor((i+1)*scale) <= (i+1)*scale
+ and ceil(i*scale) >= i*scale
+
+ floor((i+1)*scale) - ceil(i*scale) <= scale
+
+ further since: floor((i+1)*scale) - ceil(i*scale) is an integer
+
+ therefore:
+ floor((i+1)*scale) - ceil(i*scale) <= floor(scale)
+ */
+
+ if (left_fract == 0.)
+ count--;
+
+ /* compute how much the right-most pixel contributes */
+ overage = ratio*(right_fract);
+
+ /* the remainder is the the amount that the left-most pixel
+ * contributes */
+ coverage[i] = (1<<24) - (count * ratio + overage);
+ }
+
+ return ratio;
+}
+
+
+GBool CairoRescaleBox::downScaleImage(unsigned orig_width, unsigned orig_height,
+ signed scaled_width, signed scaled_height,
+ unsigned short int start_column, unsigned short int start_row,
+ unsigned short int width, unsigned short int height,
+ cairo_surface_t *dest_surface) {
+ int pixel_coverage_x, pixel_coverage_y;
+ int dest_y;
+ int src_y = 0;
+ uint32_t *scanline;
+ int *x_coverage = NULL;
+ int *y_coverage = NULL;
+ uint32_t *temp_buf = NULL;
+ GBool retval = gFalse;
+ unsigned int *dest;
+ int dst_stride;
+
+ dest = (unsigned int *)cairo_image_surface_get_data (dest_surface);
+ dst_stride = cairo_image_surface_get_stride (dest_surface);
+
+ scanline = (uint32_t*)gmallocn3 (orig_width, 1, sizeof(int));
+
+ x_coverage = (int *)gmallocn3 (orig_width, 1, sizeof(int));
+ y_coverage = (int *)gmallocn3 (orig_height, 1, sizeof(int));
+
+ /* we need to allocate enough room for ceil(src_height/dest_height)+1
+ Example:
+ src_height = 140
+ dest_height = 50
+ src_height/dest_height = 2.8
+
+ |-------------| 2.8 pixels
+ |----|----|----|----| 4 pixels
+ need to sample 3 pixels
+
+ |-------------| 2.8 pixels
+ |----|----|----|----| 4 pixels
+ need to sample 4 pixels
+ */
+
+ temp_buf = (uint32_t *)gmallocn3 ((orig_height + scaled_height-1)/scaled_height+1, scaled_width, sizeof(uint32_t));
+
+ if (!x_coverage || !y_coverage || !scanline || !temp_buf)
+ goto cleanup;
+
+ pixel_coverage_x = compute_coverage (x_coverage, orig_width, scaled_width);
+ pixel_coverage_y = compute_coverage (y_coverage, orig_height, scaled_height);
+
+ assert (width + start_column <= scaled_width);
+
+
+
+ /* skip the rows at the beginning */
+ for (dest_y = 0; dest_y < start_row; dest_y++)
+ {
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage_y = y_coverage[dest_y];
+ box -= start_coverage_y;
+ src_y++;
+ while (box >= pixel_coverage_y)
+ {
+ box -= pixel_coverage_y;
+ src_y++;
+ }
+ }
+
+ for (; dest_y < start_row + height; dest_y++)
+ {
+ int columns = 0;
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage_y = y_coverage[dest_y];
+
+ getRow(src_y, scanline);
+ downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
+ columns++;
+ src_y++;
+ box -= start_coverage_y;
+
+ while (box >= pixel_coverage_y)
+ {
+ getRow(src_y, scanline);
+ downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
+ columns++;
+ src_y++;
+ box -= pixel_coverage_y;
+ }
+
+ /* downsample any leftovers */
+ if (box > 0)
+ {
+ getRow(src_y, scanline);
+ downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
+ columns++;
+ }
+
+ /* now scale the rows we just downsampled in the y direction */
+ downsample_columns_box_filter (width, start_coverage_y, pixel_coverage_y, temp_buf, dest);
+ dest += dst_stride / 4;
+
+// assert(width*columns <= ((orig_height + scaled_height-1)/scaled_height+1) * width);
+ }
+// assert (src_y<=orig_height);
+
+ retval = gTrue;
+
+cleanup:
+ free (x_coverage);
+ free (y_coverage);
+ free (temp_buf);
+ free (scanline);
+
+ return retval;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoRescaleBox.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoRescaleBox.h
new file mode 100644
index 00000000000..072e8a9c80c
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CairoRescaleBox.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2009 Mozilla Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Mozilla Corporation not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Mozilla Corporation makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
+ * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Author: Jeff Muizelaar, Mozilla Corp.
+ */
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef CAIRO_RESCALE_BOX_H
+#define CAIRO_RESCALE_BOX_H
+
+#include "goo/gtypes.h"
+#include <cairo.h>
+
+class CairoRescaleBox {
+public:
+
+ CairoRescaleBox() {};
+ virtual ~CairoRescaleBox() {};
+
+ virtual GBool downScaleImage(unsigned orig_width, unsigned orig_height,
+ signed scaled_width, signed scaled_height,
+ unsigned short int start_column, unsigned short int start_row,
+ unsigned short int width, unsigned short int height,
+ cairo_surface_t *dest_surface);
+
+ virtual void getRow(int row_num, uint32_t *row_data) = 0;
+
+};
+
+#endif /* CAIRO_RESCALE_BOX_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Catalog.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Catalog.cc
new file mode 100644
index 00000000000..04caa1c1f35
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Catalog.cc
@@ -0,0 +1,1142 @@
+//========================================================================
+//
+// Catalog.cc
+//
+// Copyright 1996-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005-2013, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Jeff Muizelaar <jrmuizel@nit.ca>
+// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
+// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
+// Copyright (C) 2005, 2006, 2008 Brad Hards <bradh@frogmouth.net>
+// Copyright (C) 2006, 2008, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2008, 2011 Pino Toscano <pino@kde.org>
+// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Julien Nabet <serval2412@yahoo.fr>
+// Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 José Aliste <jaliste@src.gnome.org>
+// Copyright (C) 2014 Ed Porras <ed@moto-research.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include "goo/gmem.h"
+#include "Object.h"
+#include "PDFDoc.h"
+#include "XRef.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Page.h"
+#include "Error.h"
+#include "Link.h"
+#include "PageLabelInfo.h"
+#include "Catalog.h"
+#include "Form.h"
+#include "OptionalContent.h"
+#include "ViewerPreferences.h"
+#include "FileSpec.h"
+#include "StructTreeRoot.h"
+
+#if MULTITHREADED
+# define catalogLocker() MutexLocker locker(&mutex)
+#else
+# define catalogLocker()
+#endif
+//------------------------------------------------------------------------
+// Catalog
+//------------------------------------------------------------------------
+
+Catalog::Catalog(PDFDoc *docA) {
+ Object catDict, pagesDict, pagesDictRef;
+ Object obj, obj2;
+ Object optContentProps;
+
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+ ok = gTrue;
+ doc = docA;
+ xref = doc->getXRef();
+ pages = NULL;
+ pageRefs = NULL;
+ numPages = -1;
+ pagesSize = 0;
+ baseURI = NULL;
+ pageLabelInfo = NULL;
+ form = NULL;
+ optContent = NULL;
+ pageMode = pageModeNull;
+ pageLayout = pageLayoutNull;
+ destNameTree = NULL;
+ embeddedFileNameTree = NULL;
+ jsNameTree = NULL;
+ viewerPrefs = NULL;
+ structTreeRoot = NULL;
+
+ pagesList = NULL;
+ pagesRefList = NULL;
+ attrsList = NULL;
+ kidsIdxList = NULL;
+ lastCachedPage = 0;
+ markInfo = markInfoNull;
+
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ goto err1;
+ }
+ // get the AcroForm dictionary
+ catDict.dictLookup("AcroForm", &acroForm);
+
+ // read base URI
+ if (catDict.dictLookup("URI", &obj)->isDict()) {
+ if (obj.dictLookup("Base", &obj2)->isString()) {
+ baseURI = obj2.getString()->copy();
+ }
+ obj2.free();
+ }
+ obj.free();
+
+ // get the Optional Content dictionary
+ if (catDict.dictLookup("OCProperties", &optContentProps)->isDict()) {
+ optContent = new OCGs(&optContentProps, xref);
+ if (!optContent->isOk ()) {
+ delete optContent;
+ optContent = NULL;
+ }
+ }
+ optContentProps.free();
+
+ // actions
+ catDict.dictLookupNF("AA", &additionalActions);
+
+ // get the ViewerPreferences dictionary
+ catDict.dictLookup("ViewerPreferences", &viewerPreferences);
+ catDict.free();
+ return;
+
+ err1:
+ catDict.free();
+ ok = gFalse;
+}
+
+Catalog::~Catalog() {
+ delete kidsIdxList;
+ if (attrsList) {
+ std::vector<PageAttrs *>::iterator it;
+ for (it = attrsList->begin() ; it != attrsList->end(); ++it ) {
+ delete *it;
+ }
+ delete attrsList;
+ }
+ delete pagesRefList;
+ if (pagesList) {
+ std::vector<Dict *>::iterator it;
+ for (it = pagesList->begin() ; it != pagesList->end(); ++it ) {
+ if (!(*it)->decRef()) {
+ delete *it;
+ }
+ }
+ delete pagesList;
+ }
+ if (pages) {
+ for (int i = 0; i < pagesSize; ++i) {
+ if (pages[i]) {
+ delete pages[i];
+ }
+ }
+ gfree(pages);
+ gfree(pageRefs);
+ }
+ names.free();
+ dests.free();
+ delete destNameTree;
+ delete embeddedFileNameTree;
+ delete jsNameTree;
+ if (baseURI) {
+ delete baseURI;
+ }
+ delete pageLabelInfo;
+ delete form;
+ delete optContent;
+ delete viewerPrefs;
+ delete structTreeRoot;
+ metadata.free();
+ outline.free();
+ acroForm.free();
+ viewerPreferences.free();
+ additionalActions.free();
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+GooString *Catalog::readMetadata() {
+ GooString *s;
+ Dict *dict;
+ Object obj;
+
+ catalogLocker();
+ if (metadata.isNone()) {
+ Object catDict;
+
+ xref->getCatalog(&catDict);
+ if (catDict.isDict()) {
+ catDict.dictLookup("Metadata", &metadata);
+ } else {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ metadata.initNull();
+ }
+ catDict.free();
+ }
+
+ if (!metadata.isStream()) {
+ return NULL;
+ }
+ dict = metadata.streamGetDict();
+ if (!dict->lookup("Subtype", &obj)->isName("XML")) {
+ error(errSyntaxWarning, -1, "Unknown Metadata type: '{0:s}'",
+ obj.isName() ? obj.getName() : "???");
+ }
+ obj.free();
+ s = new GooString();
+ metadata.getStream()->fillGooString(s);
+ metadata.streamClose();
+ return s;
+}
+
+Page *Catalog::getPage(int i)
+{
+ if (i < 1) return NULL;
+
+ catalogLocker();
+ if (i > lastCachedPage) {
+ GBool cached = cachePageTree(i);
+ if ( cached == gFalse) {
+ return NULL;
+ }
+ }
+ return pages[i-1];
+}
+
+Ref *Catalog::getPageRef(int i)
+{
+ if (i < 1) return NULL;
+
+ catalogLocker();
+ if (i > lastCachedPage) {
+ GBool cached = cachePageTree(i);
+ if ( cached == gFalse) {
+ return NULL;
+ }
+ }
+ return &pageRefs[i-1];
+}
+
+GBool Catalog::cachePageTree(int page)
+{
+ Dict *pagesDict;
+
+ if (pagesList == NULL) {
+
+ Object catDict;
+ Ref pagesRef;
+
+ xref->getCatalog(&catDict);
+
+ if (catDict.isDict()) {
+ Object pagesDictRef;
+ if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() &&
+ pagesDictRef.getRefNum() >= 0 &&
+ pagesDictRef.getRefNum() < xref->getNumObjects()) {
+ pagesRef = pagesDictRef.getRef();
+ pagesDictRef.free();
+ } else {
+ error(errSyntaxError, -1, "Catalog dictionary does not contain a valid \"Pages\" entry");
+ pagesDictRef.free();
+ catDict.free();
+ return gFalse;
+ }
+ } else {
+ error(errSyntaxError, -1, "Could not find catalog dictionary");
+ catDict.free();
+ return gFalse;
+ }
+
+ Object obj;
+ catDict.dictLookup("Pages", &obj);
+ catDict.free();
+ // This should really be isDict("Pages"), but I've seen at least one
+ // PDF file where the /Type entry is missing.
+ if (obj.isDict()) {
+ obj.getDict()->incRef();
+ pagesDict = obj.getDict();
+ obj.free();
+ }
+ else {
+ error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})", obj.getTypeName());
+ obj.free();
+ return gFalse;
+ }
+
+ pagesSize = getNumPages();
+ pages = (Page **)gmallocn(pagesSize, sizeof(Page *));
+ pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref));
+ for (int i = 0; i < pagesSize; ++i) {
+ pages[i] = NULL;
+ pageRefs[i].num = -1;
+ pageRefs[i].gen = -1;
+ }
+
+ pagesList = new std::vector<Dict *>();
+ pagesList->push_back(pagesDict);
+ pagesRefList = new std::vector<Ref>();
+ pagesRefList->push_back(pagesRef);
+ attrsList = new std::vector<PageAttrs *>();
+ attrsList->push_back(new PageAttrs(NULL, pagesDict));
+ kidsIdxList = new std::vector<int>();
+ kidsIdxList->push_back(0);
+ lastCachedPage = 0;
+
+ }
+
+ while(1) {
+
+ if (page <= lastCachedPage) return gTrue;
+
+ if (pagesList->empty()) return gFalse;
+
+ pagesDict = pagesList->back();
+ Object kids;
+ pagesDict->lookup("Kids", &kids);
+ if (!kids.isArray()) {
+ error(errSyntaxError, -1, "Kids object (page {0:d}) is wrong type ({1:s})",
+ lastCachedPage+1, kids.getTypeName());
+ kids.free();
+ return gFalse;
+ }
+
+ int kidsIdx = kidsIdxList->back();
+ if (kidsIdx >= kids.arrayGetLength()) {
+ if (!pagesList->back()->decRef()) {
+ delete pagesList->back();
+ }
+ pagesList->pop_back();
+ pagesRefList->pop_back();
+ delete attrsList->back();
+ attrsList->pop_back();
+ kidsIdxList->pop_back();
+ if (!kidsIdxList->empty()) kidsIdxList->back()++;
+ kids.free();
+ continue;
+ }
+
+ Object kidRef;
+ kids.arrayGetNF(kidsIdx, &kidRef);
+ if (!kidRef.isRef()) {
+ error(errSyntaxError, -1, "Kid object (page {0:d}) is not an indirect reference ({1:s})",
+ lastCachedPage+1, kidRef.getTypeName());
+ kidRef.free();
+ kids.free();
+ return gFalse;
+ }
+
+ GBool loop = gFalse;;
+ for (size_t i = 0; i < pagesRefList->size(); i++) {
+ if (((*pagesRefList)[i]).num == kidRef.getRefNum()) {
+ loop = gTrue;
+ break;
+ }
+ }
+ if (loop) {
+ error(errSyntaxError, -1, "Loop in Pages tree");
+ kidRef.free();
+ kids.free();
+ kidsIdxList->back()++;
+ continue;
+ }
+
+ Object kid;
+ kids.arrayGet(kidsIdx, &kid);
+ kids.free();
+ if (kid.isDict("Page") || (kid.isDict() && !kid.getDict()->hasKey("Kids"))) {
+ PageAttrs *attrs = new PageAttrs(attrsList->back(), kid.getDict());
+ Page *p = new Page(doc, lastCachedPage+1, kid.getDict(),
+ kidRef.getRef(), attrs, form);
+ if (!p->isOk()) {
+ error(errSyntaxError, -1, "Failed to create page (page {0:d})", lastCachedPage+1);
+ delete p;
+ kidRef.free();
+ kid.free();
+ return gFalse;
+ }
+
+ if (lastCachedPage >= numPages) {
+ error(errSyntaxError, -1, "Page count in top-level pages object is incorrect");
+ kidRef.free();
+ kid.free();
+ return gFalse;
+ }
+
+ pages[lastCachedPage] = p;
+ pageRefs[lastCachedPage].num = kidRef.getRefNum();
+ pageRefs[lastCachedPage].gen = kidRef.getRefGen();
+
+ lastCachedPage++;
+ kidsIdxList->back()++;
+
+ // 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()) {
+ attrsList->push_back(new PageAttrs(attrsList->back(), kid.getDict()));
+ pagesRefList->push_back(kidRef.getRef());
+ kid.getDict()->incRef();
+ pagesList->push_back(kid.getDict());
+ kidsIdxList->push_back(0);
+ } else {
+ error(errSyntaxError, -1, "Kid object (page {0:d}) is wrong type ({1:s})",
+ lastCachedPage+1, kid.getTypeName());
+ kidsIdxList->back()++;
+ }
+ kidRef.free();
+ kid.free();
+
+ }
+
+ return gFalse;
+}
+
+int Catalog::findPage(int num, int gen) {
+ int i;
+
+ for (i = 0; i < getNumPages(); ++i) {
+ Ref *ref = getPageRef(i+1);
+ if (ref != NULL && ref->num == num && ref->gen == gen)
+ return i + 1;
+ }
+ return 0;
+}
+
+LinkDest *Catalog::findDest(GooString *name) {
+ LinkDest *dest;
+ Object obj1, obj2;
+ GBool found;
+
+ // try named destination dictionary then name tree
+ found = gFalse;
+ if (getDests()->isDict()) {
+ if (!getDests()->dictLookup(name->getCString(), &obj1)->isNull())
+ found = gTrue;
+ else
+ obj1.free();
+ }
+ if (!found) {
+ catalogLocker();
+ if (getDestNameTree()->lookup(name, &obj1))
+ found = gTrue;
+ else
+ obj1.free();
+ }
+ if (!found)
+ return NULL;
+
+ // construct LinkDest
+ dest = NULL;
+ if (obj1.isArray()) {
+ dest = new LinkDest(obj1.getArray());
+ } else if (obj1.isDict()) {
+ if (obj1.dictLookup("D", &obj2)->isArray())
+ dest = new LinkDest(obj2.getArray());
+ else
+ error(errSyntaxWarning, -1, "Bad named destination value");
+ obj2.free();
+ } else {
+ error(errSyntaxWarning, -1, "Bad named destination value");
+ }
+ obj1.free();
+ if (dest && !dest->isOk()) {
+ delete dest;
+ dest = NULL;
+ }
+
+ return dest;
+}
+
+FileSpec *Catalog::embeddedFile(int i)
+{
+ Object efDict;
+ Object obj;
+ catalogLocker();
+ obj = getEmbeddedFileNameTree()->getValue(i);
+ FileSpec *embeddedFile = 0;
+ if (obj.isRef()) {
+ Object fsDict;
+ embeddedFile = new FileSpec(obj.fetch(xref, &fsDict));
+ fsDict.free();
+ } else if (obj.isDict()) {
+ embeddedFile = new FileSpec(&obj);
+ } else {
+ Object null;
+ embeddedFile = new FileSpec(&null);
+ }
+ return embeddedFile;
+}
+
+GooString *Catalog::getJS(int i)
+{
+ Object obj;
+ // getJSNameTree()->getValue(i) returns a shallow copy of the object so we
+ // do not need to free it
+ catalogLocker();
+ getJSNameTree()->getValue(i).fetch(xref, &obj);
+
+ if (!obj.isDict()) {
+ obj.free();
+ return 0;
+ }
+ Object obj2;
+ if (!obj.dictLookup("S", &obj2)->isName()) {
+ obj2.free();
+ obj.free();
+ return 0;
+ }
+ if (strcmp(obj2.getName(), "JavaScript")) {
+ obj2.free();
+ obj.free();
+ return 0;
+ }
+ obj2.free();
+ obj.dictLookup("JS", &obj2);
+ GooString *js = 0;
+ if (obj2.isString()) {
+ js = new GooString(obj2.getString());
+ }
+ else if (obj2.isStream()) {
+ Stream *stream = obj2.getStream();
+ js = new GooString();
+ stream->fillGooString(js);
+ }
+ obj2.free();
+ obj.free();
+ return js;
+}
+
+Catalog::PageMode Catalog::getPageMode() {
+
+ catalogLocker();
+ if (pageMode == pageModeNull) {
+
+ Object catDict, obj;
+
+ pageMode = pageModeNone;
+
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ catDict.free();
+ return pageMode;
+ }
+
+ if (catDict.dictLookup("PageMode", &obj)->isName()) {
+ if (obj.isName("UseNone"))
+ pageMode = pageModeNone;
+ else if (obj.isName("UseOutlines"))
+ pageMode = pageModeOutlines;
+ else if (obj.isName("UseThumbs"))
+ pageMode = pageModeThumbs;
+ else if (obj.isName("FullScreen"))
+ pageMode = pageModeFullScreen;
+ else if (obj.isName("UseOC"))
+ pageMode = pageModeOC;
+ else if (obj.isName("UseAttachments"))
+ pageMode = pageModeAttach;
+ }
+ obj.free();
+ catDict.free();
+ }
+ return pageMode;
+}
+
+Catalog::PageLayout Catalog::getPageLayout() {
+
+ catalogLocker();
+ if (pageLayout == pageLayoutNull) {
+
+ Object catDict, obj;
+
+ pageLayout = pageLayoutNone;
+
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ catDict.free();
+ return pageLayout;
+ }
+
+ pageLayout = pageLayoutNone;
+ if (catDict.dictLookup("PageLayout", &obj)->isName()) {
+ if (obj.isName("SinglePage"))
+ pageLayout = pageLayoutSinglePage;
+ if (obj.isName("OneColumn"))
+ pageLayout = pageLayoutOneColumn;
+ if (obj.isName("TwoColumnLeft"))
+ pageLayout = pageLayoutTwoColumnLeft;
+ if (obj.isName("TwoColumnRight"))
+ pageLayout = pageLayoutTwoColumnRight;
+ if (obj.isName("TwoPageLeft"))
+ pageLayout = pageLayoutTwoPageLeft;
+ if (obj.isName("TwoPageRight"))
+ pageLayout = pageLayoutTwoPageRight;
+ }
+ obj.free();
+ catDict.free();
+ }
+ return pageLayout;
+}
+
+NameTree::NameTree()
+{
+ size = 0;
+ length = 0;
+ entries = NULL;
+}
+
+NameTree::~NameTree()
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ delete entries[i];
+
+ gfree(entries);
+}
+
+NameTree::Entry::Entry(Array *array, int index) {
+ if (!array->getString(index, &name) || !array->getNF(index + 1, &value)) {
+ Object aux;
+ array->get(index, &aux);
+ if (aux.isString() && array->getNF(index + 1, &value) )
+ {
+ name.append(aux.getString());
+ }
+ else
+ error(errSyntaxError, -1, "Invalid page tree");
+ }
+}
+
+NameTree::Entry::~Entry() {
+ value.free();
+}
+
+void NameTree::addEntry(Entry *entry)
+{
+ if (length == size) {
+ if (length == 0) {
+ size = 8;
+ } else {
+ size *= 2;
+ }
+ entries = (Entry **) grealloc (entries, sizeof (Entry *) * size);
+ }
+
+ entries[length] = entry;
+ ++length;
+}
+
+int NameTree::Entry::cmpEntry(const void *voidEntry, const void *voidOtherEntry)
+{
+ Entry *entry = *(NameTree::Entry **) voidEntry;
+ Entry *otherEntry = *(NameTree::Entry **) voidOtherEntry;
+
+ return entry->name.cmp(&otherEntry->name);
+}
+
+void NameTree::init(XRef *xrefA, Object *tree) {
+ xref = xrefA;
+ parse(tree);
+ if (entries && length > 0) {
+ qsort(entries, length, sizeof(Entry *), Entry::cmpEntry);
+ }
+}
+
+void NameTree::parse(Object *tree) {
+ Object names;
+ Object kids, kid;
+ int i;
+
+ if (!tree->isDict())
+ return;
+
+ // leaf node
+ if (tree->dictLookup("Names", &names)->isArray()) {
+ for (i = 0; i < names.arrayGetLength(); i += 2) {
+ NameTree::Entry *entry;
+
+ entry = new Entry(names.getArray(), i);
+ addEntry(entry);
+ }
+ }
+ names.free();
+
+ // root or intermediate node
+ if (tree->dictLookup("Kids", &kids)->isArray()) {
+ for (i = 0; i < kids.arrayGetLength(); ++i) {
+ if (kids.arrayGet(i, &kid)->isDict())
+ parse(&kid);
+ kid.free();
+ }
+ }
+ kids.free();
+}
+
+int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry)
+{
+ GooString *key = (GooString *) voidKey;
+ Entry *entry = *(NameTree::Entry **) voidEntry;
+
+ return key->cmp(&entry->name);
+}
+
+GBool NameTree::lookup(GooString *name, Object *obj)
+{
+ Entry **entry;
+
+ entry = (Entry **) bsearch(name, entries,
+ length, sizeof(Entry *), Entry::cmp);
+ if (entry != NULL) {
+ (*entry)->value.fetch(xref, obj);
+ return gTrue;
+ } else {
+ error(errSyntaxError, -1, "failed to look up ({0:s})", name->getCString());
+ obj->initNull();
+ return gFalse;
+ }
+}
+
+Object NameTree::getValue(int index)
+{
+ if (index < length) {
+ return entries[index]->value;
+ } else {
+ return Object();
+ }
+}
+
+GooString *NameTree::getName(int index)
+{
+ if (index < length) {
+ return &entries[index]->name;
+ } else {
+ return NULL;
+ }
+}
+
+GBool Catalog::labelToIndex(GooString *label, int *index)
+{
+ char *end;
+
+ PageLabelInfo *pli = getPageLabelInfo();
+ if (pli != NULL) {
+ if (!pli->labelToIndex(label, index))
+ return gFalse;
+ } else {
+ *index = strtol(label->getCString(), &end, 10) - 1;
+ if (*end != '\0')
+ return gFalse;
+ }
+
+ if (*index < 0 || *index >= getNumPages())
+ return gFalse;
+
+ return gTrue;
+}
+
+GBool Catalog::indexToLabel(int index, GooString *label)
+{
+ char buffer[32];
+
+ if (index < 0 || index >= getNumPages())
+ return gFalse;
+
+ PageLabelInfo *pli = getPageLabelInfo();
+ if (pli != NULL) {
+ return pli->indexToLabel(index, label);
+ } else {
+ snprintf(buffer, sizeof (buffer), "%d", index + 1);
+ label->append(buffer);
+ return gTrue;
+ }
+}
+
+int Catalog::getNumPages()
+{
+ catalogLocker();
+ if (numPages == -1)
+ {
+ Object catDict, pagesDict, obj;
+
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ catDict.free();
+ return 0;
+ }
+ catDict.dictLookup("Pages", &pagesDict);
+
+ // This should really be isDict("Pages"), but I've seen at least one
+ // PDF file where the /Type entry is missing.
+ if (!pagesDict.isDict()) {
+ error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})",
+ pagesDict.getTypeName());
+ pagesDict.free();
+ catDict.free();
+ return 0;
+ }
+
+ pagesDict.dictLookup("Count", &obj);
+ // some PDF files actually use real numbers here ("/Count 9.0")
+ if (!obj.isNum()) {
+ if (pagesDict.dictIs("Page")) {
+ Object pageRootRef;
+ catDict.dictLookupNF("Pages", &pageRootRef);
+
+ error(errSyntaxError, -1, "Pages top-level is a single Page. The document is malformed, trying to recover...");
+
+ Dict *pageDict = pagesDict.getDict();
+ if (pageRootRef.isRef()) {
+ const Ref pageRef = pageRootRef.getRef();
+ Page *p = new Page(doc, 1, pageDict, pageRef, new PageAttrs(NULL, pageDict), form);
+ if (p->isOk()) {
+ pages = (Page **)gmallocn(1, sizeof(Page *));
+ pageRefs = (Ref *)gmallocn(1, sizeof(Ref));
+
+ pages[0] = p;
+ pageRefs[0].num = pageRef.num;
+ pageRefs[0].gen = pageRef.gen;
+
+ numPages = 1;
+ lastCachedPage = 1;
+ pagesSize = 1;
+ } else {
+ delete p;
+ numPages = 0;
+ }
+ } else {
+ numPages = 0;
+ }
+ } else {
+ error(errSyntaxError, -1, "Page count in top-level pages object is wrong type ({0:s})",
+ obj.getTypeName());
+ numPages = 0;
+ }
+ } else {
+ numPages = (int)obj.getNum();
+ }
+
+ catDict.free();
+ obj.free();
+ pagesDict.free();
+ }
+
+ return numPages;
+}
+
+PageLabelInfo *Catalog::getPageLabelInfo()
+{
+ catalogLocker();
+ if (!pageLabelInfo) {
+ Object catDict;
+ Object obj;
+
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ catDict.free();
+ return NULL;
+ }
+
+ if (catDict.dictLookup("PageLabels", &obj)->isDict()) {
+ pageLabelInfo = new PageLabelInfo(&obj, getNumPages());
+ }
+ obj.free();
+ catDict.free();
+ }
+
+ return pageLabelInfo;
+}
+
+StructTreeRoot *Catalog::getStructTreeRoot()
+{
+ catalogLocker();
+ if (!structTreeRoot) {
+ Object catalog;
+ Object root;
+
+ xref->getCatalog(&catalog);
+ if (!catalog.isDict()) {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catalog.getTypeName());
+ catalog.free();
+ return NULL;
+ }
+
+ if (catalog.dictLookup("StructTreeRoot", &root)->isDict("StructTreeRoot")) {
+ structTreeRoot = new StructTreeRoot(doc, root.getDict());
+ }
+
+ root.free();
+ catalog.free();
+ }
+ return structTreeRoot;
+}
+
+Guint Catalog::getMarkInfo()
+{
+ if (markInfo == markInfoNull) {
+ markInfo = 0;
+
+ Object catDict;
+ catalogLocker();
+ xref->getCatalog(&catDict);
+
+ if (catDict.isDict()) {
+ Object markInfoDict;
+ catDict.dictLookup("MarkInfo", &markInfoDict);
+ if (markInfoDict.isDict()) {
+ Object value;
+
+ if (markInfoDict.dictLookup("Marked", &value)->isBool() && value.getBool())
+ markInfo |= markInfoMarked;
+ else if (!value.isNull())
+ error(errSyntaxError, -1, "Marked object is wrong type ({0:s})", value.getTypeName());
+ value.free();
+
+ if (markInfoDict.dictLookup("Suspects", &value)->isBool() && value.getBool())
+ markInfo |= markInfoSuspects;
+ else if (!value.isNull())
+ error(errSyntaxError, -1, "Suspects object is wrong type ({0:s})", value.getTypeName());
+ value.free();
+
+ if (markInfoDict.dictLookup("UserProperties", &value)->isBool() && value.getBool())
+ markInfo |= markInfoUserProperties;
+ else if (!value.isNull())
+ error(errSyntaxError, -1, "UserProperties object is wrong type ({0:s})", value.getTypeName());
+ value.free();
+ } else if (!markInfoDict.isNull()) {
+ error(errSyntaxError, -1, "MarkInfo object is wrong type ({0:s})", markInfoDict.getTypeName());
+ }
+ markInfoDict.free();
+ } else {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ }
+ catDict.free();
+ }
+ return markInfo;
+}
+
+Object *Catalog::getOutline()
+{
+ catalogLocker();
+ if (outline.isNone())
+ {
+ Object catDict;
+
+ xref->getCatalog(&catDict);
+ if (catDict.isDict()) {
+ catDict.dictLookup("Outlines", &outline);
+ } else {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ outline.initNull();
+ }
+ catDict.free();
+ }
+
+ return &outline;
+}
+
+Object *Catalog::getDests()
+{
+ catalogLocker();
+ if (dests.isNone())
+ {
+ Object catDict;
+
+ xref->getCatalog(&catDict);
+ if (catDict.isDict()) {
+ catDict.dictLookup("Dests", &dests);
+ } else {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ dests.initNull();
+ }
+ catDict.free();
+ }
+
+ return &dests;
+}
+
+Catalog::FormType Catalog::getFormType()
+{
+ Object xfa;
+ FormType res = NoForm;
+
+ if (acroForm.isDict()) {
+ acroForm.dictLookup("XFA", &xfa);
+ if (xfa.isStream() || xfa.isArray()) {
+ res = XfaForm;
+ } else {
+ res = AcroForm;
+ }
+ xfa.free();
+ }
+
+ return res;
+}
+
+Form *Catalog::getForm()
+{
+ catalogLocker();
+ if (!form) {
+ if (acroForm.isDict()) {
+ form = new Form(doc, &acroForm);
+ // perform form-related loading after all widgets have been loaded
+ form->postWidgetsLoad();
+ }
+ }
+
+ return form;
+}
+
+ViewerPreferences *Catalog::getViewerPreferences()
+{
+ catalogLocker();
+ if (!viewerPrefs) {
+ if (viewerPreferences.isDict()) {
+ viewerPrefs = new ViewerPreferences(viewerPreferences.getDict());
+ }
+ }
+
+ return viewerPrefs;
+}
+
+Object *Catalog::getNames()
+{
+ if (names.isNone())
+ {
+ Object catDict;
+
+ xref->getCatalog(&catDict);
+ if (catDict.isDict()) {
+ catDict.dictLookup("Names", &names);
+ } else {
+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
+ names.initNull();
+ }
+ catDict.free();
+ }
+
+ return &names;
+}
+
+NameTree *Catalog::getDestNameTree()
+{
+ if (!destNameTree) {
+
+ destNameTree = new NameTree();
+
+ if (getNames()->isDict()) {
+ Object obj;
+
+ getNames()->dictLookup("Dests", &obj);
+ destNameTree->init(xref, &obj);
+ obj.free();
+ }
+
+ }
+
+ return destNameTree;
+}
+
+NameTree *Catalog::getEmbeddedFileNameTree()
+{
+ if (!embeddedFileNameTree) {
+
+ embeddedFileNameTree = new NameTree();
+
+ if (getNames()->isDict()) {
+ Object obj;
+
+ getNames()->dictLookup("EmbeddedFiles", &obj);
+ embeddedFileNameTree->init(xref, &obj);
+ obj.free();
+ }
+
+ }
+
+ return embeddedFileNameTree;
+}
+
+NameTree *Catalog::getJSNameTree()
+{
+ if (!jsNameTree) {
+
+ jsNameTree = new NameTree();
+
+ if (getNames()->isDict()) {
+ Object obj;
+
+ getNames()->dictLookup("JavaScript", &obj);
+ jsNameTree->init(xref, &obj);
+ obj.free();
+ }
+
+ }
+
+ return jsNameTree;
+}
+
+LinkAction* Catalog::getAdditionalAction(DocumentAdditionalActionsType type) {
+ Object additionalActionsObject;
+ LinkAction *linkAction = NULL;
+
+ if (additionalActions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+ const char *key = (type == actionCloseDocument ? "WC" :
+ type == actionSaveDocumentStart ? "WS" :
+ type == actionSaveDocumentFinish ? "DS" :
+ type == actionPrintDocumentStart ? "WP" :
+ type == actionPrintDocumentFinish ? "DP" : NULL);
+
+ Object actionObject;
+
+ if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+ linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
+ actionObject.free();
+ }
+
+ additionalActionsObject.free();
+
+ return linkAction;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Catalog.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Catalog.h
new file mode 100644
index 00000000000..bc9ce20b098
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Catalog.h
@@ -0,0 +1,272 @@
+//========================================================================
+//
+// Catalog.h
+//
+// Copyright 1996-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005, 2007, 2009-2011, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
+// Copyright (C) 2005, 2006, 2008 Brad Hards <bradh@frogmouth.net>
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2008, 2011 Pino Toscano <pino@kde.org>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 José Aliste <jaliste@src.gnome.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef CATALOG_H
+#define CATALOG_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "Object.h"
+#include "goo/GooMutex.h"
+
+#include <vector>
+
+class PDFDoc;
+class XRef;
+class Object;
+class Page;
+class PageAttrs;
+struct Ref;
+class LinkDest;
+class LinkAction;
+class PageLabelInfo;
+class Form;
+class OCGs;
+class ViewerPreferences;
+class FileSpec;
+class StructTreeRoot;
+
+//------------------------------------------------------------------------
+// NameTree
+//------------------------------------------------------------------------
+
+class NameTree {
+public:
+ NameTree();
+ ~NameTree();
+ void init(XRef *xref, Object *tree);
+ GBool lookup(GooString *name, Object *obj);
+ int numEntries() { return length; };
+ // iterator accessor, note it returns a shallow copy, do not free the object
+ Object getValue(int i);
+ GooString *getName(int i);
+
+private:
+ struct Entry {
+ Entry(Array *array, int index);
+ ~Entry();
+ GooString name;
+ Object value;
+ void free();
+ static int cmpEntry(const void *voidEntry, const void *voidOtherEntry);
+ static int cmp(const void *key, const void *entry);
+ };
+
+ void parse(Object *tree);
+ void addEntry(Entry *entry);
+
+ XRef *xref;
+ Object *root;
+ Entry **entries;
+ int size, length; // size is the number of entries in
+ // the array of Entry*
+ // length is the number of real Entry
+};
+
+//------------------------------------------------------------------------
+// Catalog
+//------------------------------------------------------------------------
+
+class Catalog {
+public:
+
+ // Constructor.
+ Catalog(PDFDoc *docA);
+
+ // Destructor.
+ ~Catalog();
+
+ // Is catalog valid?
+ GBool isOk() { return ok; }
+
+ // Get number of pages.
+ int getNumPages();
+
+ // Get a page.
+ Page *getPage(int i);
+
+ // Get the reference for a page object.
+ Ref *getPageRef(int i);
+
+ // Return base URI, or NULL if none.
+ GooString *getBaseURI() { return baseURI; }
+
+ // Return the contents of the metadata stream, or NULL if there is
+ // no metadata.
+ GooString *readMetadata();
+
+ // Return the structure tree root object.
+ StructTreeRoot *getStructTreeRoot();
+
+ // Return values from the MarkInfo dictionary as flags in a bitfield.
+ enum MarkInfoFlags {
+ markInfoNull = 1 << 0,
+ markInfoMarked = 1 << 1,
+ markInfoUserProperties = 1 << 2,
+ markInfoSuspects = 1 << 3,
+ };
+ Guint getMarkInfo();
+
+ // Find a page, given its object ID. Returns page number, or 0 if
+ // not found.
+ int findPage(int num, int gen);
+
+ // Find a named destination. Returns the link destination, or
+ // NULL if <name> is not a destination.
+ LinkDest *findDest(GooString *name);
+
+ Object *getDests();
+
+ // Get the number of embedded files
+ int numEmbeddedFiles() { return getEmbeddedFileNameTree()->numEntries(); }
+
+ // Get the i'th file embedded (at the Document level) in the document
+ FileSpec *embeddedFile(int i);
+
+ // Get the number of javascript scripts
+ int numJS() { return getJSNameTree()->numEntries(); }
+ GooString *getJSName(int i) { return getJSNameTree()->getName(i); }
+
+ // Get the i'th JavaScript script (at the Document level) in the document
+ GooString *getJS(int i);
+
+ // Convert between page indices and page labels.
+ GBool labelToIndex(GooString *label, int *index);
+ GBool indexToLabel(int index, GooString *label);
+
+ Object *getOutline();
+
+ Object *getAcroForm() { return &acroForm; }
+
+ OCGs *getOptContentConfig() { return optContent; }
+
+ enum FormType
+ {
+ NoForm,
+ AcroForm,
+ XfaForm
+ };
+
+ FormType getFormType();
+ Form* getForm();
+
+ ViewerPreferences *getViewerPreferences();
+
+ enum PageMode {
+ pageModeNone,
+ pageModeOutlines,
+ pageModeThumbs,
+ pageModeFullScreen,
+ pageModeOC,
+ pageModeAttach,
+ pageModeNull
+ };
+ enum PageLayout {
+ pageLayoutNone,
+ pageLayoutSinglePage,
+ pageLayoutOneColumn,
+ pageLayoutTwoColumnLeft,
+ pageLayoutTwoColumnRight,
+ pageLayoutTwoPageLeft,
+ pageLayoutTwoPageRight,
+ pageLayoutNull
+ };
+
+ // Returns the page mode.
+ PageMode getPageMode();
+ PageLayout getPageLayout();
+
+ enum DocumentAdditionalActionsType {
+ actionCloseDocument, ///< Performed before closing the document
+ actionSaveDocumentStart, ///< Performed before saving the document
+ actionSaveDocumentFinish, ///< Performed after saving the document
+ actionPrintDocumentStart, ///< Performed before printing the document
+ actionPrintDocumentFinish, ///< Performed after printing the document
+ };
+
+ LinkAction *getAdditionalAction(DocumentAdditionalActionsType type);
+
+private:
+
+ // Get page label info.
+ PageLabelInfo *getPageLabelInfo();
+
+ PDFDoc *doc;
+ XRef *xref; // the xref table for this PDF file
+ Page **pages; // array of pages
+ Ref *pageRefs; // object ID for each page
+ int lastCachedPage;
+ std::vector<Dict *> *pagesList;
+ std::vector<Ref> *pagesRefList;
+ std::vector<PageAttrs *> *attrsList;
+ std::vector<int> *kidsIdxList;
+ Form *form;
+ ViewerPreferences *viewerPrefs;
+ int numPages; // number of pages
+ int pagesSize; // size of pages array
+ Object dests; // named destination dictionary
+ Object names; // named names dictionary
+ NameTree *destNameTree; // named destination name-tree
+ NameTree *embeddedFileNameTree; // embedded file name-tree
+ NameTree *jsNameTree; // Java Script name-tree
+ GooString *baseURI; // base URI for URI-type links
+ Object metadata; // metadata stream
+ StructTreeRoot *structTreeRoot; // structure tree root
+ Guint markInfo; // Flags from MarkInfo dictionary
+ Object outline; // outline dictionary
+ Object acroForm; // AcroForm dictionary
+ Object viewerPreferences; // ViewerPreference dictionary
+ OCGs *optContent; // Optional Content groups
+ GBool ok; // true if catalog is valid
+ PageLabelInfo *pageLabelInfo; // info about page labels
+ PageMode pageMode; // page mode
+ PageLayout pageLayout; // page layout
+ Object additionalActions; // page additional actions
+
+ GBool cachePageTree(int page); // Cache first <page> pages.
+ Object *findDestInTree(Object *tree, GooString *name, Object *obj);
+
+ Object *getNames();
+ NameTree *getDestNameTree();
+ NameTree *getEmbeddedFileNameTree();
+ NameTree *getJSNameTree();
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CharCodeToUnicode.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/CharCodeToUnicode.cc
new file mode 100644
index 00000000000..5576a4a57d4
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CharCodeToUnicode.cc
@@ -0,0 +1,729 @@
+//========================================================================
+//
+// CharCodeToUnicode.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2008-2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
+// Copyright (C) 2008 Vasile Gaburici <gaburici@cs.umd.edu>
+// Copyright (C) 2010 William Bader <williambader@hotmail.com>
+// Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2014 Jiri Slaby <jirislaby@gmail.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "goo/gfile.h"
+#include "goo/GooLikely.h"
+#include "goo/GooString.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "PSTokenizer.h"
+#include "CharCodeToUnicode.h"
+#include "UTF.h"
+
+//------------------------------------------------------------------------
+
+struct CharCodeToUnicodeString {
+ CharCode c;
+ Unicode *u;
+ int len;
+};
+
+//------------------------------------------------------------------------
+
+static int getCharFromString(void *data) {
+ char *p;
+ int c;
+
+ p = *(char **)data;
+ if (*p) {
+ c = *p++;
+ *(char **)data = p;
+ } else {
+ c = EOF;
+ }
+ return c;
+}
+
+static int getCharFromFile(void *data) {
+ return fgetc((FILE *)data);
+}
+
+//------------------------------------------------------------------------
+
+static int hexCharVals[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2x
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 3x
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5x
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 8x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 9x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ax
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Bx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Cx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Dx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ex
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // Fx
+};
+
+// Parse a <len>-byte hex string <s> into *<val>. Returns false on
+// error.
+static GBool parseHex(char *s, int len, Guint *val) {
+ int i, x;
+
+ *val = 0;
+ for (i = 0; i < len; ++i) {
+ x = hexCharVals[s[i] & 0xff];
+ if (x < 0) {
+ return gFalse;
+ }
+ *val = (*val << 4) + x;
+ }
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+
+CharCodeToUnicode *CharCodeToUnicode::makeIdentityMapping() {
+ CharCodeToUnicode *ctu = new CharCodeToUnicode();
+ ctu->isIdentity = gTrue;
+ ctu->mapLen = 1;
+ ctu->map = (Unicode *)gmallocn(ctu->mapLen, sizeof(Unicode));
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GooString *fileName,
+ GooString *collection) {
+ FILE *f;
+ Unicode *mapA;
+ CharCode size, mapLenA;
+ char buf[64];
+ Unicode u;
+ CharCodeToUnicode *ctu;
+
+ if (!(f = openFile(fileName->getCString(), "r"))) {
+ error(errIO, -1, "Couldn't open cidToUnicode file '{0:t}'",
+ fileName);
+ return NULL;
+ }
+
+ size = 32768;
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
+ mapLenA = 0;
+
+ while (getLine(buf, sizeof(buf), f)) {
+ if (mapLenA == size) {
+ size *= 2;
+ mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
+ }
+ if (sscanf(buf, "%x", &u) == 1) {
+ mapA[mapLenA] = u;
+ } else {
+ error(errSyntaxWarning, -1, "Bad line ({0:d}) in cidToUnicode file '{1:t}'",
+ (int)(mapLenA + 1), fileName);
+ mapA[mapLenA] = 0;
+ }
+ ++mapLenA;
+ }
+ fclose(f);
+
+ ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue,
+ NULL, 0, 0);
+ gfree(mapA);
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(
+ GooString *fileName) {
+ FILE *f;
+ Unicode *mapA;
+ CharCodeToUnicodeString *sMapA;
+ CharCode size, oldSize, len, sMapSizeA, sMapLenA;
+ char buf[256];
+ char *tok;
+ Unicode u0;
+ int uBufSize = 8;
+ Unicode *uBuf = (Unicode *)gmallocn(uBufSize, sizeof(Unicode));
+ CharCodeToUnicode *ctu;
+ int line, n, i;
+ char *tokptr;
+
+ if (!(f = openFile(fileName->getCString(), "r"))) {
+ gfree(uBuf);
+ error(errIO, -1, "Couldn't open unicodeToUnicode file '{0:t}'",
+ fileName);
+ return NULL;
+ }
+
+ size = 4096;
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
+ memset(mapA, 0, size * sizeof(Unicode));
+ len = 0;
+ sMapA = NULL;
+ sMapSizeA = sMapLenA = 0;
+
+ line = 0;
+ while (getLine(buf, sizeof(buf), f)) {
+ ++line;
+ if (!(tok = strtok_r(buf, " \t\r\n", &tokptr)) ||
+ !parseHex(tok, strlen(tok), &u0)) {
+ error(errSyntaxWarning, -1, "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'",
+ line, fileName);
+ continue;
+ }
+ n = 0;
+ while ((tok = strtok_r(NULL, " \t\r\n", &tokptr))) {
+ if (n >= uBufSize)
+ {
+ uBufSize += 8;
+ uBuf = (Unicode *)greallocn(uBuf, uBufSize, sizeof(Unicode));
+ }
+ if (!parseHex(tok, strlen(tok), &uBuf[n])) {
+ error(errSyntaxWarning, -1, "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'",
+ line, fileName);
+ break;
+ }
+ ++n;
+ }
+ if (n < 1) {
+ error(errSyntaxWarning, -1, "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'",
+ line, fileName);
+ continue;
+ }
+ if (u0 >= size) {
+ oldSize = size;
+ while (u0 >= size) {
+ size *= 2;
+ }
+ mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
+ memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode));
+ }
+ if (n == 1) {
+ mapA[u0] = uBuf[0];
+ } else {
+ mapA[u0] = 0;
+ if (sMapLenA == sMapSizeA) {
+ sMapSizeA += 16;
+ sMapA = (CharCodeToUnicodeString *)
+ greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString));
+ }
+ sMapA[sMapLenA].c = u0;
+ sMapA[sMapLenA].u = (Unicode*)gmallocn(n, sizeof(Unicode));
+ for (i = 0; i < n; ++i) {
+ sMapA[sMapLenA].u[i] = uBuf[i];
+ }
+ sMapA[sMapLenA].len = n;
+ ++sMapLenA;
+ }
+ if (u0 >= len) {
+ len = u0 + 1;
+ }
+ }
+ fclose(f);
+
+ ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue,
+ sMapA, sMapLenA, sMapSizeA);
+ gfree(mapA);
+ gfree(uBuf);
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) {
+ return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0);
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseCMap(GooString *buf, int nBits) {
+ CharCodeToUnicode *ctu;
+ char *p;
+
+ ctu = new CharCodeToUnicode(NULL);
+ p = buf->getCString();
+ ctu->parseCMap1(&getCharFromString, &p, nBits);
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseCMapFromFile(GooString *fileName,
+ int nBits) {
+ CharCodeToUnicode *ctu;
+ FILE *f;
+
+ ctu = new CharCodeToUnicode(NULL);
+ if ((f = globalParams->findToUnicodeFile(fileName))) {
+ ctu->parseCMap1(&getCharFromFile, f, nBits);
+ fclose(f);
+ } else {
+ error(errSyntaxError, -1, "Couldn't find ToUnicode CMap file for '{0:t}'",
+ fileName);
+ }
+ return ctu;
+}
+
+void CharCodeToUnicode::mergeCMap(GooString *buf, int nBits) {
+ char *p;
+
+ p = buf->getCString();
+ parseCMap1(&getCharFromString, &p, nBits);
+}
+
+void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
+ int nBits) {
+ PSTokenizer *pst;
+ char tok1[256], tok2[256], tok3[256];
+ int n1, n2, n3;
+ CharCode i;
+ CharCode maxCode, code1, code2;
+ GooString *name;
+ FILE *f;
+
+ maxCode = (nBits == 8) ? 0xff : (nBits == 16) ? 0xffff : 0xffffffff;
+ pst = new PSTokenizer(getCharFunc, data);
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ while (pst->getToken(tok2, sizeof(tok2), &n2)) {
+ if (!strcmp(tok2, "usecmap")) {
+ if (tok1[0] == '/') {
+ name = new GooString(tok1 + 1);
+ if ((f = globalParams->findToUnicodeFile(name))) {
+ parseCMap1(&getCharFromFile, f, nBits);
+ fclose(f);
+ } else {
+ error(errSyntaxError, -1, "Couldn't find ToUnicode CMap file for '{0:t}'",
+ name);
+ }
+ delete name;
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "beginbfchar")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endbfchar")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endbfchar")) {
+ error(errSyntaxWarning, -1, "Illegal entry in bfchar block in ToUnicode CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ tok2[0] == '<' && tok2[n2 - 1] == '>')) {
+ error(errSyntaxWarning, -1, "Illegal entry in bfchar block in ToUnicode CMap");
+ continue;
+ }
+ tok1[n1 - 1] = tok2[n2 - 1] = '\0';
+ if (!parseHex(tok1 + 1, n1 - 2, &code1)) {
+ error(errSyntaxWarning, -1, "Illegal entry in bfchar block in ToUnicode CMap");
+ continue;
+ }
+ if (code1 > maxCode) {
+ error(errSyntaxWarning, -1,
+ "Invalid entry in bfchar block in ToUnicode CMap");
+ }
+ addMapping(code1, tok2 + 1, n2 - 2, 0);
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "beginbfrange")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endbfrange")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endbfrange") ||
+ !pst->getToken(tok3, sizeof(tok3), &n3) ||
+ !strcmp(tok3, "endbfrange")) {
+ error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ tok2[0] == '<' && tok2[n2 - 1] == '>')) {
+ error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap");
+ continue;
+ }
+ tok1[n1 - 1] = tok2[n2 - 1] = '\0';
+ if (!parseHex(tok1 + 1, n1 - 2, &code1) ||
+ !parseHex(tok2 + 1, n2 - 2, &code2)) {
+ error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap");
+ continue;
+ }
+ if (code1 > maxCode || code2 > maxCode) {
+ error(errSyntaxWarning, -1,
+ "Invalid entry in bfrange block in ToUnicode CMap");
+ if (code1 > maxCode) {
+ code1 = maxCode;
+ }
+ if (code2 > maxCode) {
+ code2 = maxCode;
+ }
+ }
+ if (!strcmp(tok3, "[")) {
+ i = 0;
+ while (pst->getToken(tok1, sizeof(tok1), &n1) &&
+ code1 + i <= code2) {
+ if (!strcmp(tok1, "]")) {
+ break;
+ }
+ if (tok1[0] == '<' && tok1[n1 - 1] == '>') {
+ tok1[n1 - 1] = '\0';
+ addMapping(code1 + i, tok1 + 1, n1 - 2, 0);
+ } else {
+ error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap");
+ }
+ ++i;
+ }
+ } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') {
+ tok3[n3 - 1] = '\0';
+ for (i = 0; code1 <= code2; ++code1, ++i) {
+ addMapping(code1, tok3 + 1, n3 - 2, i);
+ }
+
+ } else {
+ error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap");
+ }
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else {
+ strcpy(tok1, tok2);
+ }
+ }
+ delete pst;
+}
+
+void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
+ int offset) {
+ CharCode oldLen, i;
+ Unicode u;
+ int j;
+
+ if (code > 0xffffff) {
+ // This is an arbitrary limit to avoid integer overflow issues.
+ // (I've seen CMaps with mappings for <ffffffff>.)
+ return;
+ }
+ if (code >= mapLen) {
+ oldLen = mapLen;
+ mapLen = mapLen ? 2 * mapLen : 256;
+ if (code >= mapLen) {
+ mapLen = (code + 256) & ~255;
+ }
+ if (unlikely(code >= mapLen)) {
+ error(errSyntaxWarning, -1, "Illegal code value in CharCodeToUnicode::addMapping");
+ return;
+ } else {
+ map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode));
+ for (i = oldLen; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+ }
+ }
+ if (n <= 4) {
+ if (!parseHex(uStr, n, &u)) {
+ error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
+ return;
+ }
+ map[code] = u + offset;
+ if (!UnicodeIsValid(map[code])) {
+ map[code] = 0xfffd;
+ }
+ } else {
+ if (sMapLen >= sMapSize) {
+ sMapSize = sMapSize + 16;
+ sMap = (CharCodeToUnicodeString *)
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+ }
+ map[code] = 0;
+ sMap[sMapLen].c = code;
+ int utf16Len = n / 4;
+ Unicode *utf16 = (Unicode*)gmallocn(utf16Len, sizeof(Unicode));
+ for (j = 0; j < utf16Len; ++j) {
+ if (!parseHex(uStr + j*4, 4, &utf16[j])) {
+ gfree(utf16);
+ error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
+ return;
+ }
+ }
+ utf16[utf16Len - 1] += offset;
+ sMap[sMapLen].len = UTF16toUCS4(utf16, utf16Len, &sMap[sMapLen].u);
+ gfree(utf16);
+ ++sMapLen;
+ }
+}
+
+CharCodeToUnicode::CharCodeToUnicode() {
+ tag = NULL;
+ map = NULL;
+ mapLen = 0;
+ sMap = NULL;
+ sMapLen = sMapSize = 0;
+ refCnt = 1;
+ isIdentity = gFalse;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+CharCodeToUnicode::CharCodeToUnicode(GooString *tagA) {
+ CharCode i;
+
+ tag = tagA;
+ mapLen = 256;
+ map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
+ for (i = 0; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+ sMap = NULL;
+ sMapLen = sMapSize = 0;
+ refCnt = 1;
+ isIdentity = gFalse;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+CharCodeToUnicode::CharCodeToUnicode(GooString *tagA, Unicode *mapA,
+ CharCode mapLenA, GBool copyMap,
+ CharCodeToUnicodeString *sMapA,
+ int sMapLenA, int sMapSizeA) {
+ tag = tagA;
+ mapLen = mapLenA;
+ if (copyMap) {
+ map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
+ memcpy(map, mapA, mapLen * sizeof(Unicode));
+ } else {
+ map = mapA;
+ }
+ sMap = sMapA;
+ sMapLen = sMapLenA;
+ sMapSize = sMapSizeA;
+ refCnt = 1;
+ isIdentity = gFalse;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+CharCodeToUnicode::~CharCodeToUnicode() {
+ if (tag) {
+ delete tag;
+ }
+ gfree(map);
+ if (sMap) {
+ for (int i = 0; i < sMapLen; ++i) gfree(sMap[i].u);
+ gfree(sMap);
+ }
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+void CharCodeToUnicode::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ ++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+}
+
+void CharCodeToUnicode::decRefCnt() {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
+ delete this;
+ }
+}
+
+GBool CharCodeToUnicode::match(GooString *tagA) {
+ return tag && !tag->cmp(tagA);
+}
+
+void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) {
+ int i, j;
+
+ if (!map || isIdentity) {
+ return;
+ }
+ if (len == 1) {
+ map[c] = u[0];
+ } else {
+ for (i = 0; i < sMapLen; ++i) {
+ if (sMap[i].c == c) {
+ gfree(sMap[i].u);
+ break;
+ }
+ }
+ if (i == sMapLen) {
+ if (sMapLen == sMapSize) {
+ sMapSize += 8;
+ sMap = (CharCodeToUnicodeString *)
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+ }
+ ++sMapLen;
+ }
+ map[c] = 0;
+ sMap[i].c = c;
+ sMap[i].len = len;
+ sMap[i].u = (Unicode*)gmallocn(len, sizeof(Unicode));
+ for (j = 0; j < len; ++j) {
+ if (UnicodeIsValid(u[j])) {
+ sMap[i].u[j] = u[j];
+ } else {
+ sMap[i].u[j] = 0xfffd;
+ }
+ }
+ }
+}
+
+int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode **u) {
+ int i;
+
+ if (isIdentity) {
+ map[0] = (Unicode)c;
+ *u = map;
+ return 1;
+ }
+ if (c >= mapLen) {
+ return 0;
+ }
+ if (map[c]) {
+ *u = &map[c];
+ return 1;
+ }
+ for (i = sMapLen - 1; i >= 0; --i) { // in reverse so CMap takes precedence
+ if (sMap[i].c == c) {
+ *u = sMap[i].u;
+ return sMap[i].len;
+ }
+ }
+ return 0;
+}
+
+int CharCodeToUnicode::mapToCharCode(Unicode* u, CharCode *c, int usize) {
+ //look for charcode in map
+ if (usize == 1 || (usize > 1 && !(*u & ~0xff))) {
+ if (isIdentity) {
+ *c = (CharCode) *u;
+ return 1;
+ }
+ for (CharCode i=0; i<mapLen; i++) {
+ if (map[i] == *u) {
+ *c = i;
+ return 1;
+ }
+ }
+ *c = 'x';
+ } else {
+ int i, j;
+ //for each entry in the sMap
+ for (i=0; i<sMapLen; i++) {
+ //if the entry's unicode length isn't the same are usize, the strings
+ // are obviously differents
+ if (sMap[i].len != usize) continue;
+ //compare the string char by char
+ for (j=0; j<sMap[i].len; j++) {
+ if (sMap[i].u[j] != u[j]) {
+ continue;
+ }
+ }
+
+ //we have the same strings
+ if (j==sMap[i].len) {
+ *c = sMap[i].c;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------
+
+CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) {
+ int i;
+
+ size = sizeA;
+ cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *));
+ for (i = 0; i < size; ++i) {
+ cache[i] = NULL;
+ }
+}
+
+CharCodeToUnicodeCache::~CharCodeToUnicodeCache() {
+ int i;
+
+ for (i = 0; i < size; ++i) {
+ if (cache[i]) {
+ cache[i]->decRefCnt();
+ }
+ }
+ gfree(cache);
+}
+
+CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GooString *tag) {
+ CharCodeToUnicode *ctu;
+ int i, j;
+
+ if (cache[0] && cache[0]->match(tag)) {
+ cache[0]->incRefCnt();
+ return cache[0];
+ }
+ for (i = 1; i < size; ++i) {
+ if (cache[i] && cache[i]->match(tag)) {
+ ctu = cache[i];
+ for (j = i; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = ctu;
+ ctu->incRefCnt();
+ return ctu;
+ }
+ }
+ return NULL;
+}
+
+void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) {
+ int i;
+
+ if (cache[size - 1]) {
+ cache[size - 1]->decRefCnt();
+ }
+ for (i = size - 1; i >= 1; --i) {
+ cache[i] = cache[i - 1];
+ }
+ cache[0] = ctu;
+ ctu->incRefCnt();
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CharCodeToUnicode.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CharCodeToUnicode.h
new file mode 100644
index 00000000000..1672105a8f4
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CharCodeToUnicode.h
@@ -0,0 +1,146 @@
+//========================================================================
+//
+// CharCodeToUnicode.h
+//
+// Mapping from character codes to Unicode.
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2008, 2011, 2012 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef CHARCODETOUNICODE_H
+#define CHARCODETOUNICODE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "CharTypes.h"
+#include "goo/gtypes.h"
+
+#if MULTITHREADED
+#include "goo/GooMutex.h"
+#endif
+
+struct CharCodeToUnicodeString;
+class GooString;
+
+//------------------------------------------------------------------------
+
+class CharCodeToUnicode {
+friend class UnicodeToCharCode;
+public:
+
+ // Create an identity mapping (Unicode = CharCode).
+ static CharCodeToUnicode *makeIdentityMapping();
+
+ // Read the CID-to-Unicode mapping for <collection> from the file
+ // specified by <fileName>. Sets the initial reference count to 1.
+ // Returns NULL on failure.
+ static CharCodeToUnicode *parseCIDToUnicode(GooString *fileName,
+ GooString *collection);
+
+ // Create a Unicode-to-Unicode mapping from the file specified by
+ // <fileName>. Sets the initial reference count to 1. Returns NULL
+ // on failure.
+ static CharCodeToUnicode *parseUnicodeToUnicode(GooString *fileName);
+
+ // Create the CharCode-to-Unicode mapping for an 8-bit font.
+ // <toUnicode> is an array of 256 Unicode indexes. Sets the initial
+ // reference count to 1.
+ static CharCodeToUnicode *make8BitToUnicode(Unicode *toUnicode);
+
+ // Parse a ToUnicode CMap for an 8- or 16-bit font.
+ static CharCodeToUnicode *parseCMap(GooString *buf, int nBits);
+ static CharCodeToUnicode *parseCMapFromFile(GooString *fileName, int nBits);
+
+ // Parse a ToUnicode CMap for an 8- or 16-bit font, merging it into
+ // <this>.
+ void mergeCMap(GooString *buf, int nBits);
+
+ ~CharCodeToUnicode();
+
+ void incRefCnt();
+ void decRefCnt();
+
+ // Return true if this mapping matches the specified <tagA>.
+ GBool match(GooString *tagA);
+
+ // Set the mapping for <c>.
+ void setMapping(CharCode c, Unicode *u, int len);
+
+ // Map a CharCode to Unicode. Returns a pointer in u to internal storage
+ // so never store the pointers it returns, just the data, otherwise
+ // your pointed values might get changed by future calls
+ int mapToUnicode(CharCode c, Unicode **u);
+
+ // Map a Unicode to CharCode.
+ int mapToCharCode(Unicode* u, CharCode *c, int usize);
+
+ // Return the mapping's length, i.e., one more than the max char
+ // code supported by the mapping.
+ CharCode getLength() { return mapLen; }
+
+private:
+
+ void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits);
+ void addMapping(CharCode code, char *uStr, int n, int offset);
+ CharCodeToUnicode();
+ CharCodeToUnicode(GooString *tagA);
+ CharCodeToUnicode(GooString *tagA, Unicode *mapA,
+ CharCode mapLenA, GBool copyMap,
+ CharCodeToUnicodeString *sMapA,
+ int sMapLenA, int sMapSizeA);
+
+ GooString *tag;
+ Unicode *map;
+ CharCode mapLen;
+ CharCodeToUnicodeString *sMap;
+ int sMapLen, sMapSize;
+ int refCnt;
+ GBool isIdentity;
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+//------------------------------------------------------------------------
+
+class CharCodeToUnicodeCache {
+public:
+
+ CharCodeToUnicodeCache(int sizeA);
+ ~CharCodeToUnicodeCache();
+
+ // Get the CharCodeToUnicode object for <tag>. Increments its
+ // reference count; there will be one reference for the cache plus
+ // one for the caller of this function. Returns NULL on failure.
+ CharCodeToUnicode *getCharCodeToUnicode(GooString *tag);
+
+ // Insert <ctu> into the cache, in the most-recently-used position.
+ void add(CharCodeToUnicode *ctu);
+
+private:
+
+ CharCodeToUnicode **cache;
+ int size;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CharTypes.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CharTypes.h
new file mode 100644
index 00000000000..d0df630d0c9
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CharTypes.h
@@ -0,0 +1,24 @@
+//========================================================================
+//
+// CharTypes.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef CHARTYPES_H
+#define CHARTYPES_H
+
+// Unicode character.
+typedef unsigned int Unicode;
+
+// Character ID for CID character collections.
+typedef unsigned int CID;
+
+// This is large enough to hold any of the following:
+// - 8-bit char code
+// - 16-bit CID
+// - Unicode
+typedef unsigned int CharCode;
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CompactFontTables.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CompactFontTables.h
new file mode 100644
index 00000000000..cfbfdaf5752
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CompactFontTables.h
@@ -0,0 +1,480 @@
+//========================================================================
+//
+// CompactFontTables.h
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2011 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef COMPACTFONTINFO_H
+#define COMPACTFONTINFO_H
+
+#include "goo/gtypes.h"
+
+static char *type1CStdStrings[391] = {
+ ".notdef",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ "questiondown",
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ "AE",
+ "ordfeminine",
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ "ae",
+ "dotlessi",
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ "onesuperior",
+ "logicalnot",
+ "mu",
+ "trademark",
+ "Eth",
+ "onehalf",
+ "plusminus",
+ "Thorn",
+ "onequarter",
+ "divide",
+ "brokenbar",
+ "degree",
+ "thorn",
+ "threequarters",
+ "twosuperior",
+ "registered",
+ "minus",
+ "eth",
+ "multiply",
+ "threesuperior",
+ "copyright",
+ "Aacute",
+ "Acircumflex",
+ "Adieresis",
+ "Agrave",
+ "Aring",
+ "Atilde",
+ "Ccedilla",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Ntilde",
+ "Oacute",
+ "Ocircumflex",
+ "Odieresis",
+ "Ograve",
+ "Otilde",
+ "Scaron",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Ugrave",
+ "Yacute",
+ "Ydieresis",
+ "Zcaron",
+ "aacute",
+ "acircumflex",
+ "adieresis",
+ "agrave",
+ "aring",
+ "atilde",
+ "ccedilla",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "egrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "igrave",
+ "ntilde",
+ "oacute",
+ "ocircumflex",
+ "odieresis",
+ "ograve",
+ "otilde",
+ "scaron",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "ugrave",
+ "yacute",
+ "ydieresis",
+ "zcaron",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ "isuperior",
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ "ff",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ "Dotaccentsmall",
+ "Macronsmall",
+ "figuredash",
+ "hypheninferior",
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ "zerosuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall",
+ "001.000",
+ "001.001",
+ "001.002",
+ "001.003",
+ "Black",
+ "Bold",
+ "Book",
+ "Light",
+ "Medium",
+ "Regular",
+ "Roman",
+ "Semibold"
+};
+
+static Gushort type1CISOAdobeCharset[229] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228
+};
+
+static const Gushort type1CExpertCharset[166] = {
+ 0, 1, 229, 230, 231, 232, 233, 234, 235, 236,
+ 237, 238, 13, 14, 15, 99, 239, 240, 241, 242,
+ 243, 244, 245, 246, 247, 248, 27, 28, 249, 250,
+ 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
+ 261, 262, 263, 264, 265, 266, 109, 110, 267, 268,
+ 269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
+ 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, 301, 302, 303, 304, 305, 306, 307, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, 318,
+ 158, 155, 163, 319, 320, 321, 322, 323, 324, 325,
+ 326, 150, 164, 169, 327, 328, 329, 330, 331, 332,
+ 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+ 343, 344, 345, 346, 347, 348, 349, 350, 351, 352,
+ 353, 354, 355, 356, 357, 358, 359, 360, 361, 362,
+ 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
+ 373, 374, 375, 376, 377, 378
+};
+
+static Gushort type1CExpertSubsetCharset[87] = {
+ 0, 1, 231, 232, 235, 236, 237, 238, 13, 14,
+ 15, 99, 239, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 27, 28, 249, 250, 251, 253, 254, 255,
+ 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 109, 110, 267, 268, 269, 270, 272, 300, 301,
+ 302, 305, 314, 315, 158, 155, 163, 320, 321, 322,
+ 323, 324, 325, 326, 150, 164, 169, 327, 328, 329,
+ 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
+ 340, 341, 342, 343, 344, 345, 346
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlCachedFile.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlCachedFile.cc
new file mode 100644
index 00000000000..af4c2b60322
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlCachedFile.cc
@@ -0,0 +1,99 @@
+//========================================================================
+//
+// CurlCachedFile.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2009 Stefan Thomas <thomas@eload24.com>
+// Copyright 2010, 2011 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "CurlCachedFile.h"
+
+#include "goo/GooString.h"
+
+//------------------------------------------------------------------------
+
+CurlCachedFileLoader::CurlCachedFileLoader()
+{
+ url = NULL;
+ cachedFile = NULL;
+ curl = NULL;
+}
+
+CurlCachedFileLoader::~CurlCachedFileLoader() {
+ curl_easy_cleanup(curl);
+}
+
+static size_t
+noop_cb(char *ptr, size_t size, size_t nmemb, void *ptr2)
+{
+ return size*nmemb;
+}
+
+size_t
+CurlCachedFileLoader::init(GooString *urlA, CachedFile *cachedFileA)
+{
+ double contentLength = -1;
+ long code = 0;
+ size_t size;
+
+ url = urlA;
+ cachedFile = cachedFileA;
+ curl = curl_easy_init();
+
+ curl_easy_setopt(curl, CURLOPT_URL, url->getCString());
+ curl_easy_setopt(curl, CURLOPT_HEADER, 1);
+ curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &noop_cb);
+ curl_easy_perform(curl);
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
+ if (code) {
+ curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &contentLength);
+ size = contentLength;
+ } else {
+ error(errInternal, -1, "Failed to get size of '{0:t}'.", url);
+ size = -1;
+ }
+ curl_easy_reset(curl);
+
+ return size;
+}
+
+static
+size_t load_cb(const char *ptr, size_t size, size_t nmemb, void *data)
+{
+ CachedFileWriter *writer = (CachedFileWriter *) data;
+ return (writer->write) (ptr, size*nmemb);
+}
+
+int CurlCachedFileLoader::load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer)
+{
+ CURLcode r = CURLE_OK;
+ size_t fromByte, toByte;
+ for (size_t i = 0; i < ranges.size(); i++) {
+
+ fromByte = ranges[i].offset;
+ toByte = fromByte + ranges[i].length - 1;
+ GooString *range = GooString::format("{0:ud}-{1:ud}", fromByte, toByte);
+
+ curl_easy_setopt(curl, CURLOPT_URL, url->getCString());
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, load_cb);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, writer);
+ curl_easy_setopt(curl, CURLOPT_RANGE, range->getCString());
+ r = curl_easy_perform(curl);
+ curl_easy_reset(curl);
+
+ delete range;
+
+ if (r != CURLE_OK) break;
+ }
+ return r;
+}
+
+//------------------------------------------------------------------------
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlCachedFile.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlCachedFile.h
new file mode 100644
index 00000000000..49882aba8ac
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlCachedFile.h
@@ -0,0 +1,40 @@
+//========================================================================
+//
+// CurlCachedFile.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef CURLCACHELOADER_H
+#define CURLCACHELOADER_H
+
+#include "poppler-config.h"
+#include "CachedFile.h"
+
+#include <curl/curl.h>
+
+//------------------------------------------------------------------------
+
+class CurlCachedFileLoader : public CachedFileLoader {
+
+public:
+
+ CurlCachedFileLoader();
+ ~CurlCachedFileLoader();
+ size_t init(GooString *url, CachedFile* cachedFile);
+ int load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer);
+
+private:
+
+ GooString *url;
+ CachedFile *cachedFile;
+ CURL *curl;
+
+};
+
+#endif
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlPDFDocBuilder.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlPDFDocBuilder.cc
new file mode 100644
index 00000000000..5b02b14a784
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlPDFDocBuilder.cc
@@ -0,0 +1,47 @@
+//========================================================================
+//
+// CurlPDFDocBuilder.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "CurlPDFDocBuilder.h"
+
+#include "CachedFile.h"
+#include "CurlCachedFile.h"
+
+//------------------------------------------------------------------------
+// CurlPDFDocBuilder
+//------------------------------------------------------------------------
+
+PDFDoc *
+CurlPDFDocBuilder::buildPDFDoc(const GooString &uri,
+ GooString *ownerPassword, GooString *userPassword, void *guiDataA)
+{
+ Object obj;
+
+ CachedFile *cachedFile = new CachedFile(
+ new CurlCachedFileLoader(), uri.copy());
+
+ obj.initNull();
+ BaseStream *str = new CachedFileStream(
+ cachedFile, 0, gFalse, cachedFile->getLength(), &obj);
+
+ return new PDFDoc(str, ownerPassword, userPassword, guiDataA);
+}
+
+GBool CurlPDFDocBuilder::supports(const GooString &uri)
+{
+ if (uri.cmpN("http://", 7) == 0 || uri.cmpN("https://", 8) == 0) {
+ return gTrue;
+ } else {
+ return gFalse;
+ }
+}
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlPDFDocBuilder.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlPDFDocBuilder.h
new file mode 100644
index 00000000000..fb34862057c
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/CurlPDFDocBuilder.h
@@ -0,0 +1,33 @@
+//========================================================================
+//
+// CurlPDFDocBuilder.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef CURLPDFDOCBUILDER_H
+#define CURLPDFDOCBUILDER_H
+
+#include "PDFDocBuilder.h"
+
+//------------------------------------------------------------------------
+// CurlPDFDocBuilder
+//
+// The CurlPDFDocBuilder implements a PDFDocBuilder for 'http(s)://'.
+//------------------------------------------------------------------------
+
+class CurlPDFDocBuilder : public PDFDocBuilder {
+
+public:
+
+ PDFDoc *buildPDFDoc(const GooString &uri, GooString *ownerPassword = NULL,
+ GooString *userPassword = NULL, void *guiDataA = NULL);
+ GBool supports(const GooString &uri);
+
+};
+
+#endif /* CURLPDFDOCBUILDER_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/DCTStream.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/DCTStream.cc
new file mode 100644
index 00000000000..bfdb0eaf80a
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/DCTStream.cc
@@ -0,0 +1,266 @@
+//========================================================================
+//
+// DCTStream.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2005 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright 2005-2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright 2009 Ryszard Trojnacki <rysiek@menel.com>
+// Copyright 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright 2011 Daiki Ueno <ueno@unixuser.org>
+// Copyright 2011 Tomas Hoger <thoger@redhat.com>
+// Copyright 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+//========================================================================
+
+#include "DCTStream.h"
+
+static void str_init_source(j_decompress_ptr cinfo)
+{
+}
+
+static boolean str_fill_input_buffer(j_decompress_ptr cinfo)
+{
+ int c;
+ struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src;
+ if (src->index == 0) {
+ c = 0xFF;
+ src->index++;
+ }
+ else if (src->index == 1) {
+ c = 0xD8;
+ src->index++;
+ }
+ else c = src->str->getChar();
+ if (c != EOF)
+ {
+ src->buffer = c;
+ src->pub.next_input_byte = &src->buffer;
+ src->pub.bytes_in_buffer = 1;
+ return TRUE;
+ }
+ else return FALSE;
+}
+
+static void str_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src;
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ str_fill_input_buffer(cinfo);
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+static void str_term_source(j_decompress_ptr cinfo)
+{
+}
+
+DCTStream::DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion) :
+ FilterStream(strA) {
+ colorXform = colorXformA;
+ if (dict != NULL) {
+ Object obj;
+
+ dict->dictLookup("Width", &obj, recursion);
+ err.width = (obj.isInt() && obj.getInt() <= JPEG_MAX_DIMENSION) ? obj.getInt() : 0;
+ obj.free();
+ dict->dictLookup("Height", &obj, recursion);
+ err.height = (obj.isInt() && obj.getInt() <= JPEG_MAX_DIMENSION) ? obj.getInt() : 0;
+ obj.free();
+ } else
+ err.height = err.width = 0;
+ init();
+}
+
+DCTStream::~DCTStream() {
+ jpeg_destroy_decompress(&cinfo);
+ delete str;
+}
+
+static void exitErrorHandler(jpeg_common_struct *error) {
+ j_decompress_ptr cinfo = (j_decompress_ptr)error;
+ str_error_mgr * err = (struct str_error_mgr *)cinfo->err;
+ if (cinfo->err->msg_code == JERR_IMAGE_TOO_BIG && err->width != 0 && err->height != 0) {
+ cinfo->image_height = err->height;
+ cinfo->image_width = err->width;
+ } else {
+ longjmp(err->setjmp_buffer, 1);
+ }
+}
+
+void DCTStream::init()
+{
+ jpeg_std_error(&err.pub);
+ err.pub.error_exit = &exitErrorHandler;
+ src.pub.init_source = str_init_source;
+ src.pub.fill_input_buffer = str_fill_input_buffer;
+ src.pub.skip_input_data = str_skip_input_data;
+ src.pub.resync_to_restart = jpeg_resync_to_restart;
+ src.pub.term_source = str_term_source;
+ src.pub.bytes_in_buffer = 0;
+ src.pub.next_input_byte = NULL;
+ src.str = str;
+ src.index = 0;
+ current = NULL;
+ limit = NULL;
+
+ cinfo.err = &err.pub;
+ if (!setjmp(err.setjmp_buffer)) {
+ jpeg_create_decompress(&cinfo);
+ cinfo.src = (jpeg_source_mgr *)&src;
+ }
+ row_buffer = NULL;
+}
+
+void DCTStream::reset() {
+ int row_stride;
+
+ str->reset();
+
+ if (row_buffer)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ init();
+ }
+
+ // JPEG data has to start with 0xFF 0xD8
+ // but some pdf like the one on
+ // https://bugs.freedesktop.org/show_bug.cgi?id=3299
+ // does have some garbage before that this seeks for
+ // the start marker...
+ bool startFound = false;
+ int c = 0, c2 = 0;
+ while (!startFound)
+ {
+ if (!c)
+ {
+ c = str->getChar();
+ if (c == -1)
+ {
+ error(errSyntaxError, -1, "Could not find start of jpeg data");
+ return;
+ }
+ if (c != 0xFF) c = 0;
+ }
+ else
+ {
+ c2 = str->getChar();
+ if (c2 != 0xD8)
+ {
+ c = 0;
+ c2 = 0;
+ }
+ else startFound = true;
+ }
+ }
+
+ if (!setjmp(err.setjmp_buffer))
+ {
+ if (jpeg_read_header(&cinfo, TRUE) != JPEG_SUSPENDED)
+ {
+ // figure out color transform
+ if (colorXform == -1 && !cinfo.saw_Adobe_marker) {
+ if (cinfo.num_components == 3) {
+ if (cinfo.saw_JFIF_marker) {
+ colorXform = 1;
+ } else if (cinfo.cur_comp_info[0]->component_id == 82 &&
+ cinfo.cur_comp_info[1]->component_id == 71 &&
+ cinfo.cur_comp_info[2]->component_id == 66) { // ASCII "RGB"
+ colorXform = 0;
+ } else {
+ colorXform = 1;
+ }
+ } else {
+ colorXform = 0;
+ }
+ } else if (cinfo.saw_Adobe_marker) {
+ colorXform = cinfo.Adobe_transform;
+ }
+
+ switch (cinfo.num_components) {
+ case 3:
+ cinfo.jpeg_color_space = colorXform ? JCS_YCbCr : JCS_RGB;
+ break;
+ case 4:
+ cinfo.jpeg_color_space = colorXform ? JCS_YCCK : JCS_CMYK;
+ break;
+ }
+
+ jpeg_start_decompress(&cinfo);
+
+ row_stride = cinfo.output_width * cinfo.output_components;
+ row_buffer = cinfo.mem->alloc_sarray((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+ }
+ }
+}
+
+// we can not go with inline since gcc
+// refuses to inline because of setjmp
+#define DO_GET_CHAR \
+ if (current == limit) { \
+ if (cinfo.output_scanline < cinfo.output_height) \
+ { \
+ if (!setjmp(err.setjmp_buffer)) \
+ { \
+ if (!jpeg_read_scanlines(&cinfo, row_buffer, 1)) c = EOF; \
+ else { \
+ current = &row_buffer[0][0]; \
+ limit = &row_buffer[0][(cinfo.output_width - 1) * cinfo.output_components] + cinfo.output_components; \
+ c = *current; \
+ ++current; \
+ } \
+ } \
+ else c = EOF; \
+ } \
+ else c = EOF; \
+ } else { \
+ c = *current; \
+ ++current; \
+ } \
+
+int DCTStream::getChar() {
+ int c;
+
+ DO_GET_CHAR
+
+ return c;
+}
+
+int DCTStream::getChars(int nChars, Guchar *buffer) {
+ int c;
+ for (int i = 0; i < nChars; ++i) {
+ DO_GET_CHAR
+ if (likely(c != EOF)) buffer[i] = c;
+ else return i;
+ }
+ return nChars;
+}
+
+int DCTStream::lookChar() {
+ if (unlikely(current == NULL)) {
+ return EOF;
+ }
+ return *current;
+}
+
+GooString *DCTStream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /DCTDecode filter\n");
+ return s;
+}
+
+GBool DCTStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/DCTStream.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/DCTStream.h
new file mode 100644
index 00000000000..bc20a7aaab6
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/DCTStream.h
@@ -0,0 +1,91 @@
+//========================================================================
+//
+// DCTStream.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2005 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright 2005 Martin Kretzschmar <martink@gnome.org>
+// Copyright 2005-2007, 2009-2011 Albert Astals Cid <aacid@kde.org>
+// Copyright 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright 2011 Daiki Ueno <ueno@unixuser.org>
+// Copyright 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+//========================================================================
+
+#ifndef DCTSTREAM_H
+#define DCTSTREAM_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "poppler-config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <setjmp.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#include "goo/gmem.h"
+#include "goo/gfile.h"
+#include "Error.h"
+#include "Object.h"
+#include "Decrypt.h"
+#include "Stream.h"
+
+extern "C" {
+#include <jpeglib.h>
+#include <jerror.h>
+}
+
+struct str_src_mgr {
+ struct jpeg_source_mgr pub;
+ JOCTET buffer;
+ Stream *str;
+ int index;
+};
+
+struct str_error_mgr {
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+ int width;
+ int height;
+};
+
+class DCTStream: public FilterStream {
+public:
+
+ DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion);
+ virtual ~DCTStream();
+ virtual StreamKind getKind() { return strDCT; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+ void init();
+
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ int colorXform;
+ JSAMPLE *current;
+ JSAMPLE *limit;
+ struct jpeg_decompress_struct cinfo;
+ struct str_error_mgr err;
+ struct str_src_mgr src;
+ JSAMPARRAY row_buffer;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/DateInfo.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/DateInfo.cc
new file mode 100644
index 00000000000..563204a1743
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/DateInfo.cc
@@ -0,0 +1,118 @@
+//========================================================================
+//
+// DateInfo.cc
+//
+// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+//========================================================================
+//
+// Based on code from pdfinfo.cc
+//
+// Copyright 1998-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <config.h>
+
+#include "DateInfo.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/* See PDF Reference 1.3, Section 3.8.2 for PDF Date representation */
+GBool parseDateString(const char *dateString, int *year, int *month, int *day, int *hour, int *minute, int *second, char *tz, int *tzHour, int *tzMinute)
+{
+ if ( dateString == NULL ) return gFalse;
+ if ( strlen(dateString) < 2 ) return gFalse;
+
+ if ( dateString[0] == 'D' && dateString[1] == ':' )
+ dateString += 2;
+
+ *month = 1;
+ *day = 1;
+ *hour = 0;
+ *minute = 0;
+ *second = 0;
+ *tz = 0x00;
+ *tzHour = 0;
+ *tzMinute = 0;
+
+ if ( sscanf( dateString,
+ "%4d%2d%2d%2d%2d%2d%c%2d%*c%2d",
+ year, month, day, hour, minute, second,
+ tz, tzHour, tzMinute ) > 0 ) {
+ /* Workaround for y2k bug in Distiller 3 stolen from gpdf, hoping that it won't
+ * be used after y2.2k */
+ if ( *year < 1930 && strlen (dateString) > 14)
+ {
+ int century, years_since_1900;
+ if ( sscanf( dateString,
+ "%2d%3d%2d%2d%2d%2d%2d",
+ &century, &years_since_1900, month, day, hour, minute, second) == 7 )
+ {
+ *year = century * 100 + years_since_1900;
+ }
+ else
+ {
+ return gFalse;
+ }
+ }
+
+ if (*year <= 0) return gFalse;
+
+ return gTrue;
+ }
+
+ return gFalse;
+}
+
+
+GooString *timeToDateString(time_t *timet) {
+ GooString *dateString;
+ char s[5];
+ struct tm *gt;
+ size_t len;
+ time_t timep = timet ? *timet : time(NULL);
+
+#ifdef HAVE_GMTIME_R
+ struct tm t;
+ gt = gmtime_r (&timep, &t);
+#else
+ gt = gmtime (&timep);
+#endif
+
+ dateString = new GooString ("D:");
+
+ /* Year YYYY */
+ len = strftime (s, sizeof(s), "%Y", gt);
+ dateString->append (s, len);
+
+ /* Month MM */
+ len = strftime (s, sizeof(s), "%m", gt);
+ dateString->append (s, len);
+
+ /* Day DD */
+ len = strftime (s, sizeof(s), "%d", gt);
+ dateString->append (s, len);
+
+ /* Hour HH */
+ len = strftime (s, sizeof(s), "%H", gt);
+ dateString->append (s, len);
+
+ /* Minute mm */
+ len = strftime (s, sizeof(s), "%M", gt);
+ dateString->append (s, len);
+
+ /* Second SS */
+ len = strftime (s, sizeof(s), "%S", gt);
+ dateString->append (s, len);
+
+ return dateString;
+}
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/DateInfo.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/DateInfo.h
new file mode 100644
index 00000000000..116350f4134
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/DateInfo.h
@@ -0,0 +1,35 @@
+//========================================================================
+//
+// DateInfo.h
+//
+// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+//========================================================================
+//
+// Based on code from pdfinfo.cc
+//
+// Copyright 1998-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef DATE_INFO_H
+#define DATE_INFO_H
+
+#include "goo/gtypes.h"
+#include "goo/GooString.h"
+#include <time.h>
+
+GBool parseDateString(const char *string, int *year, int *month, int *day, int *hour, int *minute, int *second, char *tz, int *tzHour, int *tzMinute);
+
+/* Converts the time_t into a PDF Date format string.
+ * If timet is NULL, current time is used.
+ */
+GooString *timeToDateString(time_t *timet);
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Decrypt.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Decrypt.cc
new file mode 100644
index 00000000000..ba44f959c31
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Decrypt.cc
@@ -0,0 +1,1417 @@
+//========================================================================
+//
+// Decrypt.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net>
+// Copyright (C) 2008, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Matthias Franz <matthias@ktug.or.kr>
+// Copyright (C) 2009 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "goo/gmem.h"
+#include "goo/grandom.h"
+#include "Decrypt.h"
+#include "Error.h"
+
+static void rc4InitKey(Guchar *key, int keyLen, Guchar *state);
+static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c);
+
+static GBool aesReadBlock(Stream *str, Guchar *in, GBool addPadding);
+
+static void aesKeyExpansion(DecryptAESState *s, Guchar *objKey, int objKeyLen, GBool decrypt);
+static void aesEncryptBlock(DecryptAESState *s, Guchar *in);
+static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last);
+
+static void aes256KeyExpansion(DecryptAES256State *s, Guchar *objKey, int objKeyLen, GBool decrypt);
+static void aes256EncryptBlock(DecryptAES256State *s, Guchar *in);
+static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last);
+
+static void sha256(Guchar *msg, int msgLen, Guchar *hash);
+
+static const Guchar passwordPad[32] = {
+ 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
+ 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
+ 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
+ 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
+};
+
+//------------------------------------------------------------------------
+// Decrypt
+//------------------------------------------------------------------------
+
+GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
+ GooString *ownerKey, GooString *userKey,
+ GooString *ownerEnc, GooString *userEnc,
+ int permissions, GooString *fileID,
+ GooString *ownerPassword, GooString *userPassword,
+ Guchar *fileKey, GBool encryptMetadata,
+ GBool *ownerPasswordOk) {
+ DecryptAES256State state;
+ Guchar test[127 + 56], test2[32];
+ GooString *userPassword2;
+ Guchar fState[256];
+ Guchar tmpKey[16];
+ Guchar fx, fy;
+ int len, i, j;
+
+ *ownerPasswordOk = gFalse;
+
+ if (encRevision == 5) {
+
+ // check the owner password
+ if (ownerPassword) {
+ //~ this is supposed to convert the password to UTF-8 using "SASLprep"
+ len = ownerPassword->getLength();
+ if (len > 127) {
+ len = 127;
+ }
+ memcpy(test, ownerPassword->getCString(), len);
+ memcpy(test + len, ownerKey->getCString() + 32, 8);
+ memcpy(test + len + 8, userKey->getCString(), 48);
+ sha256(test, len + 56, test);
+ if (!memcmp(test, ownerKey->getCString(), 32)) {
+
+ // compute the file key from the owner password
+ memcpy(test, ownerPassword->getCString(), len);
+ memcpy(test + len, ownerKey->getCString() + 40, 8);
+ memcpy(test + len + 8, userKey->getCString(), 48);
+ sha256(test, len + 56, test);
+ aes256KeyExpansion(&state, test, 32, gTrue);
+ for (i = 0; i < 16; ++i) {
+ state.cbc[i] = 0;
+ }
+ aes256DecryptBlock(&state, (Guchar *)ownerEnc->getCString(), gFalse);
+ memcpy(fileKey, state.buf, 16);
+ aes256DecryptBlock(&state, (Guchar *)ownerEnc->getCString() + 16,
+ gFalse);
+ memcpy(fileKey + 16, state.buf, 16);
+
+ *ownerPasswordOk = gTrue;
+ return gTrue;
+ }
+ }
+
+ // check the user password
+ if (userPassword) {
+ //~ this is supposed to convert the password to UTF-8 using "SASLprep"
+ len = userPassword->getLength();
+ if (len > 127) {
+ len = 127;
+ }
+ memcpy(test, userPassword->getCString(), len);
+ memcpy(test + len, userKey->getCString() + 32, 8);
+ sha256(test, len + 8, test);
+ if (!memcmp(test, userKey->getCString(), 32)) {
+
+ // compute the file key from the user password
+ memcpy(test, userPassword->getCString(), len);
+ memcpy(test + len, userKey->getCString() + 40, 8);
+ sha256(test, len + 8, test);
+ aes256KeyExpansion(&state, test, 32, gTrue);
+ for (i = 0; i < 16; ++i) {
+ state.cbc[i] = 0;
+ }
+ aes256DecryptBlock(&state, (Guchar *)userEnc->getCString(), gFalse);
+ memcpy(fileKey, state.buf, 16);
+ aes256DecryptBlock(&state, (Guchar *)userEnc->getCString() + 16,
+ gFalse);
+ memcpy(fileKey + 16, state.buf, 16);
+
+ return gTrue;
+ }
+ }
+
+ return gFalse;
+ } else {
+
+ // try using the supplied owner password to generate the user password
+ if (ownerPassword) {
+ len = ownerPassword->getLength();
+ if (len < 32) {
+ memcpy(test, ownerPassword->getCString(), len);
+ memcpy(test + len, passwordPad, 32 - len);
+ } else {
+ memcpy(test, ownerPassword->getCString(), 32);
+ }
+ md5(test, 32, test);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(test, keyLength, test);
+ }
+ }
+ if (encRevision == 2) {
+ rc4InitKey(test, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
+ }
+ } else {
+ memcpy(test2, ownerKey->getCString(), 32);
+ for (i = 19; i >= 0; --i) {
+ for (j = 0; j < keyLength; ++j) {
+ tmpKey[j] = test[j] ^ i;
+ }
+ rc4InitKey(tmpKey, keyLength, fState);
+ fx = fy = 0;
+ for (j = 0; j < 32; ++j) {
+ test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]);
+ }
+ }
+ }
+ userPassword2 = new GooString((char *)test2, 32);
+ if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword2, fileKey,
+ encryptMetadata)) {
+ *ownerPasswordOk = gTrue;
+ delete userPassword2;
+ return gTrue;
+ }
+ delete userPassword2;
+ }
+
+ // try using the supplied user password
+ return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword, fileKey,
+ encryptMetadata);
+ }
+}
+
+GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GooString *ownerKey, GooString *userKey,
+ int permissions, GooString *fileID,
+ GooString *userPassword, Guchar *fileKey,
+ GBool encryptMetadata) {
+ Guchar *buf;
+ Guchar test[32];
+ Guchar fState[256];
+ Guchar tmpKey[16];
+ Guchar fx, fy;
+ int len, i, j;
+ GBool ok;
+
+ // generate file key
+ buf = (Guchar *)gmalloc(72 + fileID->getLength());
+ if (userPassword) {
+ len = userPassword->getLength();
+ if (len < 32) {
+ memcpy(buf, userPassword->getCString(), len);
+ memcpy(buf + len, passwordPad, 32 - len);
+ } else {
+ memcpy(buf, userPassword->getCString(), 32);
+ }
+ } else {
+ memcpy(buf, passwordPad, 32);
+ }
+ memcpy(buf + 32, ownerKey->getCString(), 32);
+ buf[64] = permissions & 0xff;
+ buf[65] = (permissions >> 8) & 0xff;
+ buf[66] = (permissions >> 16) & 0xff;
+ buf[67] = (permissions >> 24) & 0xff;
+ memcpy(buf + 68, fileID->getCString(), fileID->getLength());
+ len = 68 + fileID->getLength();
+ if (!encryptMetadata) {
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ }
+ md5(buf, len, fileKey);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(fileKey, keyLength, fileKey);
+ }
+ }
+
+ // test user password
+ if (encRevision == 2) {
+ rc4InitKey(fileKey, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
+ }
+ ok = memcmp(test, passwordPad, 32) == 0;
+ } else if (encRevision == 3) {
+ memcpy(test, userKey->getCString(), 32);
+ for (i = 19; i >= 0; --i) {
+ for (j = 0; j < keyLength; ++j) {
+ tmpKey[j] = fileKey[j] ^ i;
+ }
+ rc4InitKey(tmpKey, keyLength, fState);
+ fx = fy = 0;
+ for (j = 0; j < 32; ++j) {
+ test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]);
+ }
+ }
+ memcpy(buf, passwordPad, 32);
+ memcpy(buf + 32, fileID->getCString(), fileID->getLength());
+ md5(buf, 32 + fileID->getLength(), buf);
+ ok = memcmp(test, buf, 16) == 0;
+ } else {
+ ok = gFalse;
+ }
+
+ gfree(buf);
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// BaseCryptStream
+//------------------------------------------------------------------------
+
+BaseCryptStream::BaseCryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen):
+ FilterStream(strA)
+{
+ int i;
+
+ algo = algoA;
+
+ // construct object key
+ for (i = 0; i < keyLength; ++i) {
+ objKey[i] = fileKey[i];
+ }
+ switch (algo) {
+ case cryptRC4:
+ objKey[keyLength] = objNum & 0xff;
+ objKey[keyLength + 1] = (objNum >> 8) & 0xff;
+ objKey[keyLength + 2] = (objNum >> 16) & 0xff;
+ objKey[keyLength + 3] = objGen & 0xff;
+ objKey[keyLength + 4] = (objGen >> 8) & 0xff;
+ md5(objKey, keyLength + 5, objKey);
+ if ((objKeyLength = keyLength + 5) > 16) {
+ objKeyLength = 16;
+ }
+ break;
+ case cryptAES:
+ objKey[keyLength] = objNum & 0xff;
+ objKey[keyLength + 1] = (objNum >> 8) & 0xff;
+ objKey[keyLength + 2] = (objNum >> 16) & 0xff;
+ objKey[keyLength + 3] = objGen & 0xff;
+ objKey[keyLength + 4] = (objGen >> 8) & 0xff;
+ objKey[keyLength + 5] = 0x73; // 's'
+ objKey[keyLength + 6] = 0x41; // 'A'
+ objKey[keyLength + 7] = 0x6c; // 'l'
+ objKey[keyLength + 8] = 0x54; // 'T'
+ md5(objKey, keyLength + 9, objKey);
+ if ((objKeyLength = keyLength + 5) > 16) {
+ objKeyLength = 16;
+ }
+ break;
+ case cryptAES256:
+ objKeyLength = keyLength;
+ break;
+ }
+
+ charactersRead = 0;
+ autoDelete = gTrue;
+}
+
+BaseCryptStream::~BaseCryptStream() {
+ if (autoDelete) {
+ delete str;
+ }
+}
+
+void BaseCryptStream::reset() {
+ charactersRead = 0;
+ nextCharBuff = EOF;
+ str->reset();
+}
+
+Goffset BaseCryptStream::getPos() {
+ return charactersRead;
+}
+
+int BaseCryptStream::getChar() {
+ // Read next character and empty the buffer, so that a new character will be read next time
+ int c = lookChar();
+ nextCharBuff = EOF;
+
+ if (c != EOF)
+ charactersRead++;
+ return c;
+}
+
+GBool BaseCryptStream::isBinary(GBool last) {
+ return str->isBinary(last);
+}
+
+void BaseCryptStream::setAutoDelete(GBool val) {
+ autoDelete = val;
+}
+
+//------------------------------------------------------------------------
+// EncryptStream
+//------------------------------------------------------------------------
+
+EncryptStream::EncryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen):
+ BaseCryptStream(strA, fileKey, algoA, keyLength, objNum, objGen)
+{
+ // Fill the CBC initialization vector for AES and AES-256
+ switch (algo) {
+ case cryptAES:
+ grandom_fill(state.aes.cbc, 16);
+ break;
+ case cryptAES256:
+ grandom_fill(state.aes256.cbc, 16);
+ break;
+ default:
+ break;
+ }
+}
+
+EncryptStream::~EncryptStream() {
+}
+
+void EncryptStream::reset() {
+ BaseCryptStream::reset();
+
+ switch (algo) {
+ case cryptRC4:
+ state.rc4.x = state.rc4.y = 0;
+ rc4InitKey(objKey, objKeyLength, state.rc4.state);
+ break;
+ case cryptAES:
+ aesKeyExpansion(&state.aes, objKey, objKeyLength, gFalse);
+ memcpy(state.aes.buf, state.aes.cbc, 16); // Copy CBC IV to buf
+ state.aes.bufIdx = 0;
+ state.aes.paddingReached = gFalse;
+ break;
+ case cryptAES256:
+ aes256KeyExpansion(&state.aes256, objKey, objKeyLength, gFalse);
+ memcpy(state.aes256.buf, state.aes256.cbc, 16); // Copy CBC IV to buf
+ state.aes256.bufIdx = 0;
+ state.aes256.paddingReached = gFalse;
+ break;
+ }
+}
+
+int EncryptStream::lookChar() {
+ Guchar in[16];
+ int c;
+
+ if (nextCharBuff != EOF)
+ return nextCharBuff;
+
+ c = EOF; // make gcc happy
+ switch (algo) {
+ case cryptRC4:
+ if ((c = str->getChar()) != EOF) {
+ // RC4 is XOR-based: the decryption algorithm works for encryption too
+ c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c);
+ }
+ break;
+ case cryptAES:
+ if (state.aes.bufIdx == 16 && !state.aes.paddingReached) {
+ state.aes.paddingReached = !aesReadBlock(str, in, gTrue);
+ aesEncryptBlock(&state.aes, in);
+ }
+ if (state.aes.bufIdx == 16) {
+ c = EOF;
+ } else {
+ c = state.aes.buf[state.aes.bufIdx++];
+ }
+ break;
+ case cryptAES256:
+ if (state.aes256.bufIdx == 16 && !state.aes256.paddingReached) {
+ state.aes256.paddingReached = !aesReadBlock(str, in, gTrue);
+ aes256EncryptBlock(&state.aes256, in);
+ }
+ if (state.aes256.bufIdx == 16) {
+ c = EOF;
+ } else {
+ c = state.aes256.buf[state.aes256.bufIdx++];
+ }
+ break;
+ }
+ return (nextCharBuff = c);
+}
+
+//------------------------------------------------------------------------
+// DecryptStream
+//------------------------------------------------------------------------
+
+DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen):
+ BaseCryptStream(strA, fileKey, algoA, keyLength, objNum, objGen)
+{
+}
+
+DecryptStream::~DecryptStream() {
+}
+
+void DecryptStream::reset() {
+ int i;
+ BaseCryptStream::reset();
+
+ switch (algo) {
+ case cryptRC4:
+ state.rc4.x = state.rc4.y = 0;
+ rc4InitKey(objKey, objKeyLength, state.rc4.state);
+ break;
+ case cryptAES:
+ aesKeyExpansion(&state.aes, objKey, objKeyLength, gTrue);
+ for (i = 0; i < 16; ++i) {
+ state.aes.cbc[i] = str->getChar();
+ }
+ state.aes.bufIdx = 16;
+ break;
+ case cryptAES256:
+ aes256KeyExpansion(&state.aes256, objKey, objKeyLength, gTrue);
+ for (i = 0; i < 16; ++i) {
+ state.aes256.cbc[i] = str->getChar();
+ }
+ state.aes256.bufIdx = 16;
+ break;
+ }
+}
+
+int DecryptStream::lookChar() {
+ Guchar in[16];
+ int c;
+
+ if (nextCharBuff != EOF)
+ return nextCharBuff;
+
+ c = EOF; // make gcc happy
+ switch (algo) {
+ case cryptRC4:
+ if ((c = str->getChar()) != EOF) {
+ c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c);
+ }
+ break;
+ case cryptAES:
+ if (state.aes.bufIdx == 16) {
+ if (aesReadBlock(str, in, gFalse)) {
+ aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
+ }
+ }
+ if (state.aes.bufIdx == 16) {
+ c = EOF;
+ } else {
+ c = state.aes.buf[state.aes.bufIdx++];
+ }
+ break;
+ case cryptAES256:
+ if (state.aes256.bufIdx == 16) {
+ if (aesReadBlock(str, in, gFalse)) {
+ aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF);
+ }
+ }
+ if (state.aes256.bufIdx == 16) {
+ c = EOF;
+ } else {
+ c = state.aes256.buf[state.aes256.bufIdx++];
+ }
+ break;
+ }
+ return (nextCharBuff = c);
+}
+
+//------------------------------------------------------------------------
+// RC4-compatible decryption
+//------------------------------------------------------------------------
+
+static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) {
+ Guchar index1, index2;
+ Guchar t;
+ int i;
+
+ for (i = 0; i < 256; ++i)
+ state[i] = i;
+
+ if (unlikely(keyLen == 0))
+ return;
+
+ index1 = index2 = 0;
+ for (i = 0; i < 256; ++i) {
+ index2 = (key[index1] + state[i] + index2) % 256;
+ t = state[i];
+ state[i] = state[index2];
+ state[index2] = t;
+ index1 = (index1 + 1) % keyLen;
+ }
+}
+
+static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) {
+ Guchar x1, y1, tx, ty;
+
+ x1 = *x = (*x + 1) % 256;
+ y1 = *y = (state[*x] + *y) % 256;
+ tx = state[x1];
+ ty = state[y1];
+ state[x1] = ty;
+ state[y1] = tx;
+ return c ^ state[(tx + ty) % 256];
+}
+
+//------------------------------------------------------------------------
+// AES decryption
+//------------------------------------------------------------------------
+
+// Returns gFalse if EOF was reached, gTrue otherwise
+static GBool aesReadBlock(Stream *str, Guchar *in, GBool addPadding)
+{
+ int c, i;
+
+ for (i = 0; i < 16; ++i) {
+ if ((c = str->getChar()) != EOF) {
+ in[i] = (Guchar)c;
+ } else {
+ break;
+ }
+ }
+
+ if (i == 16) {
+ return gTrue;
+ } else {
+ if (addPadding) {
+ c = 16 - i;
+ while (i < 16) {
+ in[i++] = (Guchar)c;
+ }
+ }
+ return gFalse;
+ }
+}
+
+static const 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 const 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 const 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 subBytes(Guchar *state) {
+ int i;
+
+ for (i = 0; i < 16; ++i) {
+ state[i] = sbox[state[i]];
+ }
+}
+
+static inline void invSubBytes(Guchar *state) {
+ int i;
+
+ for (i = 0; i < 16; ++i) {
+ state[i] = invSbox[state[i]];
+ }
+}
+
+static inline void shiftRows(Guchar *state) {
+ Guchar t;
+
+ t = state[4];
+ state[4] = state[5];
+ state[5] = state[6];
+ state[6] = state[7];
+ state[7] = t;
+
+ t = state[8];
+ state[8] = state[10];
+ state[10] = t;
+ t = state[9];
+ state[9] = state[11];
+ state[11] = t;
+
+ t = state[15];
+ state[15] = state[14];
+ state[14] = state[13];
+ state[13] = state[12];
+ state[12] = t;
+}
+
+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;
+}
+
+// {02} \cdot s
+static inline Guchar mul02(Guchar s) {
+ return (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+}
+
+// {03} \cdot s
+static inline Guchar mul03(Guchar s) {
+ Guchar s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+ return s ^ s2;
+}
+
+// {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 mixColumns(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] = mul02(s0) ^ mul03(s1) ^ s2 ^ s3;
+ state[4+c] = s0 ^ mul02(s1) ^ mul03(s2) ^ s3;
+ state[8+c] = s0 ^ s1 ^ mul02(s2) ^ mul03(s3);
+ state[12+c] = mul03(s0) ^ s1 ^ s2 ^ mul02(s3);
+ }
+}
+
+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*/, GBool decrypt) {
+ 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;
+ }
+
+ /* In case of decryption, adjust the key schedule for the equivalent inverse cipher */
+ if (decrypt) {
+ for (round = 1; round <= 9; ++round) {
+ invMixColumnsW(&s->w[round * 4]);
+ }
+ }
+}
+
+static void aesEncryptBlock(DecryptAESState *s, Guchar *in) {
+ int c, round;
+
+ // initial state (input is xor'd with previous output because of CBC)
+ for (c = 0; c < 4; ++c) {
+ s->state[c] = in[4*c] ^ s->buf[4*c];
+ s->state[4+c] = in[4*c+1] ^ s->buf[4*c+1];
+ s->state[8+c] = in[4*c+2] ^ s->buf[4*c+2];
+ s->state[12+c] = in[4*c+3] ^ s->buf[4*c+3];
+ }
+
+ // round 0
+ addRoundKey(s->state, &s->w[0]);
+
+ // rounds 1-9
+ for (round = 1; round <= 9; ++round) {
+ subBytes(s->state);
+ shiftRows(s->state);
+ mixColumns(s->state);
+ addRoundKey(s->state, &s->w[round * 4]);
+ }
+
+ // round 10
+ subBytes(s->state);
+ shiftRows(s->state);
+ addRoundKey(s->state, &s->w[10 * 4]);
+
+ for (c = 0; c < 4; ++c) {
+ s->buf[4*c] = s->state[c];
+ s->buf[4*c+1] = s->state[4+c];
+ s->buf[4*c+2] = s->state[8+c];
+ s->buf[4*c+3] = s->state[12+c];
+ }
+
+ s->bufIdx = 0;
+}
+
+static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) {
+ int c, round, n, i;
+
+ // initial state
+ for (c = 0; c < 4; ++c) {
+ s->state[c] = in[4*c];
+ s->state[4+c] = in[4*c+1];
+ s->state[8+c] = in[4*c+2];
+ s->state[12+c] = in[4*c+3];
+ }
+
+ // round 0
+ addRoundKey(s->state, &s->w[10 * 4]);
+
+ // rounds 1-9
+ for (round = 9; round >= 1; --round) {
+ invSubBytes(s->state);
+ invShiftRows(s->state);
+ invMixColumns(s->state);
+ addRoundKey(s->state, &s->w[round * 4]);
+ }
+
+ // round 10
+ invSubBytes(s->state);
+ invShiftRows(s->state);
+ addRoundKey(s->state, &s->w[0]);
+
+ // CBC
+ for (c = 0; c < 4; ++c) {
+ s->buf[4*c] = s->state[c] ^ s->cbc[4*c];
+ s->buf[4*c+1] = s->state[4+c] ^ s->cbc[4*c+1];
+ s->buf[4*c+2] = s->state[8+c] ^ s->cbc[4*c+2];
+ s->buf[4*c+3] = s->state[12+c] ^ s->cbc[4*c+3];
+ }
+
+ // save the input block for the next CBC
+ for (i = 0; i < 16; ++i) {
+ s->cbc[i] = in[i];
+ }
+
+ // remove padding
+ s->bufIdx = 0;
+ if (last) {
+ n = s->buf[15];
+ if (n < 1 || n > 16) { // this should never happen
+ n = 16;
+ }
+ for (i = 15; i >= n; --i) {
+ s->buf[i] = s->buf[i-n];
+ }
+ s->bufIdx = n;
+ }
+}
+
+//------------------------------------------------------------------------
+// AES-256 decryption
+//------------------------------------------------------------------------
+
+static void aes256KeyExpansion(DecryptAES256State *s,
+ Guchar *objKey, int objKeyLen, GBool decrypt) {
+ Guint temp;
+ int i, round;
+
+ //~ this assumes objKeyLen == 32
+
+ for (i = 0; i < 8; ++i) {
+ s->w[i] = (objKey[4*i] << 24) + (objKey[4*i+1] << 16) +
+ (objKey[4*i+2] << 8) + objKey[4*i+3];
+ }
+ for (i = 8; i < 60; ++i) {
+ temp = s->w[i-1];
+ if ((i & 7) == 0) {
+ temp = subWord(rotWord(temp)) ^ rcon[i/8];
+ } else if ((i & 7) == 4) {
+ temp = subWord(temp);
+ }
+ s->w[i] = s->w[i-8] ^ temp;
+ }
+
+ /* In case of decryption, adjust the key schedule for the equivalent inverse cipher */
+ if (decrypt) {
+ for (round = 1; round <= 13; ++round) {
+ invMixColumnsW(&s->w[round * 4]);
+ }
+ }
+}
+
+static void aes256EncryptBlock(DecryptAES256State *s, Guchar *in) {
+ int c, round;
+
+ // initial state (input is xor'd with previous output because of CBC)
+ for (c = 0; c < 4; ++c) {
+ s->state[c] = in[4*c] ^ s->buf[4*c];
+ s->state[4+c] = in[4*c+1] ^ s->buf[4*c+1];
+ s->state[8+c] = in[4*c+2] ^ s->buf[4*c+2];
+ s->state[12+c] = in[4*c+3] ^ s->buf[4*c+3];
+ }
+
+ // round 0
+ addRoundKey(s->state, &s->w[0]);
+
+ // rounds 1-13
+ for (round = 1; round <= 13; ++round) {
+ subBytes(s->state);
+ shiftRows(s->state);
+ mixColumns(s->state);
+ addRoundKey(s->state, &s->w[round * 4]);
+ }
+
+ // round 14
+ subBytes(s->state);
+ shiftRows(s->state);
+ addRoundKey(s->state, &s->w[14 * 4]);
+
+ for (c = 0; c < 4; ++c) {
+ s->buf[4*c] = s->state[c];
+ s->buf[4*c+1] = s->state[4+c];
+ s->buf[4*c+2] = s->state[8+c];
+ s->buf[4*c+3] = s->state[12+c];
+ }
+
+ s->bufIdx = 0;
+}
+
+static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last) {
+ int c, round, n, i;
+
+ // initial state
+ for (c = 0; c < 4; ++c) {
+ s->state[c] = in[4*c];
+ s->state[4+c] = in[4*c+1];
+ s->state[8+c] = in[4*c+2];
+ s->state[12+c] = in[4*c+3];
+ }
+
+ // round 0
+ addRoundKey(s->state, &s->w[14 * 4]);
+
+ // rounds 13-1
+ for (round = 13; round >= 1; --round) {
+ invSubBytes(s->state);
+ invShiftRows(s->state);
+ invMixColumns(s->state);
+ addRoundKey(s->state, &s->w[round * 4]);
+ }
+
+ // round 14
+ invSubBytes(s->state);
+ invShiftRows(s->state);
+ addRoundKey(s->state, &s->w[0]);
+
+ // CBC
+ for (c = 0; c < 4; ++c) {
+ s->buf[4*c] = s->state[c] ^ s->cbc[4*c];
+ s->buf[4*c+1] = s->state[4+c] ^ s->cbc[4*c+1];
+ s->buf[4*c+2] = s->state[8+c] ^ s->cbc[4*c+2];
+ s->buf[4*c+3] = s->state[12+c] ^ s->cbc[4*c+3];
+ }
+
+ // save the input block for the next CBC
+ for (i = 0; i < 16; ++i) {
+ s->cbc[i] = in[i];
+ }
+
+ // remove padding
+ s->bufIdx = 0;
+ if (last) {
+ n = s->buf[15];
+ if (n < 1 || n > 16) { // this should never happen
+ n = 16;
+ }
+ for (i = 15; i >= n; --i) {
+ s->buf[i] = s->buf[i-n];
+ }
+ s->bufIdx = n;
+ if (n > 16)
+ {
+ error(errSyntaxError, -1, "Reducing bufIdx from {0:d} to 16 to not crash", n);
+ s->bufIdx = 16;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// MD5 message digest
+//------------------------------------------------------------------------
+
+// this works around a bug in older Sun compilers
+static inline Gulong rotateLeft(Gulong x, int r) {
+ x &= 0xffffffff;
+ return ((x << r) | (x >> (32 - r))) & 0xffffffff;
+}
+
+static inline Gulong md5Round1(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round2(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round3(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + (b ^ c ^ d) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round4(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s);
+}
+
+void md5(Guchar *msg, int msgLen, Guchar *digest) {
+ Gulong x[16];
+ Gulong a, b, c, d, aa, bb, cc, dd;
+ int n64;
+ int i, j, k;
+
+ // sanity check
+ if (msgLen < 0) {
+ return;
+ }
+
+ // compute number of 64-byte blocks
+ // (length + pad byte (0x80) + 8 bytes for length)
+ n64 = (msgLen + 1 + 8 + 63) / 64;
+
+ // initialize a, b, c, d
+ a = 0x67452301;
+ b = 0xefcdab89;
+ c = 0x98badcfe;
+ d = 0x10325476;
+
+ // loop through blocks
+ k = 0;
+ for (i = 0; i < n64; ++i) {
+
+ // grab a 64-byte block
+ for (j = 0; j < 16 && k < msgLen - 3; ++j, k += 4)
+ x[j] = (((((msg[k+3] << 8) + msg[k+2]) << 8) + msg[k+1]) << 8) + msg[k];
+ if (i == n64 - 1) {
+ if (k == msgLen - 3)
+ x[j] = 0x80000000 + (((msg[k+2] << 8) + msg[k+1]) << 8) + msg[k];
+ else if (k == msgLen - 2)
+ x[j] = 0x800000 + (msg[k+1] << 8) + msg[k];
+ else if (k == msgLen - 1)
+ x[j] = 0x8000 + msg[k];
+ else
+ x[j] = 0x80;
+ ++j;
+ while (j < 16)
+ x[j++] = 0;
+ x[14] = msgLen << 3;
+ }
+
+ // save a, b, c, d
+ aa = a;
+ bb = b;
+ cc = c;
+ dd = d;
+
+ // round 1
+ a = md5Round1(a, b, c, d, x[0], 7, 0xd76aa478);
+ d = md5Round1(d, a, b, c, x[1], 12, 0xe8c7b756);
+ c = md5Round1(c, d, a, b, x[2], 17, 0x242070db);
+ b = md5Round1(b, c, d, a, x[3], 22, 0xc1bdceee);
+ a = md5Round1(a, b, c, d, x[4], 7, 0xf57c0faf);
+ d = md5Round1(d, a, b, c, x[5], 12, 0x4787c62a);
+ c = md5Round1(c, d, a, b, x[6], 17, 0xa8304613);
+ b = md5Round1(b, c, d, a, x[7], 22, 0xfd469501);
+ a = md5Round1(a, b, c, d, x[8], 7, 0x698098d8);
+ d = md5Round1(d, a, b, c, x[9], 12, 0x8b44f7af);
+ c = md5Round1(c, d, a, b, x[10], 17, 0xffff5bb1);
+ b = md5Round1(b, c, d, a, x[11], 22, 0x895cd7be);
+ a = md5Round1(a, b, c, d, x[12], 7, 0x6b901122);
+ d = md5Round1(d, a, b, c, x[13], 12, 0xfd987193);
+ c = md5Round1(c, d, a, b, x[14], 17, 0xa679438e);
+ b = md5Round1(b, c, d, a, x[15], 22, 0x49b40821);
+
+ // round 2
+ a = md5Round2(a, b, c, d, x[1], 5, 0xf61e2562);
+ d = md5Round2(d, a, b, c, x[6], 9, 0xc040b340);
+ c = md5Round2(c, d, a, b, x[11], 14, 0x265e5a51);
+ b = md5Round2(b, c, d, a, x[0], 20, 0xe9b6c7aa);
+ a = md5Round2(a, b, c, d, x[5], 5, 0xd62f105d);
+ d = md5Round2(d, a, b, c, x[10], 9, 0x02441453);
+ c = md5Round2(c, d, a, b, x[15], 14, 0xd8a1e681);
+ b = md5Round2(b, c, d, a, x[4], 20, 0xe7d3fbc8);
+ a = md5Round2(a, b, c, d, x[9], 5, 0x21e1cde6);
+ d = md5Round2(d, a, b, c, x[14], 9, 0xc33707d6);
+ c = md5Round2(c, d, a, b, x[3], 14, 0xf4d50d87);
+ b = md5Round2(b, c, d, a, x[8], 20, 0x455a14ed);
+ a = md5Round2(a, b, c, d, x[13], 5, 0xa9e3e905);
+ d = md5Round2(d, a, b, c, x[2], 9, 0xfcefa3f8);
+ c = md5Round2(c, d, a, b, x[7], 14, 0x676f02d9);
+ b = md5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a);
+
+ // round 3
+ a = md5Round3(a, b, c, d, x[5], 4, 0xfffa3942);
+ d = md5Round3(d, a, b, c, x[8], 11, 0x8771f681);
+ c = md5Round3(c, d, a, b, x[11], 16, 0x6d9d6122);
+ b = md5Round3(b, c, d, a, x[14], 23, 0xfde5380c);
+ a = md5Round3(a, b, c, d, x[1], 4, 0xa4beea44);
+ d = md5Round3(d, a, b, c, x[4], 11, 0x4bdecfa9);
+ c = md5Round3(c, d, a, b, x[7], 16, 0xf6bb4b60);
+ b = md5Round3(b, c, d, a, x[10], 23, 0xbebfbc70);
+ a = md5Round3(a, b, c, d, x[13], 4, 0x289b7ec6);
+ d = md5Round3(d, a, b, c, x[0], 11, 0xeaa127fa);
+ c = md5Round3(c, d, a, b, x[3], 16, 0xd4ef3085);
+ b = md5Round3(b, c, d, a, x[6], 23, 0x04881d05);
+ a = md5Round3(a, b, c, d, x[9], 4, 0xd9d4d039);
+ d = md5Round3(d, a, b, c, x[12], 11, 0xe6db99e5);
+ c = md5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8);
+ b = md5Round3(b, c, d, a, x[2], 23, 0xc4ac5665);
+
+ // round 4
+ a = md5Round4(a, b, c, d, x[0], 6, 0xf4292244);
+ d = md5Round4(d, a, b, c, x[7], 10, 0x432aff97);
+ c = md5Round4(c, d, a, b, x[14], 15, 0xab9423a7);
+ b = md5Round4(b, c, d, a, x[5], 21, 0xfc93a039);
+ a = md5Round4(a, b, c, d, x[12], 6, 0x655b59c3);
+ d = md5Round4(d, a, b, c, x[3], 10, 0x8f0ccc92);
+ c = md5Round4(c, d, a, b, x[10], 15, 0xffeff47d);
+ b = md5Round4(b, c, d, a, x[1], 21, 0x85845dd1);
+ a = md5Round4(a, b, c, d, x[8], 6, 0x6fa87e4f);
+ d = md5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0);
+ c = md5Round4(c, d, a, b, x[6], 15, 0xa3014314);
+ b = md5Round4(b, c, d, a, x[13], 21, 0x4e0811a1);
+ a = md5Round4(a, b, c, d, x[4], 6, 0xf7537e82);
+ d = md5Round4(d, a, b, c, x[11], 10, 0xbd3af235);
+ c = md5Round4(c, d, a, b, x[2], 15, 0x2ad7d2bb);
+ b = md5Round4(b, c, d, a, x[9], 21, 0xeb86d391);
+
+ // increment a, b, c, d
+ a += aa;
+ b += bb;
+ c += cc;
+ d += dd;
+ }
+
+ // break digest into bytes
+ digest[0] = (Guchar)(a & 0xff);
+ digest[1] = (Guchar)((a >>= 8) & 0xff);
+ digest[2] = (Guchar)((a >>= 8) & 0xff);
+ digest[3] = (Guchar)((a >>= 8) & 0xff);
+ digest[4] = (Guchar)(b & 0xff);
+ digest[5] = (Guchar)((b >>= 8) & 0xff);
+ digest[6] = (Guchar)((b >>= 8) & 0xff);
+ digest[7] = (Guchar)((b >>= 8) & 0xff);
+ digest[8] = (Guchar)(c & 0xff);
+ digest[9] = (Guchar)((c >>= 8) & 0xff);
+ digest[10] = (Guchar)((c >>= 8) & 0xff);
+ digest[11] = (Guchar)((c >>= 8) & 0xff);
+ digest[12] = (Guchar)(d & 0xff);
+ digest[13] = (Guchar)((d >>= 8) & 0xff);
+ digest[14] = (Guchar)((d >>= 8) & 0xff);
+ digest[15] = (Guchar)((d >>= 8) & 0xff);
+}
+
+//------------------------------------------------------------------------
+// SHA-256 hash
+//------------------------------------------------------------------------
+
+static Guint sha256K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+static inline Guint rotr(Guint x, Guint n) {
+ return (x >> n) | (x << (32 - n));
+}
+
+static inline Guint sha256Ch(Guint x, Guint y, Guint z) {
+ return (x & y) ^ (~x & z);
+}
+
+static inline Guint sha256Maj(Guint x, Guint y, Guint z) {
+ return (x & y) ^ (x & z) ^ (y & z);
+}
+
+static inline Guint sha256Sigma0(Guint x) {
+ return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
+}
+
+static inline Guint sha256Sigma1(Guint x) {
+ return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
+}
+
+static inline Guint sha256sigma0(Guint x) {
+ return rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3);
+}
+
+static inline Guint sha256sigma1(Guint x) {
+ return rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10);
+}
+
+void sha256HashBlock(Guchar *blk, Guint *H) {
+ Guint W[64];
+ Guint a, b, c, d, e, f, g, h;
+ Guint T1, T2;
+ Guint t;
+
+ // 1. prepare the message schedule
+ for (t = 0; t < 16; ++t) {
+ W[t] = (blk[t*4] << 24) |
+ (blk[t*4 + 1] << 16) |
+ (blk[t*4 + 2] << 8) |
+ blk[t*4 + 3];
+ }
+ for (t = 16; t < 64; ++t) {
+ W[t] = sha256sigma1(W[t-2]) + W[t-7] + sha256sigma0(W[t-15]) + W[t-16];
+ }
+
+ // 2. initialize the eight working variables
+ a = H[0];
+ b = H[1];
+ c = H[2];
+ d = H[3];
+ e = H[4];
+ f = H[5];
+ g = H[6];
+ h = H[7];
+
+ // 3.
+ for (t = 0; t < 64; ++t) {
+ T1 = h + sha256Sigma1(e) + sha256Ch(e,f,g) + sha256K[t] + W[t];
+ T2 = sha256Sigma0(a) + sha256Maj(a,b,c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+
+ // 4. compute the intermediate hash value
+ H[0] += a;
+ H[1] += b;
+ H[2] += c;
+ H[3] += d;
+ H[4] += e;
+ H[5] += f;
+ H[6] += g;
+ H[7] += h;
+}
+
+static void sha256(Guchar *msg, int msgLen, Guchar *hash) {
+ Guchar blk[64];
+ Guint H[8];
+ int blkLen, i;
+
+ H[0] = 0x6a09e667;
+ H[1] = 0xbb67ae85;
+ H[2] = 0x3c6ef372;
+ H[3] = 0xa54ff53a;
+ H[4] = 0x510e527f;
+ H[5] = 0x9b05688c;
+ H[6] = 0x1f83d9ab;
+ H[7] = 0x5be0cd19;
+
+ blkLen = 0;
+ for (i = 0; i + 64 <= msgLen; i += 64) {
+ sha256HashBlock(msg + i, H);
+ }
+ blkLen = msgLen - i;
+ if (blkLen > 0) {
+ memcpy(blk, msg + i, blkLen);
+ }
+
+ // pad the message
+ blk[blkLen++] = 0x80;
+ if (blkLen > 56) {
+ while (blkLen < 64) {
+ blk[blkLen++] = 0;
+ }
+ sha256HashBlock(blk, H);
+ blkLen = 0;
+ }
+ while (blkLen < 56) {
+ blk[blkLen++] = 0;
+ }
+ blk[56] = 0;
+ blk[57] = 0;
+ blk[58] = 0;
+ blk[59] = 0;
+ blk[60] = (Guchar)(msgLen >> 21);
+ blk[61] = (Guchar)(msgLen >> 13);
+ blk[62] = (Guchar)(msgLen >> 5);
+ blk[63] = (Guchar)(msgLen << 3);
+ sha256HashBlock(blk, H);
+
+ // copy the output into the buffer (convert words to bytes)
+ for (i = 0; i < 8; ++i) {
+ hash[i*4] = (Guchar)(H[i] >> 24);
+ hash[i*4 + 1] = (Guchar)(H[i] >> 16);
+ hash[i*4 + 2] = (Guchar)(H[i] >> 8);
+ hash[i*4 + 3] = (Guchar)H[i];
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Decrypt.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Decrypt.h
new file mode 100644
index 00000000000..10a6386c6b5
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Decrypt.h
@@ -0,0 +1,161 @@
+//========================================================================
+//
+// Decrypt.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net>
+// Copyright (C) 2009 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef DECRYPT_H
+#define DECRYPT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "goo/GooString.h"
+#include "Object.h"
+#include "Stream.h"
+
+//------------------------------------------------------------------------
+// Decrypt
+//------------------------------------------------------------------------
+
+class Decrypt {
+public:
+
+ // 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
+ // the owner password was correct. Either or both of the passwords
+ // may be NULL, which is treated as an empty string.
+ static GBool makeFileKey(int encVersion, int encRevision, int keyLength,
+ GooString *ownerKey, GooString *userKey,
+ GooString *ownerEnc, GooString *userEnc,
+ int permissions, GooString *fileID,
+ GooString *ownerPassword, GooString *userPassword,
+ Guchar *fileKey, GBool encryptMetadata,
+ GBool *ownerPasswordOk);
+
+private:
+
+ static GBool makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GooString *ownerKey, GooString *userKey,
+ int permissions, GooString *fileID,
+ GooString *userPassword, Guchar *fileKey,
+ GBool encryptMetadata);
+};
+
+//------------------------------------------------------------------------
+// Helper classes
+//------------------------------------------------------------------------
+
+/* DecryptRC4State, DecryptAESState, DecryptAES256State are named like this for
+ * historical reasons, but they're used for encryption too.
+ * In case of decryption, the cbc field in AES and AES-256 contains the previous
+ * input block or the CBC initialization vector (IV) if the stream has just been
+ * reset). In case of encryption, it always contains the IV, whereas the
+ * previous output is kept in buf. The paddingReached field is only used in
+ * case of encryption. */
+struct DecryptRC4State {
+ Guchar state[256];
+ Guchar x, y;
+};
+
+struct DecryptAESState {
+ Guint w[44];
+ Guchar state[16];
+ Guchar cbc[16];
+ Guchar buf[16];
+ GBool paddingReached; // encryption only
+ int bufIdx;
+};
+
+struct DecryptAES256State {
+ Guint w[60];
+ Guchar state[16];
+ Guchar cbc[16];
+ Guchar buf[16];
+ GBool paddingReached; // encryption only
+ int bufIdx;
+};
+
+class BaseCryptStream : public FilterStream {
+public:
+
+ BaseCryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen);
+ virtual ~BaseCryptStream();
+ virtual StreamKind getKind() { return strCrypt; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar() = 0;
+ virtual Goffset getPos();
+ virtual GBool isBinary(GBool last);
+ virtual Stream *getUndecodedStream() { return this; }
+ void setAutoDelete(GBool val);
+
+protected:
+ CryptAlgorithm algo;
+ int objKeyLength;
+ Guchar objKey[32];
+ Goffset charactersRead; // so that getPos() can be correct
+ int nextCharBuff; // EOF means not read yet
+ GBool autoDelete;
+
+ union {
+ DecryptRC4State rc4;
+ DecryptAESState aes;
+ DecryptAES256State aes256;
+ } state;
+};
+
+//------------------------------------------------------------------------
+// EncryptStream / DecryptStream
+//------------------------------------------------------------------------
+
+class EncryptStream : public BaseCryptStream {
+public:
+
+ EncryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen);
+ ~EncryptStream();
+ virtual void reset();
+ virtual int lookChar();
+};
+
+class DecryptStream : public BaseCryptStream {
+public:
+
+ DecryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen);
+ ~DecryptStream();
+ virtual void reset();
+ virtual int lookChar();
+};
+
+//------------------------------------------------------------------------
+
+extern void md5(Guchar *msg, int msgLen, Guchar *digest);
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Dict.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Dict.cc
new file mode 100644
index 00000000000..c2a94f4a1fa
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Dict.cc
@@ -0,0 +1,300 @@
+//========================================================================
+//
+// Dict.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2008, 2010, 2013, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2014 Scott West <scott.gregory.west@gmail.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <algorithm>
+#include <stddef.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "Object.h"
+#include "XRef.h"
+#include "Dict.h"
+
+#if MULTITHREADED
+# define dictLocker() MutexLocker locker(&mutex)
+#else
+# define dictLocker()
+#endif
+//------------------------------------------------------------------------
+// Dict
+//------------------------------------------------------------------------
+
+static const int SORT_LENGTH_LOWER_LIMIT = 32;
+
+static inline bool cmpDictEntries(const DictEntry &e1, const DictEntry &e2)
+{
+ return strcmp(e1.key, e2.key) < 0;
+}
+
+static int binarySearch(const char *key, DictEntry *entries, int length)
+{
+ int first = 0;
+ int end = length - 1;
+ while (first <= end) {
+ const int middle = (first + end) / 2;
+ const int res = strcmp(key, entries[middle].key);
+ if (res == 0) {
+ return middle;
+ } else if (res < 0) {
+ end = middle - 1;
+ } else {
+ first = middle + 1;
+ }
+ }
+ return -1;
+}
+
+Dict::Dict(XRef *xrefA) {
+ xref = xrefA;
+ entries = NULL;
+ size = length = 0;
+ ref = 1;
+ sorted = gFalse;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+Dict::Dict(Dict* dictA) {
+ xref = dictA->xref;
+ size = length = dictA->length;
+ ref = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+
+ sorted = dictA->sorted;
+ entries = (DictEntry *)gmallocn(size, sizeof(DictEntry));
+ for (int i=0; i<length; i++) {
+ entries[i].key = copyString(dictA->entries[i].key);
+ dictA->entries[i].val.copy(&entries[i].val);
+ }
+}
+
+Dict *Dict::copy(XRef *xrefA) {
+ dictLocker();
+ Dict *dictA = new Dict(this);
+ dictA->xref = xrefA;
+ for (int i=0; i<length; i++) {
+ if (dictA->entries[i].val.getType() == objDict) {
+ Dict *dict = dictA->entries[i].val.getDict();
+ Object obj;
+ obj.initDict(dict->copy(xrefA));
+ dictA->entries[i].val.free();
+ dictA->entries[i].val = obj;
+ obj.free();
+ }
+ }
+ return dictA;
+}
+
+Dict::~Dict() {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ gfree(entries[i].key);
+ entries[i].val.free();
+ }
+ gfree(entries);
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+int Dict::incRef() {
+ dictLocker();
+ ++ref;
+ return ref;
+}
+
+int Dict::decRef() {
+ dictLocker();
+ --ref;
+ return ref;
+}
+
+void Dict::add(char *key, Object *val) {
+ dictLocker();
+ if (sorted) {
+ // We use add on very few occasions so
+ // virtually this will never be hit
+ sorted = gFalse;
+ }
+
+ if (length == size) {
+ if (length == 0) {
+ size = 8;
+ } else {
+ size *= 2;
+ }
+ entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry));
+ }
+ entries[length].key = key;
+ entries[length].val = *val;
+ ++length;
+}
+
+inline DictEntry *Dict::find(const char *key) {
+ if (!sorted && length >= SORT_LENGTH_LOWER_LIMIT)
+ {
+ dictLocker();
+ sorted = gTrue;
+ std::sort(entries, entries+length, cmpDictEntries);
+ }
+
+ if (sorted) {
+ const int pos = binarySearch(key, entries, length);
+ if (pos != -1) {
+ return &entries[pos];
+ }
+ } else {
+ int i;
+
+ for (i = length - 1; i >=0; --i) {
+ if (!strcmp(key, entries[i].key))
+ return &entries[i];
+ }
+ }
+ return NULL;
+}
+
+GBool Dict::hasKey(const char *key) {
+ return find(key) != NULL;
+}
+
+void Dict::remove(const char *key) {
+ dictLocker();
+ if (sorted) {
+ const int pos = binarySearch(key, entries, length);
+ if (pos != -1) {
+ length -= 1;
+ gfree(entries[pos].key);
+ entries[pos].val.free();
+ if (pos != length) {
+ memmove(&entries[pos], &entries[pos + 1], (length - pos) * sizeof(DictEntry));
+ }
+ }
+ } else {
+ int i;
+ bool found = false;
+ DictEntry tmp;
+ if(length == 0) {
+ return;
+ }
+
+ for(i=0; i<length; i++) {
+ if (!strcmp(key, entries[i].key)) {
+ found = true;
+ break;
+ }
+ }
+ if(!found) {
+ return;
+ }
+ //replace the deleted entry with the last entry
+ gfree(entries[i].key);
+ entries[i].val.free();
+ length -= 1;
+ tmp = entries[length];
+ if (i!=length) //don't copy the last entry if it is deleted
+ entries[i] = tmp;
+ }
+}
+
+void Dict::set(const char *key, Object *val) {
+ DictEntry *e;
+ if (val->isNull()) {
+ remove(key);
+ return;
+ }
+ e = find (key);
+ if (e) {
+ dictLocker();
+ e->val.free();
+ e->val = *val;
+ } else {
+ add (copyString(key), val);
+ }
+}
+
+
+GBool Dict::is(const char *type) {
+ DictEntry *e;
+
+ return (e = find("Type")) && e->val.isName(type);
+}
+
+Object *Dict::lookup(const char *key, Object *obj, int recursion) {
+ DictEntry *e;
+
+ return (e = find(key)) ? e->val.fetch(xref, obj, recursion) : obj->initNull();
+}
+
+Object *Dict::lookupNF(const char *key, Object *obj) {
+ DictEntry *e;
+
+ return (e = find(key)) ? e->val.copy(obj) : obj->initNull();
+}
+
+GBool Dict::lookupInt(const char *key, const char *alt_key, int *value)
+{
+ Object obj1;
+ GBool success = gFalse;
+
+ lookup ((char *) key, &obj1);
+ if (obj1.isNull () && alt_key != NULL) {
+ obj1.free ();
+ lookup ((char *) alt_key, &obj1);
+ }
+ if (obj1.isInt ()) {
+ *value = obj1.getInt ();
+ success = gTrue;
+ }
+
+ obj1.free ();
+
+ return success;
+}
+
+char *Dict::getKey(int i) {
+ return entries[i].key;
+}
+
+Object *Dict::getVal(int i, Object *obj) {
+ return entries[i].val.fetch(xref, obj);
+}
+
+Object *Dict::getValNF(int i, Object *obj) {
+ return entries[i].val.copy(obj);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Dict.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Dict.h
new file mode 100644
index 00000000000..fba99edc513
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Dict.h
@@ -0,0 +1,112 @@
+//========================================================================
+//
+// Dict.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef DICT_H
+#define DICT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "Object.h"
+#include "goo/GooMutex.h"
+
+//------------------------------------------------------------------------
+// Dict
+//------------------------------------------------------------------------
+
+struct DictEntry {
+ char *key;
+ Object val;
+};
+
+class Dict {
+public:
+
+ // Constructor.
+ Dict(XRef *xrefA);
+ Dict(Dict* dictA);
+ Dict *copy(XRef *xrefA);
+
+ // Destructor.
+ ~Dict();
+
+ // Reference counting.
+ int incRef();
+ int decRef();
+
+ // Get number of entries.
+ int getLength() { return length; }
+
+ // Add an entry. NB: does not copy key.
+ void add(char *key, Object *val);
+
+ // Update the value of an existing entry, otherwise create it
+ void set(const char *key, Object *val);
+ // Remove an entry. This invalidate indexes
+ void remove(const char *key);
+
+ // Check if dictionary is of specified type.
+ GBool is(const char *type);
+
+ // Look up an entry and return the value. Returns a null object
+ // if <key> is not in the dictionary.
+ Object *lookup(const char *key, Object *obj, int recursion = 0);
+ Object *lookupNF(const char *key, Object *obj);
+ GBool lookupInt(const char *key, const char *alt_key, int *value);
+
+ // Iterative accessors.
+ char *getKey(int i);
+ Object *getVal(int i, Object *obj);
+ Object *getValNF(int i, Object *obj);
+
+ // Set the xref pointer. This is only used in one special case: the
+ // trailer dictionary, which is read before the xref table is
+ // parsed.
+ void setXRef(XRef *xrefA) { xref = xrefA; }
+
+ XRef *getXRef() { return xref; }
+
+ GBool hasKey(const char *key);
+
+private:
+
+ GBool sorted;
+ XRef *xref; // the xref table for this PDF file
+ DictEntry *entries; // array of entries
+ int size; // size of <entries> array
+ int length; // number of entries in dictionary
+ int ref; // reference count
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+
+ DictEntry *find(const char *key);
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Error.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Error.cc
new file mode 100644
index 00000000000..99ca3ad3f53
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Error.cc
@@ -0,0 +1,98 @@
+//========================================================================
+//
+// Error.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2005 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2012 Marek Kasik <mkasik@redhat.com>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include "GooString.h"
+#include "GlobalParams.h"
+#include "Error.h"
+
+static const char *errorCategoryNames[] = {
+ "Syntax Warning",
+ "Syntax Error",
+ "Config Error",
+ "Command Line Error",
+ "I/O Error",
+ "Permission Error",
+ "Unimplemented Feature",
+ "Internal Error"
+};
+
+static void (*errorCbk)(void *data, ErrorCategory category,
+ Goffset pos, char *msg) = NULL;
+static void *errorCbkData = NULL;
+
+void setErrorCallback(void (*cbk)(void *data, ErrorCategory category,
+ Goffset pos, char *msg),
+ void *data) {
+ errorCbk = cbk;
+ errorCbkData = data;
+}
+
+void CDECL error(ErrorCategory category, Goffset pos, const char *msg, ...) {
+ va_list args;
+ GooString *s, *sanitized;
+
+ // NB: this can be called before the globalParams object is created
+ if (!errorCbk && globalParams && globalParams->getErrQuiet()) {
+ return;
+ }
+ va_start(args, msg);
+ s = GooString::formatv(msg, args);
+ va_end(args);
+
+ sanitized = new GooString ();
+ for (int i = 0; i < s->getLength(); ++i) {
+ const char c = s->getChar(i);
+ if (c < (char)0x20 || c >= (char)0x7f) {
+ sanitized->appendf("<{0:02x}>", c & 0xff);
+ } else {
+ sanitized->append(c);
+ }
+ }
+
+ if (errorCbk) {
+ (*errorCbk)(errorCbkData, category, pos, sanitized->getCString());
+ } else {
+ if (pos >= 0) {
+ fprintf(stderr, "%s (%lld): %s\n",
+ errorCategoryNames[category], (long long)pos, sanitized->getCString());
+ } else {
+ fprintf(stderr, "%s: %s\n",
+ errorCategoryNames[category], sanitized->getCString());
+ }
+ fflush(stderr);
+ }
+ delete s;
+ delete sanitized;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Error.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Error.h
new file mode 100644
index 00000000000..9e11733d803
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Error.h
@@ -0,0 +1,60 @@
+//========================================================================
+//
+// Error.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2005 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2014 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef ERROR_H
+#define ERROR_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stdarg.h>
+#include "poppler-config.h"
+#include "goo/gtypes.h"
+#include "goo/GooString.h"
+
+enum ErrorCategory {
+ errSyntaxWarning, // PDF syntax error which can be worked around;
+ // output will probably be correct
+ errSyntaxError, // PDF syntax error which can be worked around;
+ // output will probably be incorrect
+ errConfig, // error in Xpdf config info (xpdfrc file, etc.)
+ errCommandLine, // error in user-supplied parameters, action not
+ // allowed, etc. (only used by command-line tools)
+ errIO, // error in file I/O
+ errNotAllowed, // action not allowed by PDF permission bits
+ errUnimplemented, // unimplemented PDF feature - display will be
+ // incorrect
+ errInternal // internal error - malfunction within the Xpdf code
+};
+
+extern void setErrorCallback(void (*cbk)(void *data, ErrorCategory category,
+ Goffset pos, char *msg),
+ void *data);
+
+extern void CDECL error(ErrorCategory category, Goffset pos, const char *msg, ...) GOOSTRING_FORMAT;
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/ErrorCodes.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/ErrorCodes.h
new file mode 100644
index 00000000000..b28528df564
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/ErrorCodes.h
@@ -0,0 +1,36 @@
+//========================================================================
+//
+// ErrorCodes.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef ERRORCODES_H
+#define ERRORCODES_H
+
+#define errNone 0 // no error
+
+#define errOpenFile 1 // couldn't open the PDF file
+
+#define errBadCatalog 2 // couldn't read the page catalog
+
+#define errDamaged 3 // PDF file was damaged and couldn't be
+ // repaired
+
+#define errEncrypted 4 // file was encrypted and password was
+ // incorrect or not supplied
+
+#define errHighlightFile 5 // nonexistent or invalid highlight file
+
+#define errBadPrinter 6 // invalid printer
+
+#define errPrinting 7 // error during printing
+
+#define errPermission 8 // PDF file doesn't allow that operation
+
+#define errBadPageNum 9 // invalid page number
+
+#define errFileIO 10 // file I/O error
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/FileSpec.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/FileSpec.cc
new file mode 100644
index 00000000000..bac1eaea0d7
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/FileSpec.cc
@@ -0,0 +1,295 @@
+//========================================================================
+//
+// FileSpec.cc
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008-2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+//========================================================================
+//
+// Most of the code from Link.cc and PSOutputDev.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <config.h>
+
+#include "FileSpec.h"
+
+EmbFile::EmbFile(Object *efStream)
+{
+ m_size = -1;
+ m_createDate = NULL;
+ m_modDate = NULL;
+ m_checksum = NULL;
+ m_mimetype = NULL;
+
+ efStream->copy(&m_objStr);
+
+ if (efStream->isStream()) {
+ // dataDict corresponds to Table 3.41 in the PDF1.6 spec.
+ Dict *dataDict = efStream->streamGetDict();
+
+ // subtype is normally the mimetype
+ Object subtypeName;
+ if (dataDict->lookup("Subtype", &subtypeName)->isName()) {
+ m_mimetype = new GooString(subtypeName.getName());
+ }
+ subtypeName.free();
+
+ // paramDict corresponds to Table 3.42 in the PDF1.6 spec
+ Object paramDict;
+ if (dataDict->lookup("Params", &paramDict)->isDict()) {
+ Object paramObj;
+ if (paramDict.dictLookup("ModDate", &paramObj)->isString())
+ m_modDate = new GooString(paramObj.getString());
+ paramObj.free();
+
+ if (paramDict.dictLookup("CreationDate", &paramObj)->isString())
+ m_createDate = new GooString(paramObj.getString());
+ paramObj.free();
+
+ if (paramDict.dictLookup("Size", &paramObj)->isInt())
+ m_size = paramObj.getInt();
+ paramObj.free();
+
+ if (paramDict.dictLookup("CheckSum", &paramObj)->isString())
+ m_checksum = new GooString(paramObj.getString());
+ paramObj.free();
+ }
+ paramDict.free();
+ }
+}
+
+EmbFile::~EmbFile()
+{
+ delete m_createDate;
+ delete m_modDate;
+ delete m_checksum;
+ delete m_mimetype;
+ m_objStr.free();
+}
+
+GBool EmbFile::save(const char *path) {
+ FILE *f;
+ GBool ret;
+
+ if (!(f = fopen(path, "wb"))) {
+ return gFalse;
+ }
+ ret = save2(f);
+ fclose(f);
+ return ret;
+}
+
+GBool EmbFile::save2(FILE *f) {
+ int c;
+
+ m_objStr.streamReset();
+ while ((c = m_objStr.streamGetChar()) != EOF) {
+ fputc(c, f);
+ }
+ return gTrue;
+}
+
+FileSpec::FileSpec(Object *fileSpecA)
+{
+ ok = gTrue;
+ fileName = NULL;
+ platformFileName = NULL;
+ embFile = NULL;
+ desc = NULL;
+ fileSpecA->copy(&fileSpec);
+
+ Object obj1;
+ if (!getFileSpecName(fileSpecA, &obj1)) {
+ ok = gFalse;
+ obj1.free();
+ error(errSyntaxError, -1, "Invalid FileSpec");
+ return;
+ }
+
+ fileName = obj1.getString()->copy();
+ obj1.free();
+
+ if (fileSpec.isDict()) {
+ if (fileSpec.dictLookup("EF", &obj1)->isDict()) {
+ if (!obj1.dictLookupNF("F", &fileStream)->isRef()) {
+ ok = gFalse;
+ fileStream.free();
+ error(errSyntaxError, -1, "Invalid FileSpec: Embedded file stream is not an indirect reference");
+ obj1.free();
+ return;
+ }
+ }
+ obj1.free();
+ }
+
+ if (fileSpec.dictLookup("Desc", &obj1)->isString())
+ desc = obj1.getString()->copy();
+ obj1.free();
+}
+
+FileSpec::~FileSpec()
+{
+ fileSpec.free();
+ fileStream.free();
+ delete fileName;
+ delete platformFileName;
+ delete embFile;
+ delete desc;
+}
+
+EmbFile *FileSpec::getEmbeddedFile()
+{
+ if(!ok)
+ return NULL;
+
+ if (embFile)
+ return embFile;
+
+ Object obj1;
+ XRef *xref = fileSpec.getDict()->getXRef();
+ embFile = new EmbFile(fileStream.fetch(xref, &obj1));
+ obj1.free();
+
+ return embFile;
+}
+
+GooString *FileSpec::getFileNameForPlatform()
+{
+ if (platformFileName)
+ return platformFileName;
+
+ Object obj1;
+ if (getFileSpecNameForPlatform(&fileSpec, &obj1))
+ platformFileName = obj1.getString()->copy();
+ obj1.free();
+
+ return platformFileName;
+}
+
+GBool getFileSpecName (Object *fileSpec, Object *fileName)
+{
+ if (fileSpec->isString()) {
+ fileSpec->copy(fileName);
+ return gTrue;
+ }
+
+ if (fileSpec->isDict()) {
+ fileSpec->dictLookup("UF", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("F", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("DOS", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("Mac", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("Unix", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ }
+ return gFalse;
+}
+
+GBool getFileSpecNameForPlatform (Object *fileSpec, Object *fileName)
+{
+ if (fileSpec->isString()) {
+ fileSpec->copy(fileName);
+ return gTrue;
+ }
+
+ if (fileSpec->isDict()) {
+ if (!fileSpec->dictLookup("UF", fileName)->isString ()) {
+ fileName->free();
+ if (!fileSpec->dictLookup("F", fileName)->isString ()) {
+ fileName->free();
+#ifdef _WIN32
+ const char *platform = "DOS";
+#else
+ const char *platform = "Unix";
+#endif
+ if (!fileSpec->dictLookup(platform, fileName)->isString ()) {
+ fileName->free();
+ error(errSyntaxError, -1, "Illegal file spec");
+ return gFalse;
+ }
+ }
+ }
+ } else {
+ error(errSyntaxError, -1, "Illegal file spec");
+ return gFalse;
+ }
+
+ // system-dependent path manipulation
+#ifdef _WIN32
+ int i, j;
+ GooString *name = fileName->getString();
+ // "//...." --> "\...."
+ // "/x/...." --> "x:\...."
+ // "/server/share/...." --> "\\server\share\...."
+ // convert escaped slashes to slashes and unescaped slashes to backslashes
+ i = 0;
+ if (name->getChar(0) == '/') {
+ if (name->getLength() >= 2 && name->getChar(1) == '/') {
+ name->del(0);
+ i = 0;
+ } else if (name->getLength() >= 2 &&
+ ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') ||
+ (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) &&
+ (name->getLength() == 2 || name->getChar(2) == '/')) {
+ name->setChar(0, name->getChar(1));
+ name->setChar(1, ':');
+ i = 2;
+ } else {
+ for (j = 2; j < name->getLength(); ++j) {
+ if (name->getChar(j-1) != '\\' &&
+ name->getChar(j) == '/') {
+ break;
+ }
+ }
+ if (j < name->getLength()) {
+ name->setChar(0, '\\');
+ name->insert(0, '\\');
+ i = 2;
+ }
+ }
+ }
+ for (; i < name->getLength(); ++i) {
+ if (name->getChar(i) == '/') {
+ name->setChar(i, '\\');
+ } else if (name->getChar(i) == '\\' &&
+ i+1 < name->getLength() &&
+ name->getChar(i+1) == '/') {
+ name->del(i);
+ }
+ }
+#endif /* _WIN32 */
+
+ return gTrue;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/FileSpec.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/FileSpec.h
new file mode 100644
index 00000000000..9f2f6fcd131
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/FileSpec.h
@@ -0,0 +1,76 @@
+//========================================================================
+//
+// FileSpec.h
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef FILE_SPEC_H
+#define FILE_SPEC_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class EmbFile {
+public:
+ EmbFile(Object *efStream);
+ ~EmbFile();
+
+ int size() { return m_size; }
+ GooString *modDate() { return m_modDate; }
+ GooString *createDate() { return m_createDate; }
+ GooString *checksum() { return m_checksum; }
+ GooString *mimeType() { return m_mimetype; }
+ Stream *stream() { return isOk() ? m_objStr.getStream() : NULL; }
+ GBool isOk() { return m_objStr.isStream(); }
+ GBool save(const char *path);
+
+private:
+ GBool save2(FILE *f);
+
+ int m_size;
+ GooString *m_createDate;
+ GooString *m_modDate;
+ GooString *m_checksum;
+ GooString *m_mimetype;
+ Object m_objStr;
+};
+
+class FileSpec {
+public:
+ FileSpec(Object *fileSpec);
+ ~FileSpec();
+
+ GBool isOk() { return ok; }
+
+ GooString *getFileName() const { return fileName; }
+ GooString *getFileNameForPlatform();
+ GooString *getDescription() const { return desc; }
+ EmbFile *getEmbeddedFile();
+
+private:
+ GBool ok;
+
+ Object fileSpec;
+
+ GooString *fileName; // F, UF, DOS, Mac, Unix
+ GooString *platformFileName;
+ Object fileStream; // Ref to F entry in UF
+ EmbFile *embFile;
+ GooString *desc; // Desc
+};
+
+GBool getFileSpecName (Object *fileSpec, Object *fileName);
+GBool getFileSpecNameForPlatform (Object *fileSpec, Object *fileName);
+
+#endif /* FILE_SPEC_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/FlateStream.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/FlateStream.cc
new file mode 100644
index 00000000000..7990dadd821
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/FlateStream.cc
@@ -0,0 +1,128 @@
+//========================================================================
+//
+// FlateStream.cc
+//
+// Copyright (C) 2005, Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2010, Albert Astals Cid <aacid@kde.org>
+//
+// This file is under the GPLv2 or later license
+//
+//========================================================================
+#include "FlateStream.h"
+FlateStream::FlateStream(Stream *strA, int predictor, int columns, int colors, int bits) :
+ FilterStream(strA)
+{
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
+ } else {
+ pred = NULL;
+ }
+ out_pos = 0;
+ memset(&d_stream, 0, sizeof(d_stream));
+ inflateInit(&d_stream);
+}
+
+FlateStream::~FlateStream() {
+ inflateEnd(&d_stream);
+ delete pred;
+ delete str;
+}
+
+void FlateStream::reset() {
+ //FIXME: what are the semantics of reset?
+ //i.e. how much intialization has to happen in the constructor?
+
+ /* reinitialize zlib */
+ inflateEnd(&d_stream);
+ memset(&d_stream, 0, sizeof(d_stream));
+ inflateInit(&d_stream);
+
+ str->reset();
+ d_stream.avail_in = 0;
+ status = Z_OK;
+ out_pos = 0;
+ out_buf_len = 0;
+}
+
+int FlateStream::getRawChar() {
+ return doGetRawChar();
+}
+
+void FlateStream::getRawChars(int nChars, int *buffer) {
+ for (int i = 0; i < nChars; ++i)
+ buffer[i] = doGetRawChar();
+}
+
+int FlateStream::getChar() {
+ if (pred)
+ return pred->getChar();
+ else
+ return getRawChar();
+}
+
+int FlateStream::lookChar() {
+ if (pred)
+ return pred->lookChar();
+
+ if (fill_buffer())
+ return EOF;
+
+ return out_buf[out_pos];
+}
+
+int FlateStream::fill_buffer() {
+ /* only fill the buffer if it has all been used */
+ if (out_pos >= out_buf_len) {
+ /* check if the flatestream has been exhausted */
+ if (status == Z_STREAM_END) {
+ return -1;
+ }
+
+ /* set to the begining of out_buf */
+ d_stream.avail_out = sizeof(out_buf);
+ d_stream.next_out = out_buf;
+ out_pos = 0;
+
+ while (1) {
+ /* buffer is empty so we need to fill it */
+ if (d_stream.avail_in == 0) {
+ int c;
+ /* read from the source stream */
+ while (d_stream.avail_in < sizeof(in_buf) && (c = str->getChar()) != EOF) {
+ in_buf[d_stream.avail_in++] = c;
+ }
+ d_stream.next_in = in_buf;
+ }
+
+ /* keep decompressing until we can't anymore */
+ if (d_stream.avail_out == 0 || d_stream.avail_in == 0 || (status != Z_OK && status != Z_BUF_ERROR))
+ break;
+ status = inflate(&d_stream, Z_SYNC_FLUSH);
+ }
+
+ out_buf_len = sizeof(out_buf) - d_stream.avail_out;
+ if (status != Z_OK && status != Z_STREAM_END)
+ return -1;
+ if (!out_buf_len)
+ return -1;
+ }
+
+ return 0;
+}
+
+GooString *FlateStream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+
+ if (psLevel < 3 || pred) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /FlateDecode filter\n");
+ return s;
+}
+
+GBool FlateStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/FlateStream.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/FlateStream.h
new file mode 100644
index 00000000000..9e3835f042a
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/FlateStream.h
@@ -0,0 +1,77 @@
+//========================================================================
+//
+// FlateStream.h
+//
+// Copyright (C) 2005, Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2010, 2011, Albert Astals Cid <aacid@kde.org>
+//
+// This file is under the GPLv2 or later license
+//
+//========================================================================
+
+#ifndef FLATESTREAM_H
+#define FLATESTREAM_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "poppler-config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#include "goo/gmem.h"
+#include "goo/gfile.h"
+#include "Error.h"
+#include "Object.h"
+#include "Decrypt.h"
+#include "Stream.h"
+
+extern "C" {
+#include <zlib.h>
+}
+
+class FlateStream: public FilterStream {
+public:
+
+ FlateStream(Stream *strA, int predictor, int columns, int colors, int bits);
+ virtual ~FlateStream();
+ virtual StreamKind getKind() { return strFlate; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual int getRawChar();
+ virtual void getRawChars(int nChars, int *buffer);
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+ inline int doGetRawChar() {
+ if (fill_buffer())
+ return EOF;
+
+ return out_buf[out_pos++];
+ }
+
+ int fill_buffer(void);
+ z_stream d_stream;
+ StreamPredictor *pred;
+ int status;
+ /* in_buf currently needs to be 1 or we over read from EmbedStreams */
+ unsigned char in_buf[1];
+ unsigned char out_buf[4096];
+ int out_pos;
+ int out_buf_len;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/FontEncodingTables.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/FontEncodingTables.cc
new file mode 100644
index 00000000000..6ebef787421
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/FontEncodingTables.cc
@@ -0,0 +1,1824 @@
+//========================================================================
+//
+// FontEncodingTables.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <config.h>
+#include <stdlib.h>
+#include "FontEncodingTables.h"
+
+const char *macRomanEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ NULL,
+ "Adieresis",
+ "Aring",
+ "Ccedilla",
+ "Eacute",
+ "Ntilde",
+ "Odieresis",
+ "Udieresis",
+ "aacute",
+ "agrave",
+ "acircumflex",
+ "adieresis",
+ "atilde",
+ "aring",
+ "ccedilla",
+ "eacute",
+ "egrave",
+ "ecircumflex",
+ "edieresis",
+ "iacute",
+ "igrave",
+ "icircumflex",
+ "idieresis",
+ "ntilde",
+ "oacute",
+ "ograve",
+ "ocircumflex",
+ "odieresis",
+ "otilde",
+ "uacute",
+ "ugrave",
+ "ucircumflex",
+ "udieresis",
+ "dagger",
+ "degree",
+ "cent",
+ "sterling",
+ "section",
+ "bullet",
+ "paragraph",
+ "germandbls",
+ "registered",
+ "copyright",
+ "trademark",
+ "acute",
+ "dieresis",
+ "notequal",
+ "AE",
+ "Oslash",
+ "infinity",
+ "plusminus",
+ "lessequal",
+ "greaterequal",
+ "yen",
+ "mu",
+ "partialdiff",
+ "summation",
+ "product",
+ "pi",
+ "integral",
+ "ordfeminine",
+ "ordmasculine",
+ "Omega",
+ "ae",
+ "oslash",
+ "questiondown",
+ "exclamdown",
+ "logicalnot",
+ "radical",
+ "florin",
+ "approxequal",
+ "Delta",
+ "guillemotleft",
+ "guillemotright",
+ "ellipsis",
+ "space",
+ "Agrave",
+ "Atilde",
+ "Otilde",
+ "OE",
+ "oe",
+ "endash",
+ "emdash",
+ "quotedblleft",
+ "quotedblright",
+ "quoteleft",
+ "quoteright",
+ "divide",
+ "lozenge",
+ "ydieresis",
+ "Ydieresis",
+ "fraction",
+ "currency",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "daggerdbl",
+ "periodcentered",
+ "quotesinglbase",
+ "quotedblbase",
+ "perthousand",
+ "Acircumflex",
+ "Ecircumflex",
+ "Aacute",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Oacute",
+ "Ocircumflex",
+ "apple",
+ "Ograve",
+ "Uacute",
+ "Ucircumflex",
+ "Ugrave",
+ "dotlessi",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron"
+};
+
+const char *macExpertEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "centoldstyle",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "comma",
+ "hyphen",
+ "period",
+ "fraction",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "colon",
+ "semicolon",
+ NULL,
+ "threequartersemdash",
+ NULL,
+ "questionsmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Ethsmall",
+ NULL,
+ NULL,
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ff",
+ "fi",
+ "fl",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ NULL,
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hypheninferior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ NULL,
+ NULL,
+ "asuperior",
+ "centsuperior",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Aacutesmall",
+ "Agravesmall",
+ "Acircumflexsmall",
+ "Adieresissmall",
+ "Atildesmall",
+ "Aringsmall",
+ "Ccedillasmall",
+ "Eacutesmall",
+ "Egravesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Iacutesmall",
+ "Igravesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ntildesmall",
+ "Oacutesmall",
+ "Ogravesmall",
+ "Ocircumflexsmall",
+ "Odieresissmall",
+ "Otildesmall",
+ "Uacutesmall",
+ "Ugravesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ NULL,
+ "eightsuperior",
+ "fourinferior",
+ "threeinferior",
+ "sixinferior",
+ "eightinferior",
+ "seveninferior",
+ "Scaronsmall",
+ NULL,
+ "centinferior",
+ "twoinferior",
+ NULL,
+ "Dieresissmall",
+ NULL,
+ "Caronsmall",
+ "osuperior",
+ "fiveinferior",
+ NULL,
+ "commainferior",
+ "periodinferior",
+ "Yacutesmall",
+ NULL,
+ "dollarinferior",
+ NULL,
+ NULL,
+ "Thornsmall",
+ NULL,
+ "nineinferior",
+ "zeroinferior",
+ "Zcaronsmall",
+ "AEsmall",
+ "Oslashsmall",
+ "questiondownsmall",
+ "oneinferior",
+ "Lslashsmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Cedillasmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "OEsmall",
+ "figuredash",
+ "hyphensuperior",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdownsmall",
+ NULL,
+ "Ydieresissmall",
+ NULL,
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "ninesuperior",
+ "zerosuperior",
+ NULL,
+ "esuperior",
+ "rsuperior",
+ "tsuperior",
+ NULL,
+ NULL,
+ "isuperior",
+ "ssuperior",
+ "dsuperior",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "lsuperior",
+ "Ogoneksmall",
+ "Brevesmall",
+ "Macronsmall",
+ "bsuperior",
+ "nsuperior",
+ "msuperior",
+ "commasuperior",
+ "periodsuperior",
+ "Dotaccentsmall",
+ "Ringsmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+const char *winAnsiEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "bullet",
+ "Euro",
+ "bullet",
+ "quotesinglbase",
+ "florin",
+ "quotedblbase",
+ "ellipsis",
+ "dagger",
+ "daggerdbl",
+ "circumflex",
+ "perthousand",
+ "Scaron",
+ "guilsinglleft",
+ "OE",
+ "bullet",
+ "Zcaron",
+ "bullet",
+ "bullet",
+ "quoteleft",
+ "quoteright",
+ "quotedblleft",
+ "quotedblright",
+ "bullet",
+ "endash",
+ "emdash",
+ "tilde",
+ "trademark",
+ "scaron",
+ "guilsinglright",
+ "oe",
+ "bullet",
+ "zcaron",
+ "Ydieresis",
+ "space",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "currency",
+ "yen",
+ "brokenbar",
+ "section",
+ "dieresis",
+ "copyright",
+ "ordfeminine",
+ "guillemotleft",
+ "logicalnot",
+ "hyphen",
+ "registered",
+ "macron",
+ "degree",
+ "plusminus",
+ "twosuperior",
+ "threesuperior",
+ "acute",
+ "mu",
+ "paragraph",
+ "periodcentered",
+ "cedilla",
+ "onesuperior",
+ "ordmasculine",
+ "guillemotright",
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "questiondown",
+ "Agrave",
+ "Aacute",
+ "Acircumflex",
+ "Atilde",
+ "Adieresis",
+ "Aring",
+ "AE",
+ "Ccedilla",
+ "Egrave",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Igrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Eth",
+ "Ntilde",
+ "Ograve",
+ "Oacute",
+ "Ocircumflex",
+ "Otilde",
+ "Odieresis",
+ "multiply",
+ "Oslash",
+ "Ugrave",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Yacute",
+ "Thorn",
+ "germandbls",
+ "agrave",
+ "aacute",
+ "acircumflex",
+ "atilde",
+ "adieresis",
+ "aring",
+ "ae",
+ "ccedilla",
+ "egrave",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "igrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "eth",
+ "ntilde",
+ "ograve",
+ "oacute",
+ "ocircumflex",
+ "otilde",
+ "odieresis",
+ "divide",
+ "oslash",
+ "ugrave",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "yacute",
+ "thorn",
+ "ydieresis"
+};
+
+const char *standardEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ NULL,
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ NULL,
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ NULL,
+ "questiondown",
+ NULL,
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ NULL,
+ "ring",
+ "cedilla",
+ NULL,
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "AE",
+ NULL,
+ "ordfeminine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ae",
+ NULL,
+ NULL,
+ NULL,
+ "dotlessi",
+ NULL,
+ NULL,
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+const char *expertEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ NULL,
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "comma",
+ "hyphen",
+ "period",
+ "fraction",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "colon",
+ "semicolon",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ NULL,
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ NULL,
+ NULL,
+ NULL,
+ "isuperior",
+ NULL,
+ NULL,
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ NULL,
+ NULL,
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ NULL,
+ "ff",
+ "fi",
+ "fl",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ NULL,
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ NULL,
+ NULL,
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ NULL,
+ "Dotaccentsmall",
+ NULL,
+ NULL,
+ "Macronsmall",
+ NULL,
+ NULL,
+ "figuredash",
+ "hypheninferior",
+ NULL,
+ NULL,
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ NULL,
+ NULL,
+ NULL,
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ NULL,
+ NULL,
+ "zerosuperior",
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall"
+};
+
+const char *symbolEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "universal",
+ "numbersign",
+ "existential",
+ "percent",
+ "ampersand",
+ "suchthat",
+ "parenleft",
+ "parenright",
+ "asteriskmath",
+ "plus",
+ "comma",
+ "minus",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "congruent",
+ "Alpha",
+ "Beta",
+ "Chi",
+ "Delta",
+ "Epsilon",
+ "Phi",
+ "Gamma",
+ "Eta",
+ "Iota",
+ "theta1",
+ "Kappa",
+ "Lambda",
+ "Mu",
+ "Nu",
+ "Omicron",
+ "Pi",
+ "Theta",
+ "Rho",
+ "Sigma",
+ "Tau",
+ "Upsilon",
+ "sigma1",
+ "Omega",
+ "Xi",
+ "Psi",
+ "Zeta",
+ "bracketleft",
+ "therefore",
+ "bracketright",
+ "perpendicular",
+ "underscore",
+ "radicalex",
+ "alpha",
+ "beta",
+ "chi",
+ "delta",
+ "epsilon",
+ "phi",
+ "gamma",
+ "eta",
+ "iota",
+ "phi1",
+ "kappa",
+ "lambda",
+ "mu",
+ "nu",
+ "omicron",
+ "pi",
+ "theta",
+ "rho",
+ "sigma",
+ "tau",
+ "upsilon",
+ "omega1",
+ "omega",
+ "xi",
+ "psi",
+ "zeta",
+ "braceleft",
+ "bar",
+ "braceright",
+ "similar",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Upsilon1",
+ "minute",
+ "lessequal",
+ "fraction",
+ "infinity",
+ "florin",
+ "club",
+ "diamond",
+ "heart",
+ "spade",
+ "arrowboth",
+ "arrowleft",
+ "arrowup",
+ "arrowright",
+ "arrowdown",
+ "degree",
+ "plusminus",
+ "second",
+ "greaterequal",
+ "multiply",
+ "proportional",
+ "partialdiff",
+ "bullet",
+ "divide",
+ "notequal",
+ "equivalence",
+ "approxequal",
+ "ellipsis",
+ "arrowvertex",
+ "arrowhorizex",
+ "carriagereturn",
+ "aleph",
+ "Ifraktur",
+ "Rfraktur",
+ "weierstrass",
+ "circlemultiply",
+ "circleplus",
+ "emptyset",
+ "intersection",
+ "union",
+ "propersuperset",
+ "reflexsuperset",
+ "notsubset",
+ "propersubset",
+ "reflexsubset",
+ "element",
+ "notelement",
+ "angle",
+ "gradient",
+ "registerserif",
+ "copyrightserif",
+ "trademarkserif",
+ "product",
+ "radical",
+ "dotmath",
+ "logicalnot",
+ "logicaland",
+ "logicalor",
+ "arrowdblboth",
+ "arrowdblleft",
+ "arrowdblup",
+ "arrowdblright",
+ "arrowdbldown",
+ "lozenge",
+ "angleleft",
+ "registersans",
+ "copyrightsans",
+ "trademarksans",
+ "summation",
+ "parenlefttp",
+ "parenleftex",
+ "parenleftbt",
+ "bracketlefttp",
+ "bracketleftex",
+ "bracketleftbt",
+ "bracelefttp",
+ "braceleftmid",
+ "braceleftbt",
+ "braceex",
+ NULL,
+ "angleright",
+ "integral",
+ "integraltp",
+ "integralex",
+ "integralbt",
+ "parenrighttp",
+ "parenrightex",
+ "parenrightbt",
+ "bracketrighttp",
+ "bracketrightex",
+ "bracketrightbt",
+ "bracerighttp",
+ "bracerightmid",
+ "bracerightbt",
+ NULL
+};
+
+const char *zapfDingbatsEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "a1",
+ "a2",
+ "a202",
+ "a3",
+ "a4",
+ "a5",
+ "a119",
+ "a118",
+ "a117",
+ "a11",
+ "a12",
+ "a13",
+ "a14",
+ "a15",
+ "a16",
+ "a105",
+ "a17",
+ "a18",
+ "a19",
+ "a20",
+ "a21",
+ "a22",
+ "a23",
+ "a24",
+ "a25",
+ "a26",
+ "a27",
+ "a28",
+ "a6",
+ "a7",
+ "a8",
+ "a9",
+ "a10",
+ "a29",
+ "a30",
+ "a31",
+ "a32",
+ "a33",
+ "a34",
+ "a35",
+ "a36",
+ "a37",
+ "a38",
+ "a39",
+ "a40",
+ "a41",
+ "a42",
+ "a43",
+ "a44",
+ "a45",
+ "a46",
+ "a47",
+ "a48",
+ "a49",
+ "a50",
+ "a51",
+ "a52",
+ "a53",
+ "a54",
+ "a55",
+ "a56",
+ "a57",
+ "a58",
+ "a59",
+ "a60",
+ "a61",
+ "a62",
+ "a63",
+ "a64",
+ "a65",
+ "a66",
+ "a67",
+ "a68",
+ "a69",
+ "a70",
+ "a71",
+ "a72",
+ "a73",
+ "a74",
+ "a203",
+ "a75",
+ "a204",
+ "a76",
+ "a77",
+ "a78",
+ "a79",
+ "a81",
+ "a82",
+ "a83",
+ "a84",
+ "a97",
+ "a98",
+ "a99",
+ "a100",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "a101",
+ "a102",
+ "a103",
+ "a104",
+ "a106",
+ "a107",
+ "a108",
+ "a112",
+ "a111",
+ "a110",
+ "a109",
+ "a120",
+ "a121",
+ "a122",
+ "a123",
+ "a124",
+ "a125",
+ "a126",
+ "a127",
+ "a128",
+ "a129",
+ "a130",
+ "a131",
+ "a132",
+ "a133",
+ "a134",
+ "a135",
+ "a136",
+ "a137",
+ "a138",
+ "a139",
+ "a140",
+ "a141",
+ "a142",
+ "a143",
+ "a144",
+ "a145",
+ "a146",
+ "a147",
+ "a148",
+ "a149",
+ "a150",
+ "a151",
+ "a152",
+ "a153",
+ "a154",
+ "a155",
+ "a156",
+ "a157",
+ "a158",
+ "a159",
+ "a160",
+ "a161",
+ "a163",
+ "a164",
+ "a196",
+ "a165",
+ "a192",
+ "a166",
+ "a167",
+ "a168",
+ "a169",
+ "a170",
+ "a171",
+ "a172",
+ "a173",
+ "a162",
+ "a174",
+ "a175",
+ "a176",
+ "a177",
+ "a178",
+ "a179",
+ "a193",
+ "a180",
+ "a199",
+ "a181",
+ "a200",
+ "a182",
+ NULL,
+ "a201",
+ "a183",
+ "a184",
+ "a197",
+ "a185",
+ "a194",
+ "a198",
+ "a186",
+ "a195",
+ "a187",
+ "a188",
+ "a189",
+ "a190",
+ "a191",
+ NULL
+};
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/FontEncodingTables.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/FontEncodingTables.h
new file mode 100644
index 00000000000..a417b324e48
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/FontEncodingTables.h
@@ -0,0 +1,20 @@
+//========================================================================
+//
+// FontEncodingTables.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FONTENCODINGTABLES_H
+#define FONTENCODINGTABLES_H
+
+extern const char *macRomanEncoding[];
+extern const char *macExpertEncoding[];
+extern const char *winAnsiEncoding[];
+extern const char *standardEncoding[];
+extern const char *expertEncoding[];
+extern const char *symbolEncoding[];
+extern const char *zapfDingbatsEncoding[];
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/FontInfo.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/FontInfo.cc
new file mode 100644
index 00000000000..8fc89e9d827
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/FontInfo.cc
@@ -0,0 +1,245 @@
+//========================================================================
+//
+// FontInfo.cc
+//
+// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005-2008, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
+// Copyright (C) 2006 Kouhei Sutou <kou@cozmixng.org>
+// Copyright (C) 2009 Pino Toscano <pino@kde.org>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2010, 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2010, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+//========================================================================
+//
+// Based on code from pdffonts.cc
+//
+// Copyright 2001-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <math.h>
+#include "GlobalParams.h"
+#include "Error.h"
+#include "Object.h"
+#include "Dict.h"
+#include "GfxFont.h"
+#include "Annot.h"
+#include "PDFDoc.h"
+#include "FontInfo.h"
+
+FontInfoScanner::FontInfoScanner(PDFDoc *docA, int firstPage) {
+ doc = docA;
+ currentPage = firstPage + 1;
+}
+
+FontInfoScanner::~FontInfoScanner() {
+}
+
+GooList *FontInfoScanner::scan(int nPages) {
+ GooList *result;
+ Page *page;
+ Dict *resDict;
+ Annots *annots;
+ Object obj1;
+ int lastPage;
+
+ if (currentPage > doc->getNumPages()) {
+ return NULL;
+ }
+
+ result = new GooList();
+
+ lastPage = currentPage + nPages;
+ if (lastPage > doc->getNumPages() + 1) {
+ lastPage = doc->getNumPages() + 1;
+ }
+
+ XRef *xrefA = doc->getXRef()->copy();
+ for (int pg = currentPage; pg < lastPage; ++pg) {
+ page = doc->getPage(pg);
+ if (!page) continue;
+
+ if ((resDict = page->getResourceDictCopy(xrefA))) {
+ scanFonts(xrefA, resDict, result);
+ delete resDict;
+ }
+ annots = page->getAnnots();
+ for (int i = 0; i < annots->getNumAnnots(); ++i) {
+ if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) {
+ scanFonts(xrefA, obj1.getDict(), result);
+ }
+ obj1.free();
+ }
+ }
+
+ currentPage = lastPage;
+
+ delete xrefA;
+ return result;
+}
+
+void FontInfoScanner::scanFonts(XRef *xrefA, Dict *resDict, GooList *fontsList) {
+ Object obj1, obj2, objDict, resObj;
+ Ref r;
+ GfxFontDict *gfxFontDict;
+ GfxFont *font;
+ int i;
+
+ // scan the fonts in this resource dictionary
+ gfxFontDict = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(xrefA, &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ gfxFontDict = new GfxFontDict(xrefA, &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ gfxFontDict = new GfxFontDict(xrefA, NULL, obj1.getDict());
+ }
+ if (gfxFontDict) {
+ for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
+ if ((font = gfxFontDict->getFont(i))) {
+ Ref fontRef = *font->getID();
+
+ // add this font to the list if not already found
+ if (fonts.find(fontRef.num) == fonts.end()) {
+ fontsList->append(new FontInfo(font, xrefA));
+ fonts.insert(fontRef.num);
+ }
+ }
+ }
+ delete gfxFontDict;
+ }
+ obj1.free();
+
+ // recursively scan any resource dictionaries in objects in this
+ // resource dictionary
+ const char *resTypes[] = { "XObject", "Pattern" };
+ for (Guint resType = 0; resType < sizeof(resTypes) / sizeof(resTypes[0]); ++resType) {
+ resDict->lookup(resTypes[resType], &objDict);
+ if (objDict.isDict()) {
+ for (i = 0; i < objDict.dictGetLength(); ++i) {
+ objDict.dictGetValNF(i, &obj1);
+ if (obj1.isRef()) {
+ // check for an already-seen object
+ const Ref r = obj1.getRef();
+ if (visitedObjects.find(r.num) != visitedObjects.end()) {
+ obj1.free();
+ continue;
+ }
+
+ visitedObjects.insert(r.num);
+ }
+
+ obj1.fetch(xrefA, &obj2);
+
+ if (obj2.isStream()) {
+ obj2.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict() && resObj.getDict() != resDict) {
+ scanFonts(xrefA, resObj.getDict(), fontsList);
+ }
+ resObj.free();
+ }
+ obj1.free();
+ obj2.free();
+ }
+ }
+ objDict.free();
+ }
+}
+
+FontInfo::FontInfo(GfxFont *font, XRef *xref) {
+ GooString *origName;
+ Object fontObj, toUnicodeObj;
+ int i;
+
+ fontRef = *font->getID();
+
+ // font name
+ origName = font->getName();
+ if (origName != NULL) {
+ name = font->getName()->copy();
+ } else {
+ name = NULL;
+ }
+
+ // font type
+ type = (FontInfo::Type)font->getType();
+
+ // check for an embedded font
+ if (font->getType() == fontType3) {
+ emb = gTrue;
+ } else {
+ emb = font->getEmbeddedFontID(&embRef);
+ }
+
+ file = NULL;
+ substituteName = NULL;
+ if (!emb)
+ {
+ SysFontType dummy;
+ int dummy2;
+ GooString substituteNameAux;
+ file = globalParams->findSystemFontFile(font, &dummy, &dummy2, &substituteNameAux);
+ if (substituteNameAux.getLength() > 0)
+ substituteName = substituteNameAux.copy();
+ }
+ encoding = font->getEncodingName()->copy();
+
+ // look for a ToUnicode map
+ hasToUnicode = gFalse;
+ if (xref->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
+ hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
+ toUnicodeObj.free();
+ }
+ fontObj.free();
+
+ // check for a font subset name: capital letters followed by a '+'
+ // sign
+ subset = gFalse;
+ if (name) {
+ for (i = 0; i < name->getLength(); ++i) {
+ if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
+ break;
+ }
+ }
+ subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
+ }
+}
+
+FontInfo::FontInfo(FontInfo& f) {
+ name = f.name ? f.name->copy() : NULL;
+ file = f.file ? f.file->copy() : NULL;
+ encoding = f.encoding ? f.encoding->copy() : NULL;
+ substituteName = f.substituteName ? f.substituteName->copy() : NULL;
+ type = f.type;
+ emb = f.emb;
+ subset = f.subset;
+ hasToUnicode = f.hasToUnicode;
+ fontRef = f.fontRef;
+ embRef = f.embRef;
+}
+
+FontInfo::~FontInfo() {
+ delete name;
+ delete file;
+ delete encoding;
+ if (substituteName)
+ delete substituteName;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/FontInfo.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/FontInfo.h
new file mode 100644
index 00000000000..615b6793de3
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/FontInfo.h
@@ -0,0 +1,103 @@
+//========================================================================
+//
+// FontInfo.h
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005-2008, 2010, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
+// Copyright (C) 2009 Pino Toscano <pino@kde.org>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+//========================================================================
+//
+// Based on code from pdffonts.cc
+//
+// Copyright 2001-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FONT_INFO_H
+#define FONT_INFO_H
+
+#include "Object.h"
+#include "goo/gtypes.h"
+#include "goo/GooList.h"
+
+class GfxFont;
+class PDFDoc;
+
+class FontInfo {
+public:
+ enum Type {
+ unknown,
+ Type1,
+ Type1C,
+ Type1COT,
+ Type3,
+ TrueType,
+ TrueTypeOT,
+ CIDType0,
+ CIDType0C,
+ CIDType0COT,
+ CIDTrueType,
+ CIDTrueTypeOT
+ };
+
+ // Constructor.
+ FontInfo(GfxFont *fontA, XRef *xrefA);
+ // Copy constructor
+ FontInfo(FontInfo& f);
+ // Destructor.
+ ~FontInfo();
+
+ GooString *getName() { return name; };
+ GooString *getSubstituteName() { return substituteName; };
+ GooString *getFile() { return file; };
+ GooString *getEncoding() { return encoding; };
+ Type getType() { return type; };
+ GBool getEmbedded() { return emb; };
+ GBool getSubset() { return subset; };
+ GBool getToUnicode() { return hasToUnicode; };
+ Ref getRef() { return fontRef; };
+ Ref getEmbRef() { return embRef; };
+
+private:
+ GooString *name;
+ GooString *substituteName;
+ GooString *file;
+ GooString *encoding;
+ Type type;
+ GBool emb;
+ GBool subset;
+ GBool hasToUnicode;
+ Ref fontRef;
+ Ref embRef;
+};
+
+class FontInfoScanner {
+public:
+
+ // Constructor.
+ FontInfoScanner(PDFDoc *doc, int firstPage = 0);
+ // Destructor.
+ ~FontInfoScanner();
+
+ GooList *scan(int nPages);
+
+private:
+
+ PDFDoc *doc;
+ int currentPage;
+ std::set<int> fonts;
+ std::set<int> visitedObjects;
+
+ void scanFonts(XRef *xrefA, Dict *resDict, GooList *fontsList);
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Form.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Form.cc
new file mode 100644
index 00000000000..a46a6590f27
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Form.cc
@@ -0,0 +1,1612 @@
+//========================================================================
+//
+// Form.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2006-2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright 2007-2012 Albert Astals Cid <aacid@kde.org>
+// Copyright 2007-2008, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright 2007, 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright 2007 Iñigo Martínez <inigomartinez@gmail.com>
+// Copyright 2008, 2011 Pino Toscano <pino@kde.org>
+// Copyright 2008 Michael Vrable <mvrable@cs.ucsd.edu>
+// Copyright 2009 Matthias Drochner <M.Drochner@fz-juelich.de>
+// Copyright 2009 KDAB via Guillermo Amaral <gamaral@amaral.com.mx>
+// Copyright 2010, 2012 Mark Riedesel <mark@klowner.com>
+// Copyright 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <set>
+#include <stddef.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "Error.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Gfx.h"
+#include "Form.h"
+#include "PDFDoc.h"
+#include "XRef.h"
+#include "PDFDocEncoding.h"
+#include "Annot.h"
+#include "Link.h"
+
+//return a newly allocated char* containing an UTF16BE string of size length
+char* pdfDocEncodingToUTF16 (GooString* orig, int* length)
+{
+ //double size, a unicode char takes 2 char, add 2 for the unicode marker
+ *length = 2+2*orig->getLength();
+ char *result = new char[(*length)];
+ char *cstring = orig->getCString();
+ //unicode marker
+ result[0] = 0xfe;
+ result[1] = 0xff;
+ //convert to utf16
+ for(int i=2,j=0; i<(*length); i+=2,j++) {
+ Unicode u = pdfDocEncoding[(unsigned int)((unsigned char)cstring[j])]&0xffff;
+ result[i] = (u >> 8) & 0xff;
+ result[i+1] = u & 0xff;
+ }
+ return result;
+}
+
+static GooString *convertToUtf16(GooString *pdfDocEncodingString)
+{
+ int tmp_length;
+ char* tmp_str = pdfDocEncodingToUTF16(pdfDocEncodingString, &tmp_length);
+ delete pdfDocEncodingString;
+ pdfDocEncodingString = new GooString(tmp_str, tmp_length);
+ delete [] tmp_str;
+ return pdfDocEncodingString;
+}
+
+
+FormWidget::FormWidget(PDFDoc *docA, Object *aobj, unsigned num, Ref aref, FormField *fieldA)
+{
+ ref = aref;
+ ID = 0;
+ childNum = num;
+ doc = docA;
+ xref = doc->getXRef();
+ aobj->copy(&obj);
+ type = formUndef;
+ field = fieldA;
+ widget = NULL;
+}
+
+FormWidget::~FormWidget()
+{
+ if (widget)
+ widget->decRefCnt();
+ obj.free ();
+}
+
+#ifdef DEBUG_FORMS
+void FormWidget::print(int indent) {
+ printf ("%*s+ (%d %d): [widget]\n", indent, "", ref.num, ref.gen);
+}
+#endif
+
+void FormWidget::createWidgetAnnotation() {
+ if (widget)
+ return;
+
+ Object obj1;
+ obj1.initRef(ref.num, ref.gen);
+ widget = new AnnotWidget(doc, obj.getDict(), &obj1, field);
+ obj1.free();
+}
+
+GBool FormWidget::inRect(double x, double y) const {
+ return widget ? widget->inRect(x, y) : gFalse;
+}
+
+void FormWidget::getRect(double *x1, double *y1, double *x2, double *y2) const {
+ if (widget)
+ widget->getRect(x1, y1, x2, y2);
+}
+
+double FormWidget::getFontSize() const {
+ return widget ? widget->getFontSize() : 0.;
+}
+
+bool FormWidget::isReadOnly() const
+{
+ return field->isReadOnly();
+}
+
+int FormWidget::encodeID (unsigned pageNum, unsigned fieldNum)
+{
+ return (pageNum << 4*sizeof(unsigned)) + fieldNum;
+}
+
+void FormWidget::decodeID (unsigned id, unsigned* pageNum, unsigned* fieldNum)
+{
+ *pageNum = id >> 4*sizeof(unsigned);
+ *fieldNum = (id << 4*sizeof(unsigned)) >> 4*sizeof(unsigned);
+}
+
+GooString *FormWidget::getPartialName() const {
+ return field->getPartialName();
+}
+
+GooString *FormWidget::getAlternateUiName() const {
+ return field->getAlternateUiName();
+}
+
+GooString *FormWidget::getMappingName() const {
+ return field->getMappingName();
+}
+
+GooString *FormWidget::getFullyQualifiedName() {
+ return field->getFullyQualifiedName();
+}
+
+LinkAction *FormWidget::getActivationAction() {
+ return widget ? widget->getAction() : NULL;
+}
+
+LinkAction *FormWidget::getAdditionalAction(Annot::FormAdditionalActionsType type) {
+ return widget ? widget->getFormAdditionalAction(type) : NULL;
+}
+
+FormWidgetButton::FormWidgetButton (PDFDoc *docA, Object *aobj, unsigned num, Ref ref, FormField *p) :
+ FormWidget(docA, aobj, num, ref, p)
+{
+ type = formButton;
+ parent = static_cast<FormFieldButton*>(field);
+ onStr = NULL;
+
+ Object obj1, obj2;
+
+ // Find the name of the ON state in the AP dictionnary
+ // The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off
+ // The "on" state may be stored under any other name
+ if (obj.dictLookup("AP", &obj1)->isDict()) {
+ if (obj1.dictLookup("N", &obj2)->isDict()) {
+ for (int i = 0; i < obj2.dictGetLength(); i++) {
+ char *key = obj2.dictGetKey(i);
+ if (strcmp (key, "Off") != 0) {
+ onStr = new GooString (key);
+ break;
+ }
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+}
+
+char *FormWidgetButton::getOnStr() {
+ if (onStr)
+ return onStr->getCString();
+
+ // 12.7.4.2.3 Check Boxes
+ // Yes should be used as the name for the on state
+ return parent->getButtonType() == formButtonCheck ? (char *)"Yes" : NULL;
+}
+
+FormWidgetButton::~FormWidgetButton ()
+{
+ delete onStr;
+}
+
+FormButtonType FormWidgetButton::getButtonType () const
+{
+ return parent->getButtonType ();
+}
+
+void FormWidgetButton::setAppearanceState(const char *state) {
+ if (!widget)
+ return;
+ widget->setAppearanceState(state);
+}
+
+void FormWidgetButton::updateWidgetAppearance()
+{
+ // The appearance stream must NOT be regenerated for this widget type
+}
+
+void FormWidgetButton::setState (GBool astate)
+{
+ //pushButtons don't have state
+ if (parent->getButtonType() == formButtonPush)
+ return;
+
+ // Silently return if can't set ON state
+ if (astate && !onStr)
+ return;
+
+ parent->setState(astate ? onStr->getCString() : (char *)"Off");
+ // Parent will call setAppearanceState()
+}
+
+GBool FormWidgetButton::getState ()
+{
+ return onStr ? parent->getState(onStr->getCString()) : gFalse;
+}
+
+
+FormWidgetText::FormWidgetText (PDFDoc *docA, Object *aobj, unsigned num, Ref ref, FormField *p) :
+ FormWidget(docA, aobj, num, ref, p)
+{
+ type = formText;
+ parent = static_cast<FormFieldText*>(field);
+}
+
+GooString* FormWidgetText::getContent ()
+{
+ return parent->getContent();
+}
+
+GooString* FormWidgetText::getContentCopy ()
+{
+ return parent->getContentCopy();
+}
+
+void FormWidgetText::updateWidgetAppearance()
+{
+ if (widget)
+ widget->updateAppearanceStream();
+}
+
+bool FormWidgetText::isMultiline () const
+{
+ return parent->isMultiline();
+}
+
+bool FormWidgetText::isPassword () const
+{
+ return parent->isPassword();
+}
+
+bool FormWidgetText::isFileSelect () const
+{
+ return parent->isFileSelect();
+}
+
+bool FormWidgetText::noSpellCheck () const
+{
+ return parent->noSpellCheck();
+}
+
+bool FormWidgetText::noScroll () const
+{
+ return parent->noScroll();
+}
+
+bool FormWidgetText::isComb () const
+{
+ return parent->isComb();
+}
+
+bool FormWidgetText::isRichText () const
+{
+ return parent->isRichText();
+}
+
+int FormWidgetText::getMaxLen () const
+{
+ return parent->getMaxLen ();
+}
+
+void FormWidgetText::setContent(GooString* new_content)
+{
+ if (isReadOnly()) {
+ error(errInternal, -1, "FormWidgetText::setContentCopy called on a read only field\n");
+ return;
+ }
+
+ parent->setContentCopy(new_content);
+}
+
+FormWidgetChoice::FormWidgetChoice(PDFDoc *docA, Object *aobj, unsigned num, Ref ref, FormField *p) :
+ FormWidget(docA, aobj, num, ref, p)
+{
+ type = formChoice;
+ parent = static_cast<FormFieldChoice*>(field);
+}
+
+FormWidgetChoice::~FormWidgetChoice()
+{
+}
+
+bool FormWidgetChoice::_checkRange (int i)
+{
+ if (i < 0 || i >= parent->getNumChoices()) {
+ error(errInternal, -1, "FormWidgetChoice::_checkRange i out of range : {0:d}", i);
+ return false;
+ }
+ return true;
+}
+
+void FormWidgetChoice::select (int i)
+{
+ if (isReadOnly()) {
+ error(errInternal, -1, "FormWidgetChoice::select called on a read only field\n");
+ return;
+ }
+ if (!_checkRange(i)) return;
+ parent->select(i);
+}
+
+void FormWidgetChoice::toggle (int i)
+{
+ if (isReadOnly()) {
+ error(errInternal, -1, "FormWidgetChoice::toggle called on a read only field\n");
+ return;
+ }
+ if (!_checkRange(i)) return;
+ parent->toggle(i);
+}
+
+void FormWidgetChoice::deselectAll ()
+{
+ if (isReadOnly()) {
+ error(errInternal, -1, "FormWidgetChoice::deselectAll called on a read only field\n");
+ return;
+ }
+ parent->deselectAll();
+}
+
+GooString* FormWidgetChoice::getEditChoice ()
+{
+ if (!hasEdit()) {
+ error(errInternal, -1, "FormFieldChoice::getEditChoice called on a non-editable choice\n");
+ return NULL;
+ }
+ return parent->getEditChoice();
+}
+
+void FormWidgetChoice::updateWidgetAppearance()
+{
+ if (widget)
+ widget->updateAppearanceStream();
+}
+
+bool FormWidgetChoice::isSelected (int i)
+{
+ if (!_checkRange(i)) return false;
+ return parent->isSelected(i);
+}
+
+void FormWidgetChoice::setEditChoice (GooString* new_content)
+{
+ if (isReadOnly()) {
+ error(errInternal, -1, "FormWidgetText::setEditChoice called on a read only field\n");
+ return;
+ }
+ if (!hasEdit()) {
+ error(errInternal, -1, "FormFieldChoice::setEditChoice : trying to edit an non-editable choice\n");
+ return;
+ }
+
+ parent->setEditChoice(new_content);
+}
+
+int FormWidgetChoice::getNumChoices()
+{
+ return parent->getNumChoices();
+}
+
+GooString* FormWidgetChoice::getChoice(int i)
+{
+ return parent->getChoice(i);
+}
+
+bool FormWidgetChoice::isCombo () const
+{
+ return parent->isCombo();
+}
+
+bool FormWidgetChoice::hasEdit () const
+{
+ return parent->hasEdit();
+}
+
+bool FormWidgetChoice::isMultiSelect () const
+{
+ return parent->isMultiSelect();
+}
+
+bool FormWidgetChoice::noSpellCheck () const
+{
+ return parent->noSpellCheck();
+}
+
+bool FormWidgetChoice::commitOnSelChange () const
+{
+ return parent->commitOnSelChange();
+}
+
+bool FormWidgetChoice::isListBox () const
+{
+ return parent->isListBox();
+}
+
+FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned num, Ref ref, FormField *p) :
+ FormWidget(docA, aobj, num, ref, p)
+{
+ type = formSignature;
+ parent = static_cast<FormFieldSignature*>(field);
+}
+
+void FormWidgetSignature::updateWidgetAppearance()
+{
+ // Unimplemented
+}
+
+
+//========================================================================
+// FormField
+//========================================================================
+
+FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *parentA, std::set<int> *usedParents, FormFieldType ty)
+{
+ doc = docA;
+ xref = doc->getXRef();
+ aobj->copy(&obj);
+ Dict* dict = obj.getDict();
+ ref.num = ref.gen = 0;
+ type = ty;
+ parent = parentA;
+ numChildren = 0;
+ children = NULL;
+ terminal = false;
+ widgets = NULL;
+ readOnly = false;
+ defaultAppearance = NULL;
+ fullyQualifiedName = NULL;
+ quadding = quaddingLeftJustified;
+ hasQuadding = gFalse;
+
+ ref = aref;
+
+ Object obj1;
+ //childs
+ if (dict->lookup("Kids", &obj1)->isArray()) {
+ // Load children
+ for (int i = 0 ; i < obj1.arrayGetLength(); i++) {
+ Object childRef, childObj;
+
+ if (!obj1.arrayGetNF(i, &childRef)->isRef()) {
+ error (errSyntaxError, -1, "Invalid form field renference");
+ childRef.free();
+ continue;
+ }
+ if (!obj1.arrayGet(i, &childObj)->isDict()) {
+ error (errSyntaxError, -1, "Form field child is not a dictionary");
+ childObj.free();
+ childRef.free();
+ continue;
+ }
+
+ const Ref ref = childRef.getRef();
+ if (usedParents->find(ref.num) == usedParents->end()) {
+ Object obj2, obj3;
+ // Field child: it could be a form field or a widget or composed dict
+ if (childObj.dictLookupNF("Parent", &obj2)->isRef() || childObj.dictLookup("Parent", &obj3)->isDict()) {
+ // Child is a form field or composed dict
+ // We create the field, if it's composed
+ // it will create the widget as a child
+ std::set<int> usedParentsAux = *usedParents;
+ usedParentsAux.insert(ref.num);
+ obj2.free();
+ obj3.free();
+
+ if (terminal) {
+ error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n");
+ continue;
+ }
+
+ numChildren++;
+ children = (FormField**)greallocn(children, numChildren, sizeof(FormField*));
+ children[numChildren - 1] = Form::createFieldFromDict(&childObj, doc, ref, this, &usedParentsAux);
+ } else if (childObj.dictLookup("Subtype", &obj2)->isName("Widget")) {
+ // Child is a widget annotation
+ if (!terminal && numChildren > 0) {
+ error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n");
+ obj2.free();
+ obj3.free();
+ continue;
+ }
+ _createWidget(&childObj, ref);
+ }
+ obj2.free();
+ obj3.free();
+ }
+ childObj.free();
+ childRef.free();
+ }
+ } else {
+ // No children, if it's a composed dict, create the child widget
+ obj1.free();
+ if (dict->lookup("Subtype", &obj1)->isName("Widget"))
+ _createWidget(&obj, ref);
+ }
+ obj1.free();
+
+ //flags
+ if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+ int flags = obj1.getInt();
+ if (flags & 0x1) { // 1 -> ReadOnly
+ readOnly = true;
+ }
+ if (flags & 0x2) { // 2 -> Required
+ //TODO
+ }
+ if (flags & 0x4) { // 3 -> NoExport
+ //TODO
+ }
+ }
+ obj1.free();
+
+ // Variable Text
+ if (Form::fieldLookup(dict, "DA", &obj1)->isString())
+ defaultAppearance = obj1.getString()->copy();
+ obj1.free();
+
+ if (Form::fieldLookup(dict, "Q", &obj1)->isInt()) {
+ quadding = static_cast<VariableTextQuadding>(obj1.getInt());
+ hasQuadding = gTrue;
+ }
+ obj1.free();
+
+ if (dict->lookup("T", &obj1)->isString()) {
+ partialName = obj1.getString()->copy();
+ } else {
+ partialName = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("TU", &obj1)->isString()) {
+ alternateUiName = obj1.getString()->copy();
+ } else {
+ alternateUiName = NULL;
+ }
+ obj1.free();
+
+ if(dict->lookup("TM", &obj1)->isString()) {
+ mappingName = obj1.getString()->copy();
+ } else {
+ mappingName = NULL;
+ }
+ obj1.free();
+}
+
+FormField::~FormField()
+{
+ if (!terminal) {
+ if(children) {
+ for (int i=0; i<numChildren; i++)
+ delete children[i];
+ gfree(children);
+ }
+ } else {
+ for (int i = 0; i < numChildren; ++i)
+ delete widgets[i];
+ gfree (widgets);
+ }
+ obj.free();
+
+ delete defaultAppearance;
+ delete partialName;
+ delete alternateUiName;
+ delete mappingName;
+ delete fullyQualifiedName;
+}
+
+#ifdef DEBUG_FORMS
+void FormField::print(int indent)
+{
+ printf ("%*s- (%d %d): [container] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+ terminal ? "Yes" : "No", numChildren);
+}
+
+void FormField::printTree(int indent)
+{
+ print(indent);
+ if (terminal) {
+ for (int i = 0; i < numChildren; i++)
+ widgets[i]->print(indent + 4);
+ } else {
+ for (int i = 0; i < numChildren; i++)
+ children[i]->printTree(indent + 4);
+ }
+}
+#endif
+
+void FormField::fillChildrenSiblingsID()
+{
+ if (terminal)
+ return;
+ for (int i = 0; i < numChildren; i++) {
+ children[i]->fillChildrenSiblingsID();
+ }
+}
+
+void FormField::createWidgetAnnotations() {
+ if (terminal) {
+ for (int i = 0; i < numChildren; i++)
+ widgets[i]->createWidgetAnnotation();
+ } else {
+ for (int i = 0; i < numChildren; i++)
+ children[i]->createWidgetAnnotations();
+ }
+}
+
+void FormField::_createWidget (Object *obj, Ref aref)
+{
+ terminal = true;
+ numChildren++;
+ widgets = (FormWidget**)greallocn(widgets, numChildren, sizeof(FormWidget*));
+ //ID = index in "widgets" table
+ switch (type) {
+ case formButton:
+ widgets[numChildren-1] = new FormWidgetButton(doc, obj, numChildren-1, aref, this);
+ break;
+ case formText:
+ widgets[numChildren-1] = new FormWidgetText(doc, obj, numChildren-1, aref, this);
+ break;
+ case formChoice:
+ widgets[numChildren-1] = new FormWidgetChoice(doc, obj, numChildren-1, aref, this);
+ break;
+ case formSignature:
+ widgets[numChildren-1] = new FormWidgetSignature(doc, obj, numChildren-1, aref, this);
+ break;
+ default:
+ error(errSyntaxWarning, -1, "SubType on non-terminal field, invalid document?");
+ numChildren--;
+ terminal = false;
+ }
+}
+
+FormWidget* FormField::findWidgetByRef (Ref aref)
+{
+ if (terminal) {
+ for(int i=0; i<numChildren; i++) {
+ if (widgets[i]->getRef().num == aref.num
+ && widgets[i]->getRef().gen == aref.gen)
+ return widgets[i];
+ }
+ } else {
+ for(int i=0; i<numChildren; i++) {
+ FormWidget* result = children[i]->findWidgetByRef(aref);
+ if(result) return result;
+ }
+ }
+ return NULL;
+}
+
+GooString* FormField::getFullyQualifiedName() {
+ Object obj1, obj2;
+ Object parent;
+ GooString *parent_name;
+ GooString *full_name;
+ GBool unicode_encoded = gFalse;
+
+ if (fullyQualifiedName)
+ return fullyQualifiedName;
+
+ full_name = new GooString();
+
+ obj.copy(&obj1);
+ while (obj1.dictLookup("Parent", &parent)->isDict()) {
+ if (parent.dictLookup("T", &obj2)->isString()) {
+ parent_name = obj2.getString();
+
+ if (unicode_encoded) {
+ full_name->insert(0, "\0.", 2); // 2-byte unicode period
+ if (parent_name->hasUnicodeMarker()) {
+ full_name->insert(0, parent_name->getCString() + 2, parent_name->getLength() - 2); // Remove the unicode BOM
+ } else {
+ int tmp_length;
+ char* tmp_str = pdfDocEncodingToUTF16(parent_name, &tmp_length);
+ full_name->insert(0, tmp_str + 2, tmp_length - 2); // Remove the unicode BOM
+ delete [] tmp_str;
+ }
+ } else {
+ full_name->insert(0, '.'); // 1-byte ascii period
+ if (parent_name->hasUnicodeMarker()) {
+ unicode_encoded = gTrue;
+ full_name = convertToUtf16(full_name);
+ full_name->insert(0, parent_name->getCString() + 2, parent_name->getLength() - 2); // Remove the unicode BOM
+ } else {
+ full_name->insert(0, parent_name);
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ parent.copy(&obj1);
+ parent.free();
+ }
+ obj1.free();
+ parent.free();
+
+ if (partialName) {
+ if (unicode_encoded) {
+ if (partialName->hasUnicodeMarker()) {
+ full_name->append(partialName->getCString() + 2, partialName->getLength() - 2); // Remove the unicode BOM
+ } else {
+ int tmp_length;
+ char* tmp_str = pdfDocEncodingToUTF16(partialName, &tmp_length);
+ full_name->append(tmp_str + 2, tmp_length - 2); // Remove the unicode BOM
+ delete [] tmp_str;
+ }
+ } else {
+ if (partialName->hasUnicodeMarker()) {
+ unicode_encoded = gTrue;
+ full_name = convertToUtf16(full_name);
+ full_name->append(partialName->getCString() + 2, partialName->getLength() - 2); // Remove the unicode BOM
+ } else {
+ full_name->append(partialName);
+ }
+ }
+ } else {
+ int len = full_name->getLength();
+ // Remove the last period
+ if (unicode_encoded) {
+ if (len > 1) {
+ full_name->del(len - 2, 2);
+ }
+ } else {
+ if (len > 0) {
+ full_name->del(len - 1, 1);
+ }
+ }
+ }
+
+ if (unicode_encoded) {
+ full_name->insert(0, 0xff);
+ full_name->insert(0, 0xfe);
+ }
+
+ fullyQualifiedName = full_name;
+ return fullyQualifiedName;
+}
+
+void FormField::updateChildrenAppearance()
+{
+ // Recursively update each child's appearance
+ if (terminal) {
+ for (int i = 0; i < numChildren; i++)
+ widgets[i]->updateWidgetAppearance();
+ } else {
+ for (int i = 0; i < numChildren; i++)
+ children[i]->updateChildrenAppearance();
+ }
+}
+
+//------------------------------------------------------------------------
+// FormFieldButton
+//------------------------------------------------------------------------
+FormFieldButton::FormFieldButton(PDFDoc *docA, Object *aobj, const Ref& ref, FormField *parent, std::set<int> *usedParents)
+ : FormField(docA, aobj, ref, parent, usedParents, formButton)
+{
+ Dict* dict = obj.getDict();
+ active_child = -1;
+ noAllOff = false;
+ siblings = NULL;
+ numSiblings = 0;
+ appearanceState.initNull();
+
+ Object obj1;
+ btype = formButtonCheck;
+ if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+ int flags = obj1.getInt();
+
+ if (flags & 0x10000) { // 17 -> push button
+ btype = formButtonPush;
+ } else if (flags & 0x8000) { // 16 -> radio button
+ btype = formButtonRadio;
+ if (flags & 0x4000) { // 15 -> noToggleToOff
+ noAllOff = true;
+ }
+ }
+ if (flags & 0x1000000) { // 26 -> radiosInUnison
+ error(errUnimplemented, -1, "FormFieldButton:: radiosInUnison flag unimplemented, please report a bug with a testcase\n");
+ }
+ }
+
+ if (btype != formButtonPush) {
+ // Even though V is inheritable we are interested in the value of this
+ // field, if not present it's probably because it's a button in a set.
+ dict->lookup("V", &appearanceState);
+ }
+}
+
+#ifdef DEBUG_FORMS
+static char *_getButtonType(FormButtonType type)
+{
+ switch (type) {
+ case formButtonPush:
+ return "push";
+ case formButtonCheck:
+ return "check";
+ case formButtonRadio:
+ return "radio";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
+void FormFieldButton::print(int indent)
+{
+ printf ("%*s- (%d %d): [%s] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+ _getButtonType(btype), terminal ? "Yes" : "No", numChildren);
+}
+#endif
+
+void FormFieldButton::setNumSiblings (int num)
+{
+ numSiblings = num;
+ siblings = (FormFieldButton**)greallocn(siblings, numSiblings, sizeof(FormFieldButton*));
+}
+
+void FormFieldButton::fillChildrenSiblingsID()
+{
+ if (!terminal) {
+ for(int i=0; i<numChildren; i++) {
+ FormFieldButton *child = dynamic_cast<FormFieldButton*>(children[i]);
+ if (child != NULL) {
+ // Fill the siblings of this node childs
+ child->setNumSiblings(numChildren-1);
+ for(int j=0, counter=0; j<numChildren; j++) {
+ FormFieldButton *otherChild = dynamic_cast<FormFieldButton*>(children[j]);
+ if (i == j) continue;
+ if (child == otherChild) continue;
+ child->setSibling(counter, otherChild);
+ counter++;
+ }
+
+ // now call ourselves on the child
+ // to fill its children data
+ child->fillChildrenSiblingsID();
+ }
+ }
+ }
+}
+
+GBool FormFieldButton::setState(char *state)
+{
+ if (readOnly) {
+ error(errInternal, -1, "FormFieldButton::setState called on a readOnly field\n");
+ return gFalse;
+ }
+
+ // A check button could behave as a radio button
+ // when it's in a set of more than 1 buttons
+ if (btype != formButtonRadio && btype != formButtonCheck)
+ return gFalse;
+
+ if (terminal && parent && parent->getType() == formButton && appearanceState.isNull()) {
+ // It's button in a set, set state on parent
+ if (static_cast<FormFieldButton*>(parent)->setState(state)) {
+ return gTrue;
+ }
+ return gFalse;
+ }
+
+ GBool isOn = strcmp(state, "Off") != 0;
+
+ if (!isOn && noAllOff)
+ return gFalse; // Don't allow to set all radio to off
+
+ char *current = getAppearanceState();
+ GBool currentFound = gFalse, newFound = gFalse;
+
+ for (int i = 0; i < numChildren; i++) {
+ FormWidgetButton *widget;
+
+ // If radio button is a terminal field we want the widget at i, but
+ // if it's not terminal, the child widget is a composed dict, so
+ // we want the ony child widget of the children at i
+ if (terminal)
+ widget = static_cast<FormWidgetButton*>(widgets[i]);
+ else
+ widget = static_cast<FormWidgetButton*>(children[i]->getWidget(0));
+
+ if (!widget->getOnStr())
+ continue;
+
+ char *onStr = widget->getOnStr();
+ if (current && strcmp(current, onStr) == 0) {
+ widget->setAppearanceState("Off");
+ if (!isOn)
+ break;
+ currentFound = gTrue;
+ }
+
+ if (isOn && strcmp(state, onStr) == 0) {
+ widget->setAppearanceState(state);
+ newFound = gTrue;
+ }
+
+ if (currentFound && newFound)
+ break;
+ }
+
+ updateState(state);
+
+ return gTrue;
+}
+
+GBool FormFieldButton::getState(char *state) {
+ if (appearanceState.isName(state))
+ return gTrue;
+
+ return (parent && parent->getType() == formButton) ? static_cast<FormFieldButton*>(parent)->getState(state) : gFalse;
+}
+
+void FormFieldButton::updateState(char *state) {
+ Object obj1;
+
+ appearanceState.free();
+ appearanceState.initName(state);
+
+ appearanceState.copy(&obj1);
+ obj.getDict()->set("V", &obj1);
+ xref->setModifiedObject(&obj, ref);
+}
+
+FormFieldButton::~FormFieldButton()
+{
+ appearanceState.free();
+ if (siblings)
+ gfree(siblings);
+}
+
+//------------------------------------------------------------------------
+// FormFieldText
+//------------------------------------------------------------------------
+FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormField *parent, std::set<int> *usedParents)
+ : FormField(docA, aobj, ref, parent, usedParents, formText)
+{
+ Dict* dict = obj.getDict();
+ Object obj1;
+ content = NULL;
+ multiline = password = fileSelect = doNotSpellCheck = doNotScroll = comb = richText = false;
+ maxLen = 0;
+
+ if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+ int flags = obj1.getInt();
+ if (flags & 0x1000) // 13 -> Multiline
+ multiline = true;
+ if (flags & 0x2000) // 14 -> Password
+ password = true;
+ if (flags & 0x100000) // 21 -> FileSelect
+ fileSelect = true;
+ if (flags & 0x400000)// 23 -> DoNotSpellCheck
+ doNotSpellCheck = true;
+ if (flags & 0x800000) // 24 -> DoNotScroll
+ doNotScroll = true;
+ if (flags & 0x1000000) // 25 -> Comb
+ comb = true;
+ if (flags & 0x2000000)// 26 -> RichText
+ richText = true;
+ }
+ obj1.free();
+
+ if (Form::fieldLookup(dict, "MaxLen", &obj1)->isInt()) {
+ maxLen = obj1.getInt();
+ }
+ obj1.free();
+
+ if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
+ if (obj1.getString()->hasUnicodeMarker()) {
+ if (obj1.getString()->getLength() > 2)
+ content = obj1.getString()->copy();
+ } else if (obj1.getString()->getLength() > 0) {
+ //non-unicode string -- assume pdfDocEncoding and try to convert to UTF16BE
+ int tmp_length;
+ char* tmp_str = pdfDocEncodingToUTF16(obj1.getString(), &tmp_length);
+ content = new GooString(tmp_str, tmp_length);
+ delete [] tmp_str;
+ }
+ }
+ obj1.free();
+}
+
+#ifdef DEBUG_FORMS
+void FormFieldText::print(int indent)
+{
+ printf ("%*s- (%d %d): [text] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+ terminal ? "Yes" : "No", numChildren);
+}
+#endif
+
+GooString* FormFieldText::getContentCopy ()
+{
+ if (!content) return NULL;
+ return new GooString(content);
+}
+
+void FormFieldText::setContentCopy (GooString* new_content)
+{
+ delete content;
+ content = NULL;
+
+ if (new_content) {
+ content = new_content->copy();
+
+ //append the unicode marker <FE FF> if needed
+ if (!content->hasUnicodeMarker()) {
+ content->insert(0, 0xff);
+ content->insert(0, 0xfe);
+ }
+ }
+
+ Object obj1;
+ obj1.initString(content ? content->copy() : new GooString(""));
+ obj.getDict()->set("V", &obj1);
+ xref->setModifiedObject(&obj, ref);
+ updateChildrenAppearance();
+}
+
+FormFieldText::~FormFieldText()
+{
+ delete content;
+}
+
+
+//------------------------------------------------------------------------
+// FormFieldChoice
+//------------------------------------------------------------------------
+FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, FormField *parent, std::set<int> *usedParents)
+ : FormField(docA, aobj, ref, parent, usedParents, formChoice)
+{
+ numChoices = 0;
+ choices = NULL;
+ editedChoice = NULL;
+ topIdx = 0;
+
+ Dict* dict = obj.getDict();
+ Object obj1;
+
+ combo = edit = multiselect = doNotSpellCheck = doCommitOnSelChange = false;
+
+ if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+ int flags = obj1.getInt();
+ if (flags & 0x20000) // 18 -> Combo
+ combo = true;
+ if (flags & 0x40000) // 19 -> Edit
+ edit = true;
+ if (flags & 0x200000) // 22 -> MultiSelect
+ multiselect = true;
+ if (flags & 0x400000) // 23 -> DoNotSpellCheck
+ doNotSpellCheck = true;
+ if (flags & 0x4000000) // 27 -> CommitOnSelChange
+ doCommitOnSelChange = true;
+ }
+ obj1.free();
+
+ if (dict->lookup("TI", &obj1)->isInt())
+ topIdx = obj1.getInt();
+ obj1.free();
+
+ if (dict->lookup("Opt", &obj1)->isArray()) {
+ Object obj2;
+
+ numChoices = obj1.arrayGetLength();
+ choices = new ChoiceOpt[numChoices];
+ memset(choices, 0, sizeof(ChoiceOpt) * numChoices);
+
+ for (int i = 0; i < numChoices; i++) {
+ if (obj1.arrayGet(i, &obj2)->isString()) {
+ choices[i].optionName = obj2.getString()->copy();
+ } else if (obj2.isArray()) { // [Export_value, Displayed_text]
+ Object obj3;
+
+ if (obj2.arrayGetLength() < 2) {
+ error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- array's length < 2\n");
+ continue;
+ }
+ if (obj2.arrayGet(0, &obj3)->isString())
+ choices[i].exportVal = obj3.getString()->copy();
+ else
+ error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- exported value not a string\n");
+ obj3.free();
+
+ if (obj2.arrayGet(1, &obj3)->isString())
+ choices[i].optionName = obj3.getString()->copy();
+ else
+ error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- choice name not a string\n");
+ obj3.free();
+ } else {
+ error(errSyntaxError, -1, "FormWidgetChoice:: invalid {0:d} Opt entry\n", i);
+ }
+ obj2.free();
+ }
+ } else {
+ //empty choice
+ }
+ obj1.free();
+
+ // Find selected items
+ // Note: PDF specs say that /V has precedence over /I, but acroread seems to
+ // do the opposite. We do the same.
+ if (Form::fieldLookup(dict, "I", &obj1)->isArray()) {
+ for (int i = 0; i < obj1.arrayGetLength(); i++) {
+ Object obj2;
+ if (obj1.arrayGet(i, &obj2)->isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) {
+ choices[obj2.getInt()].selected = true;
+ }
+ obj2.free();
+ }
+ } else {
+ obj1.free();
+ // Note: According to PDF specs, /V should *never* contain the exportVal.
+ // However, if /Opt is an array of (exportVal,optionName) pairs, acroread
+ // seems to expect the exportVal instead of the optionName and so we do too.
+ if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
+ GBool optionFound = gFalse;
+
+ for (int i = 0; i < numChoices; i++) {
+ if (choices[i].exportVal) {
+ if (choices[i].exportVal->cmp(obj1.getString()) == 0) {
+ optionFound = gTrue;
+ }
+ } else if (choices[i].optionName) {
+ if (choices[i].optionName->cmp(obj1.getString()) == 0) {
+ optionFound = gTrue;
+ }
+ }
+
+ if (optionFound) {
+ choices[i].selected = true;
+ break; // We've determined that this option is selected. No need to keep on scanning
+ }
+ }
+
+ // Set custom value if /V doesn't refer to any predefined option and the field is user-editable
+ if (!optionFound && edit) {
+ editedChoice = obj1.getString()->copy();
+ }
+ } else if (obj1.isArray()) {
+ for (int i = 0; i < numChoices; i++) {
+ for (int j = 0; j < obj1.arrayGetLength(); j++) {
+ Object obj2;
+ obj1.arrayGet(j, &obj2);
+ GBool matches = gFalse;
+
+ if (choices[i].exportVal) {
+ if (choices[i].exportVal->cmp(obj2.getString()) == 0) {
+ matches = gTrue;
+ }
+ } else if (choices[i].optionName) {
+ if (choices[i].optionName->cmp(obj2.getString()) == 0) {
+ matches = gTrue;
+ }
+ }
+
+ obj2.free();
+
+ if (matches) {
+ choices[i].selected = true;
+ break; // We've determined that this option is selected. No need to keep on scanning
+ }
+ }
+ }
+ }
+ }
+ obj1.free();
+}
+
+FormFieldChoice::~FormFieldChoice()
+{
+ for (int i = 0; i < numChoices; i++) {
+ delete choices[i].exportVal;
+ delete choices[i].optionName;
+ }
+ delete [] choices;
+ delete editedChoice;
+}
+
+#ifdef DEBUG_FORMS
+void FormFieldChoice::print(int indent)
+{
+ printf ("%*s- (%d %d): [choice] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+ terminal ? "Yes" : "No", numChildren);
+}
+#endif
+
+void FormFieldChoice::updateSelection() {
+ Object objV, objI, obj1;
+ objI.initNull();
+
+ if (edit && editedChoice) {
+ // This is an editable combo-box with user-entered text
+ objV.initString(editedChoice->copy());
+ } else {
+ const int numSelected = getNumSelected();
+
+ // Create /I array only if multiple selection is allowed (as per PDF spec)
+ if (multiselect) {
+ objI.initArray(xref);
+ }
+
+ if (numSelected == 0) {
+ // No options are selected
+ objV.initString(new GooString(""));
+ } else if (numSelected == 1) {
+ // Only one option is selected
+ for (int i = 0; i < numChoices; i++) {
+ if (choices[i].selected) {
+ if (multiselect) {
+ objI.arrayAdd(obj1.initInt(i));
+ }
+
+ if (choices[i].exportVal) {
+ objV.initString(choices[i].exportVal->copy());
+ } else if (choices[i].optionName) {
+ objV.initString(choices[i].optionName->copy());
+ }
+
+ break; // We've just written the selected option. No need to keep on scanning
+ }
+ }
+ } else {
+ // More than one option is selected
+ objV.initArray(xref);
+ for (int i = 0; i < numChoices; i++) {
+ if (choices[i].selected) {
+ if (multiselect) {
+ objI.arrayAdd(obj1.initInt(i));
+ }
+
+ if (choices[i].exportVal) {
+ objV.arrayAdd(obj1.initString(choices[i].exportVal->copy()));
+ } else if (choices[i].optionName) {
+ objV.arrayAdd(obj1.initString(choices[i].optionName->copy()));
+ }
+ }
+ }
+ }
+ }
+
+ obj.getDict()->set("V", &objV);
+ obj.getDict()->set("I", &objI);
+ xref->setModifiedObject(&obj, ref);
+ updateChildrenAppearance();
+}
+
+void FormFieldChoice::unselectAll ()
+{
+ for (int i = 0; i < numChoices; i++) {
+ choices[i].selected = false;
+ }
+}
+
+void FormFieldChoice::deselectAll () {
+ delete editedChoice;
+ editedChoice = NULL;
+
+ unselectAll();
+ updateSelection();
+}
+
+void FormFieldChoice::toggle (int i)
+{
+ delete editedChoice;
+ editedChoice = NULL;
+
+ choices[i].selected = !choices[i].selected;
+ updateSelection();
+}
+
+void FormFieldChoice::select (int i)
+{
+ delete editedChoice;
+ editedChoice = NULL;
+
+ if (!multiselect)
+ unselectAll();
+
+ choices[i].selected = true;
+ updateSelection();
+}
+
+void FormFieldChoice::setEditChoice (GooString* new_content)
+{
+ delete editedChoice;
+ editedChoice = NULL;
+
+ unselectAll();
+
+ if (new_content) {
+ editedChoice = new_content->copy();
+
+ //append the unicode marker <FE FF> if needed
+ if (!editedChoice->hasUnicodeMarker()) {
+ editedChoice->insert(0, 0xff);
+ editedChoice->insert(0, 0xfe);
+ }
+ }
+ updateSelection();
+}
+
+GooString* FormFieldChoice::getEditChoice ()
+{
+ return editedChoice;
+}
+
+int FormFieldChoice::getNumSelected ()
+{
+ int cnt = 0;
+ for(int i=0; i<numChoices; i++) {
+ if (choices[i].selected)
+ cnt++;
+ }
+ return cnt;
+}
+
+GooString *FormFieldChoice::getSelectedChoice() {
+ if (edit && editedChoice)
+ return editedChoice;
+
+ for (int i = 0; i < numChoices; i++) {
+ if (choices[i].optionName && choices[i].selected)
+ return choices[i].optionName;
+ }
+
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+// FormFieldSignature
+//------------------------------------------------------------------------
+FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents)
+ : FormField(docA, dict, ref, parent, usedParents, formSignature)
+{
+}
+
+FormFieldSignature::~FormFieldSignature()
+{
+
+}
+
+#ifdef DEBUG_FORMS
+void FormFieldSignature::print(int indent)
+{
+ printf ("%*s- (%d %d): [signature] terminal: %s children: %d\n", indent, "", ref.num, ref.gen,
+ terminal ? "Yes" : "No", numChildren);
+}
+#endif
+
+//------------------------------------------------------------------------
+// Form
+//------------------------------------------------------------------------
+
+Form::Form(PDFDoc *docA, Object* acroFormA)
+{
+ Object obj1;
+
+ doc = docA;
+ xref = doc->getXRef();
+ acroForm = acroFormA;
+
+ size = 0;
+ numFields = 0;
+ rootFields = NULL;
+ quadding = quaddingLeftJustified;
+ defaultAppearance = NULL;
+ defaultResources = NULL;
+
+ acroForm->dictLookup("NeedAppearances", &obj1);
+ needAppearances = (obj1.isBool() && obj1.getBool());
+ obj1.free();
+
+ if (acroForm->dictLookup("DA", &obj1)->isString())
+ defaultAppearance = obj1.getString()->copy();
+ obj1.free();
+
+ if (acroForm->dictLookup("Q", &obj1)->isInt())
+ quadding = static_cast<VariableTextQuadding>(obj1.getInt());
+ obj1.free();
+
+ acroForm->dictLookup("DR", &resDict);
+ if (resDict.isDict()) {
+ // At a minimum, this dictionary shall contain a Font entry
+ if (resDict.dictLookup("Font", &obj1)->isDict())
+ defaultResources = new GfxResources(xref, resDict.getDict(), NULL);
+ obj1.free();
+ }
+ if (!defaultResources) {
+ resDict.free();
+ resDict.initNull();
+ }
+
+ acroForm->dictLookup("Fields", &obj1);
+ if (obj1.isArray()) {
+ Array *array = obj1.getArray();
+ Object obj2;
+
+ for(int i=0; i<array->getLength(); i++) {
+ Object oref;
+ array->get(i, &obj2);
+ array->getNF(i, &oref);
+ if (!oref.isRef()) {
+ error(errSyntaxWarning, -1, "Direct object in rootFields");
+ obj2.free();
+ oref.free();
+ continue;
+ }
+
+ if (!obj2.isDict()) {
+ error(errSyntaxWarning, -1, "Reference in Fields array to an invalid or non existent object");
+ obj2.free();
+ oref.free();
+ continue;
+ }
+
+ if (numFields >= size) {
+ size += 16;
+ rootFields = (FormField**)greallocn(rootFields,size,sizeof(FormField*));
+ }
+
+ std::set<int> usedParents;
+ rootFields[numFields++] = createFieldFromDict (&obj2, doc, oref.getRef(), NULL, &usedParents);
+
+ obj2.free();
+ oref.free();
+ }
+ } else {
+ error(errSyntaxError, -1, "Can't get Fields array\n");
+ }
+ obj1.free ();
+
+#ifdef DEBUG_FORMS
+ for (int i = 0; i < numFields; i++)
+ rootFields[i]->printTree();
+#endif
+}
+
+Form::~Form() {
+ int i;
+ for(i = 0; i< numFields; ++i)
+ delete rootFields[i];
+ gfree (rootFields);
+ delete defaultAppearance;
+ delete defaultResources;
+ resDict.free();
+}
+
+// Look up an inheritable field dictionary entry.
+static Object *fieldLookup(Dict *field, const char *key, Object *obj, std::set<int> *usedParents) {
+ Dict *dict;
+ Object parent;
+
+ dict = field;
+ if (!dict->lookup(key, obj)->isNull()) {
+ return obj;
+ }
+ obj->free();
+ dict->lookupNF("Parent", &parent);
+ if (parent.isRef()) {
+ const Ref ref = parent.getRef();
+ if (usedParents->find(ref.num) == usedParents->end()) {
+ usedParents->insert(ref.num);
+
+ Object obj2;
+ parent.fetch(dict->getXRef(), &obj2);
+ if (obj2.isDict()) {
+ fieldLookup(obj2.getDict(), key, obj, usedParents);
+ } else {
+ obj->initNull();
+ }
+ obj2.free();
+ }
+ } else if (parent.isDict()) {
+ fieldLookup(parent.getDict(), key, obj, usedParents);
+ } else {
+ obj->initNull();
+ }
+ parent.free();
+ return obj;
+}
+
+Object *Form::fieldLookup(Dict *field, const char *key, Object *obj) {
+ std::set<int> usedParents;
+ return ::fieldLookup(field, key, obj, &usedParents);
+}
+
+FormField *Form::createFieldFromDict (Object* obj, PDFDoc *docA, const Ref& pref, FormField *parent, std::set<int> *usedParents)
+{
+ Object obj2;
+ FormField *field;
+
+ if (Form::fieldLookup(obj->getDict (), "FT", &obj2)->isName("Btn")) {
+ field = new FormFieldButton(docA, obj, pref, parent, usedParents);
+ } else if (obj2.isName("Tx")) {
+ field = new FormFieldText(docA, obj, pref, parent, usedParents);
+ } else if (obj2.isName("Ch")) {
+ field = new FormFieldChoice(docA, obj, pref, parent, usedParents);
+ } else if (obj2.isName("Sig")) {
+ field = new FormFieldSignature(docA, obj, pref, parent, usedParents);
+ } else { //we don't have an FT entry => non-terminal field
+ field = new FormField(docA, obj, pref, parent, usedParents);
+ }
+ obj2.free();
+
+ return field;
+}
+
+void Form::postWidgetsLoad()
+{
+ // We create the widget annotations associated to
+ // every form widget here, because the AnnotWidget constructor
+ // needs the form object that gets from the catalog. When constructing
+ // a FormWidget the Catalog is still creating the form object
+ for (int i = 0; i < numFields; i++) {
+ rootFields[i]->fillChildrenSiblingsID();
+ rootFields[i]->createWidgetAnnotations();
+ }
+}
+
+FormWidget* Form::findWidgetByRef (Ref aref)
+{
+ for(int i=0; i<numFields; i++) {
+ FormWidget *result = rootFields[i]->findWidgetByRef(aref);
+ if(result) return result;
+ }
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+// FormPageWidgets
+//------------------------------------------------------------------------
+
+FormPageWidgets::FormPageWidgets (Annots *annots, unsigned int page, Form *form)
+{
+ numWidgets = 0;
+ widgets = NULL;
+
+ if (annots && annots->getNumAnnots() > 0 && form) {
+ size = annots->getNumAnnots();
+ widgets = (FormWidget**)greallocn(widgets, size, sizeof(FormWidget*));
+
+ /* For each entry in the page 'Annots' dict, try to find
+ a matching form field */
+ for (int i = 0; i < size; ++i) {
+ Annot *annot = annots->getAnnot(i);
+
+ if (annot->getType() != Annot::typeWidget)
+ continue;
+
+ if (!annot->getHasRef()) {
+ /* Since all entry in a form field's kid dict needs to be
+ indirect references, if this annot isn't indirect, it isn't
+ related to a form field */
+ continue;
+ }
+
+ Ref r = annot->getRef();
+
+ /* Try to find a form field which either has this Annot in its Kids entry
+ or is merged with this Annot */
+ FormWidget* tmp = form->findWidgetByRef(r);
+ if (tmp) {
+ // We've found a corresponding form field, link it
+ tmp->setID(FormWidget::encodeID(page, numWidgets));
+ widgets[numWidgets++] = tmp;
+ }
+ }
+ }
+}
+
+FormPageWidgets::~FormPageWidgets()
+{
+ gfree (widgets);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Form.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Form.h
new file mode 100644
index 00000000000..3778ff6f2ef
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Form.h
@@ -0,0 +1,563 @@
+//========================================================================
+//
+// Form.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2006 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright 2007, 2008, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright 2007-2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright 2010 Mark Riedesel <mark@klowner.com>
+// Copyright 2011 Pino Toscano <pino@kde.org>
+// Copyright 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright 2013 Adrian Johnson <ajohnson@redneon.com>
+//
+//========================================================================
+
+#ifndef FORM_H
+#define FORM_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+#include "Annot.h"
+
+#include <set>
+
+class GooString;
+class Array;
+class Dict;
+class Annot;
+class AnnotWidget;
+class Annots;
+class LinkAction;
+class GfxResources;
+class PDFDoc;
+
+enum FormFieldType {
+ formButton,
+ formText,
+ formChoice,
+ formSignature,
+ formUndef
+};
+
+enum FormButtonType {
+ formButtonCheck,
+ formButtonPush,
+ formButtonRadio
+};
+
+enum VariableTextQuadding {
+ quaddingLeftJustified,
+ quaddingCentered,
+ quaddingRightJustified
+};
+
+class Form;
+class FormField;
+class FormFieldButton;
+class FormFieldText;
+class FormFieldSignature;
+class FormFieldChoice;
+
+//------------------------------------------------------------------------
+// FormWidget
+// A FormWidget represents the graphical part of a field and is "attached"
+// to a page.
+//------------------------------------------------------------------------
+
+class FormWidget {
+public:
+ virtual ~FormWidget();
+
+ // Check if point is inside the field bounding rect
+ GBool inRect(double x, double y) const;
+
+ // Get the field bounding rect
+ void getRect(double *x1, double *y1, double *x2, double *y2) const;
+
+ unsigned getID () { return ID; }
+ void setID (unsigned int i) { ID=i; }
+
+ FormField *getField () { return field; }
+ FormFieldType getType() { return type; }
+
+ Object* getObj() { return &obj; }
+ Ref getRef() { return ref; }
+
+ void setChildNum (unsigned i) { childNum = i; }
+ unsigned getChildNum () { return childNum; }
+
+ double getFontSize() const;
+
+ GooString *getPartialName() const;
+ GooString *getAlternateUiName() const;
+ GooString *getMappingName() const;
+ GooString *getFullyQualifiedName();
+
+ GBool isModified () const;
+
+ bool isReadOnly() const;
+
+ LinkAction *getActivationAction();
+ LinkAction *getAdditionalAction(Annot::FormAdditionalActionsType type);
+
+ // return the unique ID corresponding to pageNum/fieldNum
+ static int encodeID (unsigned pageNum, unsigned fieldNum);
+ // decode id and retrieve pageNum and fieldNum
+ static void decodeID (unsigned id, unsigned* pageNum, unsigned* fieldNum);
+
+ void createWidgetAnnotation();
+ AnnotWidget *getWidgetAnnotation() const { return widget; }
+
+ virtual void updateWidgetAppearance() = 0;
+
+#ifdef DEBUG_FORMS
+ void print(int indent = 0);
+#endif
+
+protected:
+ FormWidget(PDFDoc *docA, Object *aobj, unsigned num, Ref aref, FormField *fieldA);
+
+ AnnotWidget *widget;
+ FormField* field;
+ FormFieldType type;
+ Object obj;
+ Ref ref;
+ PDFDoc *doc;
+ XRef *xref;
+
+ //index of this field in the parent's child list
+ unsigned childNum;
+
+ /*
+ Field ID is an (unsigned) integer, calculated as follow :
+ the first sizeof/2 bits are the field number, relative to the page
+ the last sizeof/2 bits are the page number
+ [page number | field number]
+ (encoding) id = (pageNum << 4*sizeof(unsigned)) + fieldNum;
+ (decoding) pageNum = id >> 4*sizeof(unsigned); fieldNum = (id << 4*sizeof(unsigned)) >> 4*sizeof(unsigned);
+ */
+ unsigned ID;
+};
+
+//------------------------------------------------------------------------
+// FormWidgetButton
+//------------------------------------------------------------------------
+
+class FormWidgetButton: public FormWidget {
+public:
+ FormWidgetButton(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
+ ~FormWidgetButton ();
+
+ FormButtonType getButtonType() const;
+
+ void setState (GBool state);
+ GBool getState ();
+
+ char* getOnStr();
+ void setAppearanceState(const char *state);
+ void updateWidgetAppearance();
+
+protected:
+ GooString *onStr;
+ FormFieldButton *parent;
+};
+
+//------------------------------------------------------------------------
+// FormWidgetText
+//------------------------------------------------------------------------
+
+class FormWidgetText: public FormWidget {
+public:
+ FormWidgetText(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
+ //return the field's content (UTF16BE)
+ GooString* getContent() ;
+ //return a copy of the field's content (UTF16BE)
+ GooString* getContentCopy();
+
+ //except a UTF16BE string
+ void setContent(GooString* new_content);
+
+ void updateWidgetAppearance();
+
+ bool isMultiline () const;
+ bool isPassword () const;
+ bool isFileSelect () const;
+ bool noSpellCheck () const;
+ bool noScroll () const;
+ bool isComb () const;
+ bool isRichText () const;
+ int getMaxLen () const;
+protected:
+ FormFieldText *parent;
+};
+
+//------------------------------------------------------------------------
+// FormWidgetChoice
+//------------------------------------------------------------------------
+
+class FormWidgetChoice: public FormWidget {
+public:
+ FormWidgetChoice(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
+ ~FormWidgetChoice();
+
+ int getNumChoices();
+ //return the display name of the i-th choice (UTF16BE)
+ GooString* getChoice(int i);
+ //select the i-th choice
+ void select (int i);
+
+ //toggle selection of the i-th choice
+ void toggle (int i);
+
+ //deselect everything
+ void deselectAll ();
+
+ //except a UTF16BE string
+ //only work for editable combo box, set the user-entered text as the current choice
+ void setEditChoice(GooString* new_content);
+
+ GooString* getEditChoice ();
+
+ void updateWidgetAppearance();
+ bool isSelected (int i);
+
+ bool isCombo () const;
+ bool hasEdit () const;
+ bool isMultiSelect () const;
+ bool noSpellCheck () const;
+ bool commitOnSelChange () const;
+ bool isListBox () const;
+protected:
+ bool _checkRange (int i);
+ FormFieldChoice *parent;
+};
+
+//------------------------------------------------------------------------
+// FormWidgetSignature
+//------------------------------------------------------------------------
+
+class FormWidgetSignature: public FormWidget {
+public:
+ FormWidgetSignature(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
+ void updateWidgetAppearance();
+protected:
+ FormFieldSignature *parent;
+};
+
+//------------------------------------------------------------------------
+// FormField
+// A FormField implements the logical side of a field and is "attached" to
+// the Catalog. This is an internal class and client applications should
+// only interact with FormWidgets.
+//------------------------------------------------------------------------
+
+class FormField {
+public:
+ FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *parent, std::set<int> *usedParents, FormFieldType t=formUndef);
+
+ virtual ~FormField();
+
+ // Accessors.
+ FormFieldType getType() { return type; }
+ Object* getObj() { return &obj; }
+ Ref getRef() { return ref; }
+
+ void setReadOnly (bool b) { readOnly = b; }
+ bool isReadOnly () const { return readOnly; }
+
+ GooString* getDefaultAppearance() const { return defaultAppearance; }
+ GBool hasTextQuadding() const { return hasQuadding; }
+ VariableTextQuadding getTextQuadding() const { return quadding; }
+
+ GooString *getPartialName() const { return partialName; }
+ GooString *getAlternateUiName() const { return alternateUiName; }
+ GooString *getMappingName() const { return mappingName; }
+ GooString *getFullyQualifiedName();
+
+ FormWidget* findWidgetByRef (Ref aref);
+ int getNumWidgets() { return terminal ? numChildren : 0; }
+ FormWidget *getWidget(int i) { return terminal ? widgets[i] : NULL; }
+
+ // only implemented in FormFieldButton
+ virtual void fillChildrenSiblingsID ();
+
+ void createWidgetAnnotations();
+
+#ifdef DEBUG_FORMS
+ void printTree(int indent = 0);
+ virtual void print(int indent = 0);
+#endif
+
+
+ protected:
+ void _createWidget (Object *obj, Ref aref);
+ void createChildren(std::set<int> *usedParents);
+ void updateChildrenAppearance();
+
+ FormFieldType type; // field type
+ Ref ref;
+ bool terminal;
+ Object obj;
+ PDFDoc *doc;
+ XRef *xref;
+ FormField **children;
+ FormField *parent;
+ int numChildren;
+ FormWidget **widgets;
+ bool readOnly;
+
+ GooString *partialName; // T field
+ GooString *alternateUiName; // TU field
+ GooString *mappingName; // TM field
+ GooString *fullyQualifiedName;
+
+ // Variable Text
+ GooString *defaultAppearance;
+ GBool hasQuadding;
+ VariableTextQuadding quadding;
+
+private:
+ FormField() {}
+};
+
+
+//------------------------------------------------------------------------
+// FormFieldButton
+//------------------------------------------------------------------------
+
+class FormFieldButton: public FormField {
+public:
+ FormFieldButton(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
+
+ FormButtonType getButtonType () { return btype; }
+
+ bool noToggleToOff () const { return noAllOff; }
+
+ // returns gTrue if the state modification is accepted
+ GBool setState (char *state);
+ GBool getState(char *state);
+
+ char *getAppearanceState() { return appearanceState.isName() ? appearanceState.getName() : NULL; }
+
+ void fillChildrenSiblingsID ();
+
+ void setNumSiblings (int num);
+ void setSibling (int i, FormFieldButton *id) { siblings[i] = id; }
+
+ //For radio buttons, return the fields of the other radio buttons in the same group
+ FormFieldButton* getSibling (int i) const { return siblings[i]; }
+ int getNumSiblings () const { return numSiblings; }
+
+#ifdef DEBUG_FORMS
+ void print(int indent = 0);
+#endif
+
+ virtual ~FormFieldButton();
+protected:
+ void updateState(char *state);
+
+ FormFieldButton** siblings; // IDs of dependent buttons (each button of a radio field has all the others buttons
+ // of the same field in this array)
+ int numSiblings;
+
+ FormButtonType btype;
+ int size;
+ int active_child; //only used for combo box
+ bool noAllOff;
+ Object appearanceState; // V
+};
+
+//------------------------------------------------------------------------
+// FormFieldText
+//------------------------------------------------------------------------
+
+class FormFieldText: public FormField {
+public:
+ FormFieldText(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
+
+ GooString* getContent () { return content; }
+ GooString* getContentCopy ();
+ void setContentCopy (GooString* new_content);
+ virtual ~FormFieldText();
+
+ bool isMultiline () const { return multiline; }
+ bool isPassword () const { return password; }
+ bool isFileSelect () const { return fileSelect; }
+ bool noSpellCheck () const { return doNotSpellCheck; }
+ bool noScroll () const { return doNotScroll; }
+ bool isComb () const { return comb; }
+ bool isRichText () const { return richText; }
+
+ int getMaxLen () const { return maxLen; }
+
+#ifdef DEBUG_FORMS
+ void print(int indent = 0);
+#endif
+protected:
+ GooString* content;
+ bool multiline;
+ bool password;
+ bool fileSelect;
+ bool doNotSpellCheck;
+ bool doNotScroll;
+ bool comb;
+ bool richText;
+ int maxLen;
+};
+
+//------------------------------------------------------------------------
+// FormFieldChoice
+//------------------------------------------------------------------------
+
+class FormFieldChoice: public FormField {
+public:
+ FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, FormField *parent, std::set<int> *usedParents);
+
+ virtual ~FormFieldChoice();
+
+ int getNumChoices() { return numChoices; }
+ GooString* getChoice(int i) { return choices ? choices[i].optionName : NULL; }
+ GooString* getExportVal (int i) { return choices ? choices[i].exportVal : NULL; }
+ // For multi-select choices it returns the first one
+ GooString* getSelectedChoice();
+
+ //select the i-th choice
+ void select (int i);
+
+ //toggle selection of the i-th choice
+ void toggle (int i);
+
+ //deselect everything
+ void deselectAll ();
+
+ //only work for editable combo box, set the user-entered text as the current choice
+ void setEditChoice(GooString* new_content);
+
+ GooString* getEditChoice ();
+
+ bool isSelected (int i) { return choices[i].selected; }
+
+ int getNumSelected ();
+
+ bool isCombo () const { return combo; }
+ bool hasEdit () const { return edit; }
+ bool isMultiSelect () const { return multiselect; }
+ bool noSpellCheck () const { return doNotSpellCheck; }
+ bool commitOnSelChange () const { return doCommitOnSelChange; }
+ bool isListBox () const { return !combo; }
+
+ int getTopIndex() const { return topIdx; }
+
+#ifdef DEBUG_FORMS
+ void print(int indent = 0);
+#endif
+
+protected:
+ void unselectAll();
+ void updateSelection();
+
+ bool combo;
+ bool edit;
+ bool multiselect;
+ bool doNotSpellCheck;
+ bool doCommitOnSelChange;
+
+ struct ChoiceOpt {
+ GooString* exportVal; //the export value ("internal" name)
+ GooString* optionName; //displayed name
+ bool selected; //if this choice is selected
+ };
+
+ int numChoices;
+ ChoiceOpt* choices;
+ GooString* editedChoice;
+ int topIdx; // TI
+};
+
+//------------------------------------------------------------------------
+// FormFieldSignature
+//------------------------------------------------------------------------
+
+class FormFieldSignature: public FormField {
+public:
+ FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
+
+ virtual ~FormFieldSignature();
+
+#ifdef DEBUG_FORMS
+ void print(int indent = 0);
+#endif
+};
+
+//------------------------------------------------------------------------
+// Form
+// This class handle the document-wide part of Form (things in the acroForm
+// Catalog entry).
+//------------------------------------------------------------------------
+
+class Form {
+public:
+ Form(PDFDoc *docA, Object* acroForm);
+
+ ~Form();
+
+ // Look up an inheritable field dictionary entry.
+ static Object *fieldLookup(Dict *field, const char *key, Object *obj);
+
+ /* Creates a new Field of the type specified in obj's dict.
+ used in Form::Form and FormField::FormField */
+ static FormField *createFieldFromDict (Object* obj, PDFDoc *docA, const Ref& aref, FormField *parent, std::set<int> *usedParents);
+
+ Object *getObj () const { return acroForm; }
+ GBool getNeedAppearances () const { return needAppearances; }
+ int getNumFields() const { return numFields; }
+ FormField* getRootField(int i) const { return rootFields[i]; }
+ GooString* getDefaultAppearance() const { return defaultAppearance; }
+ VariableTextQuadding getTextQuadding() const { return quadding; }
+ GfxResources* getDefaultResources() const { return defaultResources; }
+ Object* getDefaultResourcesObj() { return &resDict; }
+
+ FormWidget* findWidgetByRef (Ref aref);
+
+ void postWidgetsLoad();
+private:
+ FormField** rootFields;
+ int numFields;
+ int size;
+ PDFDoc *doc;
+ XRef* xref;
+ Object *acroForm;
+ GBool needAppearances;
+ GfxResources *defaultResources;
+ Object resDict;
+
+ // Variable Text
+ GooString *defaultAppearance;
+ VariableTextQuadding quadding;
+};
+
+//------------------------------------------------------------------------
+// FormPageWidgets
+//------------------------------------------------------------------------
+
+class FormPageWidgets {
+public:
+ FormPageWidgets (Annots* annots, unsigned int page, Form *form);
+ ~FormPageWidgets();
+
+ int getNumWidgets() const { return numWidgets; }
+ FormWidget* getWidget(int i) const { return widgets[i]; }
+
+private:
+ FormWidget** widgets;
+ int numWidgets;
+ int size;
+};
+
+#endif
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Function.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Function.cc
new file mode 100644
index 00000000000..67283dffe9f
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Function.cc
@@ -0,0 +1,1788 @@
+//========================================================================
+//
+// Function.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2008-2010, 2013, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
+// Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "goo/gmem.h"
+#include "goo/gstrtod.h"
+#include "Object.h"
+#include "Dict.h"
+#include "Stream.h"
+#include "Error.h"
+#include "Function.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//------------------------------------------------------------------------
+// Function
+//------------------------------------------------------------------------
+
+Function::Function() {
+}
+
+Function::~Function() {
+}
+
+Function *Function::parse(Object *funcObj) {
+ std::set<int> usedParents;
+ return parse(funcObj, &usedParents);
+}
+
+Function *Function::parse(Object *funcObj, std::set<int> *usedParents) {
+ Function *func;
+ Dict *dict;
+ int funcType;
+ Object obj1;
+
+ if (funcObj->isStream()) {
+ dict = funcObj->streamGetDict();
+ } else if (funcObj->isDict()) {
+ dict = funcObj->getDict();
+ } else if (funcObj->isName("Identity")) {
+ return new IdentityFunction();
+ } else {
+ error(errSyntaxError, -1, "Expected function dictionary or stream");
+ return NULL;
+ }
+
+ if (!dict->lookup("FunctionType", &obj1)->isInt()) {
+ error(errSyntaxError, -1, "Function type is missing or wrong type");
+ obj1.free();
+ return NULL;
+ }
+ funcType = obj1.getInt();
+ obj1.free();
+
+ if (funcType == 0) {
+ func = new SampledFunction(funcObj, dict);
+ } else if (funcType == 2) {
+ func = new ExponentialFunction(funcObj, dict);
+ } else if (funcType == 3) {
+ func = new StitchingFunction(funcObj, dict, usedParents);
+ } else if (funcType == 4) {
+ func = new PostScriptFunction(funcObj, dict);
+ } else {
+ error(errSyntaxError, -1, "Unimplemented function type ({0:d})", funcType);
+ return NULL;
+ }
+ if (!func->isOk()) {
+ delete func;
+ return NULL;
+ }
+
+ return func;
+}
+
+Function::Function(const Function *func) {
+ m = func->m;
+ n = func->n;
+
+ memcpy(domain, func->domain, funcMaxInputs * 2 * sizeof(double));
+ memcpy(range, func->range, funcMaxOutputs * 2 * sizeof(double));
+
+ hasRange = func->hasRange;
+}
+
+GBool Function::init(Dict *dict) {
+ Object obj1, obj2;
+ int i;
+
+ //----- Domain
+ if (!dict->lookup("Domain", &obj1)->isArray()) {
+ error(errSyntaxError, -1, "Function is missing domain");
+ goto err2;
+ }
+ m = obj1.arrayGetLength() / 2;
+ if (m > funcMaxInputs) {
+ error(errSyntaxError, -1, "Functions with more than {0:d} inputs are unsupported",
+ funcMaxInputs);
+ goto err2;
+ }
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function domain array");
+ goto err1;
+ }
+ domain[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function domain array");
+ goto err1;
+ }
+ domain[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- Range
+ hasRange = gFalse;
+ n = 0;
+ if (dict->lookup("Range", &obj1)->isArray()) {
+ hasRange = gTrue;
+ n = obj1.arrayGetLength() / 2;
+ if (n > funcMaxOutputs) {
+ error(errSyntaxError, -1, "Functions with more than {0:d} outputs are unsupported",
+ funcMaxOutputs);
+ goto err2;
+ }
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function range array");
+ goto err1;
+ }
+ range[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function range array");
+ goto err1;
+ }
+ range[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ return gTrue;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+ return gFalse;
+}
+
+//------------------------------------------------------------------------
+// IdentityFunction
+//------------------------------------------------------------------------
+
+IdentityFunction::IdentityFunction() {
+ int i;
+
+ // fill these in with arbitrary values just in case they get used
+ // somewhere
+ m = funcMaxInputs;
+ n = funcMaxOutputs;
+ for (i = 0; i < funcMaxInputs; ++i) {
+ domain[i][0] = 0;
+ domain[i][1] = 1;
+ }
+ hasRange = gFalse;
+}
+
+IdentityFunction::~IdentityFunction() {
+}
+
+void IdentityFunction::transform(double *in, double *out) {
+ int i;
+
+ for (i = 0; i < funcMaxOutputs; ++i) {
+ out[i] = in[i];
+ }
+}
+
+//------------------------------------------------------------------------
+// SampledFunction
+//------------------------------------------------------------------------
+
+SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
+ Stream *str;
+ int sampleBits;
+ double sampleMul;
+ Object obj1, obj2;
+ Guint buf, bitMask;
+ int bits;
+ Guint s;
+ double in[funcMaxInputs];
+ int i, j, t, bit, idx;
+
+ idxOffset = NULL;
+ samples = NULL;
+ sBuf = NULL;
+ ok = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (!hasRange) {
+ error(errSyntaxError, -1, "Type 0 function is missing range");
+ goto err1;
+ }
+ if (m > sampledFuncMaxInputs) {
+ error(errSyntaxError, -1, "Sampled functions with more than {0:d} inputs are unsupported",
+ sampledFuncMaxInputs);
+ goto err1;
+ }
+
+ //----- buffer
+ sBuf = (double *)gmallocn(1 << m, sizeof(double));
+
+ //----- get the stream
+ if (!funcObj->isStream()) {
+ error(errSyntaxError, -1, "Type 0 function isn't a stream");
+ goto err1;
+ }
+ str = funcObj->getStream();
+
+ //----- Size
+ if (!dict->lookup("Size", &obj1)->isArray() ||
+ obj1.arrayGetLength() != m) {
+ error(errSyntaxError, -1, "Function has missing or invalid size array");
+ goto err2;
+ }
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isInt()) {
+ error(errSyntaxError, -1, "Illegal value in function size array");
+ goto err3;
+ }
+ sampleSize[i] = obj2.getInt();
+ if (sampleSize[i] <= 0) {
+ error(errSyntaxError, -1, "Illegal non-positive value in function size array");
+ goto err3;
+ }
+ obj2.free();
+ }
+ obj1.free();
+ idxOffset = (int *)gmallocn(1 << m, sizeof(int));
+ for (i = 0; i < (1<<m); ++i) {
+ idx = 0;
+ for (j = m - 1, t = i; j >= 1; --j, t <<= 1) {
+ if (sampleSize[j] == 1) {
+ bit = 0;
+ } else {
+ bit = (t >> (m - 1)) & 1;
+ }
+ idx = (idx + bit) * sampleSize[j-1];
+ }
+ if (sampleSize[0] == 1) {
+ bit = 0;
+ } else {
+ bit = (t >> (m - 1)) & 1;
+ }
+ idxOffset[i] = (idx + bit) * n;
+ }
+
+ //----- BitsPerSample
+ if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
+ error(errSyntaxError, -1, "Function has missing or invalid BitsPerSample");
+ goto err2;
+ }
+ sampleBits = obj1.getInt();
+ sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1);
+ obj1.free();
+
+ //----- Encode
+ if (dict->lookup("Encode", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2*m) {
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function encode array");
+ goto err3;
+ }
+ encode[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function encode array");
+ goto err3;
+ }
+ encode[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ for (i = 0; i < m; ++i) {
+ encode[i][0] = 0;
+ encode[i][1] = sampleSize[i] - 1;
+ }
+ }
+ obj1.free();
+ for (i = 0; i < m; ++i) {
+ inputMul[i] = (encode[i][1] - encode[i][0]) /
+ (domain[i][1] - domain[i][0]);
+ }
+
+ //----- Decode
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2*n) {
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function decode array");
+ goto err3;
+ }
+ decode[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function decode array");
+ goto err3;
+ }
+ decode[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ decode[i][0] = range[i][0];
+ decode[i][1] = range[i][1];
+ }
+ }
+ obj1.free();
+
+ //----- samples
+ nSamples = n;
+ for (i = 0; i < m; ++i)
+ nSamples *= sampleSize[i];
+ samples = (double *)gmallocn(nSamples, sizeof(double));
+ buf = 0;
+ bits = 0;
+ bitMask = (1 << sampleBits) - 1;
+ str->reset();
+ for (i = 0; i < nSamples; ++i) {
+ if (sampleBits == 8) {
+ s = str->getChar();
+ } else if (sampleBits == 16) {
+ s = str->getChar();
+ s = (s << 8) + str->getChar();
+ } else if (sampleBits == 32) {
+ s = str->getChar();
+ s = (s << 8) + str->getChar();
+ s = (s << 8) + str->getChar();
+ s = (s << 8) + str->getChar();
+ } else {
+ while (bits < sampleBits) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bits += 8;
+ }
+ s = (buf >> (bits - sampleBits)) & bitMask;
+ bits -= sampleBits;
+ }
+ samples[i] = (double)s * sampleMul;
+ }
+ str->close();
+
+ // set up the cache
+ for (i = 0; i < m; ++i) {
+ in[i] = domain[i][0];
+ cacheIn[i] = in[i] - 1;
+ }
+ transform(in, cacheOut);
+
+ ok = gTrue;
+ return;
+
+ err3:
+ obj2.free();
+ err2:
+ obj1.free();
+ err1:
+ return;
+}
+
+SampledFunction::~SampledFunction() {
+ if (idxOffset) {
+ gfree(idxOffset);
+ }
+ if (samples) {
+ gfree(samples);
+ }
+ if (sBuf) {
+ gfree(sBuf);
+ }
+}
+
+SampledFunction::SampledFunction(const SampledFunction *func) : Function(func) {
+ memcpy(sampleSize, func->sampleSize, funcMaxInputs * sizeof(int));
+
+ memcpy(encode, func->encode, funcMaxInputs * 2 * sizeof(double));
+ memcpy(decode, func->decode, funcMaxOutputs * 2 * sizeof(double));
+
+ memcpy(inputMul, func->inputMul, funcMaxInputs * sizeof(double));
+
+ nSamples = func->nSamples;
+
+ idxOffset = (int *)gmallocn(1 << m, sizeof(int));
+ memcpy(idxOffset, func->idxOffset, (1 << m) * (int)sizeof(int));
+
+ samples = (double *)gmallocn(nSamples, sizeof(double));
+ memcpy(samples, func->samples, nSamples * sizeof(double));
+
+ sBuf = (double *)gmallocn(1 << m, sizeof(double));
+
+ memcpy(cacheIn, func->cacheIn, funcMaxInputs * sizeof(double));
+ memcpy(cacheOut, func->cacheOut, funcMaxOutputs * sizeof(double));
+
+ ok = func->ok;
+}
+
+void SampledFunction::transform(double *in, double *out) {
+ double x;
+ int e[funcMaxInputs];
+ double efrac0[funcMaxInputs];
+ double efrac1[funcMaxInputs];
+ int i, j, k, idx0, t;
+
+ // check the cache
+ for (i = 0; i < m; ++i) {
+ if (in[i] != cacheIn[i]) {
+ break;
+ }
+ }
+ if (i == m) {
+ for (i = 0; i < n; ++i) {
+ out[i] = cacheOut[i];
+ }
+ return;
+ }
+
+ // map input values into sample array
+ for (i = 0; i < m; ++i) {
+ x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0];
+ if (x < 0 || x != x) { // x!=x is a more portable version of isnan(x)
+ x = 0;
+ } else if (x > sampleSize[i] - 1) {
+ x = sampleSize[i] - 1;
+ }
+ e[i] = (int)x;
+ if (e[i] == sampleSize[i] - 1 && sampleSize[i] > 1) {
+ // this happens if in[i] = domain[i][1]
+ e[i] = sampleSize[i] - 2;
+ }
+ efrac1[i] = x - e[i];
+ efrac0[i] = 1 - efrac1[i];
+ }
+
+ // compute index for the first sample to be used
+ idx0 = 0;
+ for (k = m - 1; k >= 1; --k) {
+ idx0 = (idx0 + e[k]) * sampleSize[k-1];
+ }
+ idx0 = (idx0 + e[0]) * n;
+
+ // for each output, do m-linear interpolation
+ for (i = 0; i < n; ++i) {
+
+ // pull 2^m values out of the sample array
+ for (j = 0; j < (1<<m); ++j) {
+ int idx = idx0 + idxOffset[j] + i;
+ if (likely(idx >= 0 && idx < nSamples)) {
+ sBuf[j] = samples[idx];
+ } else {
+ sBuf[j] = 0; // TODO Investigate if this is what Adobe does
+ }
+ }
+
+ // do m sets of interpolations
+ for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) {
+ for (k = 0; k < t; k += 2) {
+ sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k+1];
+ }
+ }
+
+ // map output value to range
+ out[i] = sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+
+ // save current result in the cache
+ for (i = 0; i < m; ++i) {
+ cacheIn[i] = in[i];
+ }
+ for (i = 0; i < n; ++i) {
+ cacheOut[i] = out[i];
+ }
+}
+
+GBool SampledFunction::hasDifferentResultSet(Function *func) {
+ if (func->getType() == 0) {
+ SampledFunction *compTo = (SampledFunction *) func;
+ if (compTo->getSampleNumber() != nSamples)
+ return gTrue;
+ double *compSamples = compTo->getSamples();
+ for (int i = 0; i < nSamples; i++) {
+ if (samples[i] != compSamples[i])
+ return gTrue;
+ }
+ }
+ return gFalse;
+}
+
+//------------------------------------------------------------------------
+// ExponentialFunction
+//------------------------------------------------------------------------
+
+ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
+ Object obj1, obj2;
+ int i;
+
+ ok = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (m != 1) {
+ error(errSyntaxError, -1, "Exponential function with more than one input");
+ goto err1;
+ }
+
+ //----- C0
+ if (dict->lookup("C0", &obj1)->isArray()) {
+ if (hasRange && obj1.arrayGetLength() != n) {
+ error(errSyntaxError, -1, "Function's C0 array is wrong length");
+ goto err2;
+ }
+ n = obj1.arrayGetLength();
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function C0 array");
+ goto err3;
+ }
+ c0[i] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ if (hasRange && n != 1) {
+ error(errSyntaxError, -1, "Function's C0 array is wrong length");
+ goto err2;
+ }
+ n = 1;
+ c0[0] = 0;
+ }
+ obj1.free();
+
+ //----- C1
+ if (dict->lookup("C1", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() != n) {
+ error(errSyntaxError, -1, "Function's C1 array is wrong length");
+ goto err2;
+ }
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isNum()) {
+ error(errSyntaxError, -1, "Illegal value in function C1 array");
+ goto err3;
+ }
+ c1[i] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ if (n != 1) {
+ error(errSyntaxError, -1, "Function's C1 array is wrong length");
+ goto err2;
+ }
+ c1[0] = 1;
+ }
+ obj1.free();
+
+ //----- N (exponent)
+ if (!dict->lookup("N", &obj1)->isNum()) {
+ error(errSyntaxError, -1, "Function has missing or invalid N");
+ goto err2;
+ }
+ e = obj1.getNum();
+ obj1.free();
+
+ isLinear = fabs(e-1.) < 1e-10;
+ ok = gTrue;
+ return;
+
+ err3:
+ obj2.free();
+ err2:
+ obj1.free();
+ err1:
+ return;
+}
+
+ExponentialFunction::~ExponentialFunction() {
+}
+
+ExponentialFunction::ExponentialFunction(const ExponentialFunction *func) : Function(func) {
+ memcpy(c0, func->c0, funcMaxOutputs * sizeof(double));
+ memcpy(c1, func->c1, funcMaxOutputs * sizeof(double));
+
+ e = func->e;
+ isLinear = func->isLinear;
+ ok = func->ok;
+}
+
+void ExponentialFunction::transform(double *in, double *out) {
+ double x;
+ int i;
+
+ if (in[0] < domain[0][0]) {
+ x = domain[0][0];
+ } else if (in[0] > domain[0][1]) {
+ x = domain[0][1];
+ } else {
+ x = in[0];
+ }
+ for (i = 0; i < n; ++i) {
+ out[i] = c0[i] + (isLinear ? x : pow(x, e)) * (c1[i] - c0[i]);
+ if (hasRange) {
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+ }
+ return;
+}
+
+//------------------------------------------------------------------------
+// StitchingFunction
+//------------------------------------------------------------------------
+
+StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int> *usedParents) {
+ Object obj1, obj2;
+ int i;
+
+ ok = gFalse;
+ funcs = NULL;
+ bounds = NULL;
+ encode = NULL;
+ scale = NULL;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (m != 1) {
+ error(errSyntaxError, -1, "Stitching function with more than one input");
+ goto err1;
+ }
+
+ //----- Functions
+ if (!dict->lookup("Functions", &obj1)->isArray()) {
+ error(errSyntaxError, -1, "Missing 'Functions' entry in stitching function");
+ goto err1;
+ }
+ k = obj1.arrayGetLength();
+ funcs = (Function **)gmallocn(k, sizeof(Function *));
+ bounds = (double *)gmallocn(k + 1, sizeof(double));
+ encode = (double *)gmallocn(2 * k, sizeof(double));
+ scale = (double *)gmallocn(k, sizeof(double));
+ for (i = 0; i < k; ++i) {
+ funcs[i] = NULL;
+ }
+ for (i = 0; i < k; ++i) {
+ std::set<int> usedParentsAux = *usedParents;
+ obj1.arrayGetNF(i, &obj2);
+ if (obj2.isRef()) {
+ const Ref ref = obj2.getRef();
+ if (usedParentsAux.find(ref.num) == usedParentsAux.end()) {
+ usedParentsAux.insert(ref.num);
+ obj2.free();
+ obj1.arrayGet(i, &obj2);
+ } else {
+ goto err2;
+ }
+ }
+ if (!(funcs[i] = Function::parse(&obj2, &usedParentsAux))) {
+ goto err2;
+ }
+ if (funcs[i]->getInputSize() != 1 ||
+ (i > 0 && funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
+ error(errSyntaxError, -1,
+ "Incompatible subfunctions in stitching function");
+ goto err2;
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- Bounds
+ if (!dict->lookup("Bounds", &obj1)->isArray() ||
+ obj1.arrayGetLength() != k - 1) {
+ error(errSyntaxError, -1, "Missing or invalid 'Bounds' entry in stitching function");
+ goto err1;
+ }
+ bounds[0] = domain[0][0];
+ for (i = 1; i < k; ++i) {
+ if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
+ error(errSyntaxError, -1, "Invalid type in 'Bounds' array in stitching function");
+ goto err2;
+ }
+ bounds[i] = obj2.getNum();
+ obj2.free();
+ }
+ bounds[k] = domain[0][1];
+ obj1.free();
+
+ //----- Encode
+ if (!dict->lookup("Encode", &obj1)->isArray() ||
+ obj1.arrayGetLength() != 2 * k) {
+ error(errSyntaxError, -1, "Missing or invalid 'Encode' entry in stitching function");
+ goto err1;
+ }
+ for (i = 0; i < 2 * k; ++i) {
+ if (!obj1.arrayGet(i, &obj2)->isNum()) {
+ error(errSyntaxError, -1, "Invalid type in 'Encode' array in stitching function");
+ goto err2;
+ }
+ encode[i] = obj2.getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- pre-compute the scale factors
+ for (i = 0; i < k; ++i) {
+ if (bounds[i] == bounds[i+1]) {
+ // avoid a divide-by-zero -- in this situation, function i will
+ // never be used anyway
+ scale[i] = 0;
+ } else {
+ scale[i] = (encode[2*i+1] - encode[2*i]) / (bounds[i+1] - bounds[i]);
+ }
+ }
+
+ n = funcs[0]->getOutputSize();
+ ok = gTrue;
+ return;
+
+ err2:
+ obj2.free();
+ err1:
+ obj1.free();
+}
+
+StitchingFunction::StitchingFunction(const StitchingFunction *func) : Function(func) {
+ k = func->k;
+
+ funcs = (Function **)gmallocn(k, sizeof(Function *));
+ for (int i = 0; i < k; ++i) {
+ funcs[i] = func->funcs[i]->copy();
+ }
+
+ bounds = (double *)gmallocn(k + 1, sizeof(double));
+ memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
+
+ encode = (double *)gmallocn(2 * k, sizeof(double));
+ memcpy(encode, func->encode, 2 * k * sizeof(double));
+
+ scale = (double *)gmallocn(k, sizeof(double));
+ memcpy(scale, func->scale, k * sizeof(double));
+
+ ok = func->ok;
+}
+
+StitchingFunction::~StitchingFunction() {
+ int i;
+
+ if (funcs) {
+ for (i = 0; i < k; ++i) {
+ if (funcs[i]) {
+ delete funcs[i];
+ }
+ }
+ }
+ gfree(funcs);
+ gfree(bounds);
+ gfree(encode);
+ gfree(scale);
+}
+
+void StitchingFunction::transform(double *in, double *out) {
+ double x;
+ int i;
+
+ if (in[0] < domain[0][0]) {
+ x = domain[0][0];
+ } else if (in[0] > domain[0][1]) {
+ x = domain[0][1];
+ } else {
+ x = in[0];
+ }
+ for (i = 0; i < k - 1; ++i) {
+ if (x < bounds[i+1]) {
+ break;
+ }
+ }
+ x = encode[2*i] + (x - bounds[i]) * scale[i];
+ funcs[i]->transform(&x, out);
+}
+
+//------------------------------------------------------------------------
+// PostScriptFunction
+//------------------------------------------------------------------------
+
+enum PSOp {
+ psOpAbs,
+ psOpAdd,
+ psOpAnd,
+ psOpAtan,
+ psOpBitshift,
+ psOpCeiling,
+ psOpCopy,
+ psOpCos,
+ psOpCvi,
+ psOpCvr,
+ psOpDiv,
+ psOpDup,
+ psOpEq,
+ psOpExch,
+ psOpExp,
+ psOpFalse,
+ psOpFloor,
+ psOpGe,
+ psOpGt,
+ psOpIdiv,
+ psOpIndex,
+ psOpLe,
+ psOpLn,
+ psOpLog,
+ psOpLt,
+ psOpMod,
+ psOpMul,
+ psOpNe,
+ psOpNeg,
+ psOpNot,
+ psOpOr,
+ psOpPop,
+ psOpRoll,
+ psOpRound,
+ psOpSin,
+ psOpSqrt,
+ psOpSub,
+ psOpTrue,
+ psOpTruncate,
+ psOpXor,
+ psOpIf,
+ psOpIfelse,
+ psOpReturn
+};
+
+// Note: 'if' and 'ifelse' are parsed separately.
+// The rest are listed here in alphabetical order.
+// The index in this table is equivalent to the entry in PSOp.
+static const char *psOpNames[] = {
+ "abs",
+ "add",
+ "and",
+ "atan",
+ "bitshift",
+ "ceiling",
+ "copy",
+ "cos",
+ "cvi",
+ "cvr",
+ "div",
+ "dup",
+ "eq",
+ "exch",
+ "exp",
+ "false",
+ "floor",
+ "ge",
+ "gt",
+ "idiv",
+ "index",
+ "le",
+ "ln",
+ "log",
+ "lt",
+ "mod",
+ "mul",
+ "ne",
+ "neg",
+ "not",
+ "or",
+ "pop",
+ "roll",
+ "round",
+ "sin",
+ "sqrt",
+ "sub",
+ "true",
+ "truncate",
+ "xor"
+};
+
+#define nPSOps (sizeof(psOpNames) / sizeof(char *))
+
+enum PSObjectType {
+ psBool,
+ psInt,
+ psReal,
+ psOperator,
+ psBlock
+};
+
+// In the code array, 'if'/'ifelse' operators take up three slots
+// plus space for the code in the subclause(s).
+//
+// +---------------------------------+
+// | psOperator: psOpIf / psOpIfelse |
+// +---------------------------------+
+// | psBlock: ptr=<A> |
+// +---------------------------------+
+// | psBlock: ptr=<B> |
+// +---------------------------------+
+// | if clause |
+// | ... |
+// | psOperator: psOpReturn |
+// +---------------------------------+
+// <A> | else clause |
+// | ... |
+// | psOperator: psOpReturn |
+// +---------------------------------+
+// <B> | ... |
+//
+// For 'if', pointer <A> is present in the code stream but unused.
+
+struct PSObject {
+ PSObjectType type;
+ union {
+ GBool booln; // boolean (stack only)
+ int intg; // integer (stack and code)
+ double real; // real (stack and code)
+ PSOp op; // operator (code only)
+ int blk; // if/ifelse block pointer (code only)
+ };
+};
+
+#define psStackSize 100
+
+class PSStack {
+public:
+
+ PSStack() {sp = psStackSize; }
+ void clear() { sp = psStackSize; }
+ void pushBool(GBool booln)
+ {
+ if (checkOverflow()) {
+ stack[--sp].type = psBool;
+ stack[sp].booln = booln;
+ }
+ }
+ void pushInt(int intg)
+ {
+ if (checkOverflow()) {
+ stack[--sp].type = psInt;
+ stack[sp].intg = intg;
+ }
+ }
+ void pushReal(double real)
+ {
+ if (checkOverflow()) {
+ stack[--sp].type = psReal;
+ stack[sp].real = real;
+ }
+ }
+ GBool popBool()
+ {
+ if (checkUnderflow() && checkType(psBool, psBool)) {
+ return stack[sp++].booln;
+ }
+ return gFalse;
+ }
+ int popInt()
+ {
+ if (checkUnderflow() && checkType(psInt, psInt)) {
+ return stack[sp++].intg;
+ }
+ return 0;
+ }
+ double popNum()
+ {
+ double ret;
+
+ if (checkUnderflow() && checkType(psInt, psReal)) {
+ ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
+ ++sp;
+ return ret;
+ }
+ return 0;
+ }
+ GBool empty() { return sp == psStackSize; }
+ GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
+ GBool topTwoAreInts()
+ { return sp < psStackSize - 1 &&
+ stack[sp].type == psInt &&
+ stack[sp+1].type == psInt; }
+ GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
+ GBool topTwoAreNums()
+ { return sp < psStackSize - 1 &&
+ (stack[sp].type == psInt || stack[sp].type == psReal) &&
+ (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
+ void copy(int n);
+ void roll(int n, int j);
+ void index(int i)
+ {
+ if (!checkOverflow()) {
+ return;
+ }
+ --sp;
+ if (unlikely(sp + i + 1 >= psStackSize)) {
+ error(errSyntaxError, -1, "Stack underflow in PostScript function");
+ return;
+ }
+ if (unlikely(sp + i + 1 < 0)) {
+ error(errSyntaxError, -1, "Stack overflow in PostScript function");
+ return;
+ }
+ stack[sp] = stack[sp + 1 + i];
+ }
+ void pop()
+ {
+ if (!checkUnderflow()) {
+ return;
+ }
+ ++sp;
+ }
+
+private:
+
+ GBool checkOverflow(int n = 1)
+ {
+ if (sp - n < 0) {
+ error(errSyntaxError, -1, "Stack overflow in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+ }
+ GBool checkUnderflow()
+ {
+ if (sp == psStackSize) {
+ error(errSyntaxError, -1, "Stack underflow in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+ }
+ GBool checkType(PSObjectType t1, PSObjectType t2)
+ {
+ if (stack[sp].type != t1 && stack[sp].type != t2) {
+ error(errSyntaxError, -1, "Type mismatch in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+ }
+ PSObject stack[psStackSize];
+ int sp;
+};
+
+
+void PSStack::copy(int n) {
+ int i;
+
+ if (sp + n > psStackSize) {
+ error(errSyntaxError, -1, "Stack underflow in PostScript function");
+ return;
+ }
+ if (unlikely(sp - n > psStackSize)) {
+ error(errSyntaxError, -1, "Stack underflow in PostScript function");
+ return;
+ }
+ if (!checkOverflow(n)) {
+ return;
+ }
+ for (i = sp + n - 1; i >= sp; --i) {
+ stack[i - n] = stack[i];
+ }
+ sp -= n;
+}
+
+void PSStack::roll(int n, int j) {
+ PSObject obj;
+ int i, k;
+
+ if (unlikely(n == 0)) {
+ return;
+ }
+ if (j >= 0) {
+ j %= n;
+ } else {
+ j = -j % n;
+ if (j != 0) {
+ j = n - j;
+ }
+ }
+ if (n <= 0 || j == 0 || n > psStackSize || sp + n > psStackSize) {
+ return;
+ }
+ if (j <= n / 2) {
+ for (i = 0; i < j; ++i) {
+ obj = stack[sp];
+ for (k = sp; k < sp + n - 1; ++k) {
+ stack[k] = stack[k+1];
+ }
+ stack[sp + n - 1] = obj;
+ }
+ } else {
+ j = n - j;
+ for (i = 0; i < j; ++i) {
+ obj = stack[sp + n - 1];
+ for (k = sp + n - 1; k > sp; --k) {
+ stack[k] = stack[k-1];
+ }
+ stack[sp] = obj;
+ }
+ }
+}
+
+PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
+ Stream *str;
+ int codePtr;
+ GooString *tok;
+ double in[funcMaxInputs];
+ int i;
+
+ code = NULL;
+ codeString = NULL;
+ codeSize = 0;
+ ok = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (!hasRange) {
+ error(errSyntaxError, -1, "Type 4 function is missing range");
+ goto err1;
+ }
+
+ //----- get the stream
+ if (!funcObj->isStream()) {
+ error(errSyntaxError, -1, "Type 4 function isn't a stream");
+ goto err1;
+ }
+ str = funcObj->getStream();
+
+ //----- parse the function
+ codeString = new GooString();
+ str->reset();
+ if (!(tok = getToken(str)) || tok->cmp("{")) {
+ error(errSyntaxError, -1, "Expected '{{' at start of PostScript function");
+ if (tok) {
+ delete tok;
+ }
+ goto err1;
+ }
+ delete tok;
+ codePtr = 0;
+ if (!parseCode(str, &codePtr)) {
+ goto err2;
+ }
+ str->close();
+
+ //----- set up the cache
+ for (i = 0; i < m; ++i) {
+ in[i] = domain[i][0];
+ cacheIn[i] = in[i] - 1;
+ }
+ transform(in, cacheOut);
+
+ ok = gTrue;
+
+ err2:
+ str->close();
+ err1:
+ return;
+}
+
+PostScriptFunction::PostScriptFunction(const PostScriptFunction *func) : Function(func) {
+ codeSize = func->codeSize;
+
+ code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
+ memcpy(code, func->code, codeSize * sizeof(PSObject));
+
+ codeString = func->codeString->copy();
+
+ memcpy(cacheIn, func->cacheIn, funcMaxInputs * sizeof(double));
+ memcpy(cacheOut, func->cacheOut, funcMaxOutputs * sizeof(double));
+
+ ok = func->ok;
+}
+
+PostScriptFunction::~PostScriptFunction() {
+ gfree(code);
+ delete codeString;
+}
+
+void PostScriptFunction::transform(double *in, double *out) {
+ PSStack stack;
+ int i;
+
+ // check the cache
+ for (i = 0; i < m; ++i) {
+ if (in[i] != cacheIn[i]) {
+ break;
+ }
+ }
+ if (i == m) {
+ for (i = 0; i < n; ++i) {
+ out[i] = cacheOut[i];
+ }
+ return;
+ }
+
+ for (i = 0; i < m; ++i) {
+ //~ may need to check for integers here
+ stack.pushReal(in[i]);
+ }
+ exec(&stack, 0);
+ for (i = n - 1; i >= 0; --i) {
+ out[i] = stack.popNum();
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+ stack.clear();
+
+ // if (!stack->empty()) {
+ // error(errSyntaxWarning, -1,
+ // "Extra values on stack at end of PostScript function");
+ // }
+
+ // save current result in the cache
+ for (i = 0; i < m; ++i) {
+ cacheIn[i] = in[i];
+ }
+ for (i = 0; i < n; ++i) {
+ cacheOut[i] = out[i];
+ }
+}
+
+GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
+ GooString *tok;
+ char *p;
+ GBool isReal;
+ int opPtr, elsePtr;
+ int a, b, mid, cmp;
+
+ while (1) {
+ if (!(tok = getToken(str))) {
+ error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ p = tok->getCString();
+ if (isdigit(*p) || *p == '.' || *p == '-') {
+ isReal = gFalse;
+ for (; *p; ++p) {
+ if (*p == '.') {
+ isReal = gTrue;
+ break;
+ }
+ }
+ resizeCode(*codePtr);
+ if (isReal) {
+ code[*codePtr].type = psReal;
+ code[*codePtr].real = gatof(tok->getCString());
+ } else {
+ code[*codePtr].type = psInt;
+ code[*codePtr].intg = atoi(tok->getCString());
+ }
+ ++*codePtr;
+ delete tok;
+ } else if (!tok->cmp("{")) {
+ delete tok;
+ opPtr = *codePtr;
+ *codePtr += 3;
+ resizeCode(opPtr + 2);
+ if (!parseCode(str, codePtr)) {
+ return gFalse;
+ }
+ if (!(tok = getToken(str))) {
+ error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ if (!tok->cmp("{")) {
+ elsePtr = *codePtr;
+ if (!parseCode(str, codePtr)) {
+ return gFalse;
+ }
+ delete tok;
+ if (!(tok = getToken(str))) {
+ error(errSyntaxError, -1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ } else {
+ elsePtr = -1;
+ }
+ if (!tok->cmp("if")) {
+ if (elsePtr >= 0) {
+ error(errSyntaxError, -1,
+ "Got 'if' operator with two blocks in PostScript function");
+ return gFalse;
+ }
+ code[opPtr].type = psOperator;
+ code[opPtr].op = psOpIf;
+ code[opPtr+2].type = psBlock;
+ code[opPtr+2].blk = *codePtr;
+ } else if (!tok->cmp("ifelse")) {
+ if (elsePtr < 0) {
+ error(errSyntaxError, -1,
+ "Got 'ifelse' operator with one block in PostScript function");
+ return gFalse;
+ }
+ code[opPtr].type = psOperator;
+ code[opPtr].op = psOpIfelse;
+ code[opPtr+1].type = psBlock;
+ code[opPtr+1].blk = elsePtr;
+ code[opPtr+2].type = psBlock;
+ code[opPtr+2].blk = *codePtr;
+ } else {
+ error(errSyntaxError, -1,
+ "Expected if/ifelse operator in PostScript function");
+ delete tok;
+ return gFalse;
+ }
+ delete tok;
+ } else if (!tok->cmp("}")) {
+ delete tok;
+ resizeCode(*codePtr);
+ code[*codePtr].type = psOperator;
+ code[*codePtr].op = psOpReturn;
+ ++*codePtr;
+ break;
+ } else {
+ a = -1;
+ b = nPSOps;
+ cmp = 0; // make gcc happy
+ // invariant: psOpNames[a] < tok < psOpNames[b]
+ while (b - a > 1) {
+ mid = (a + b) / 2;
+ cmp = tok->cmp(psOpNames[mid]);
+ if (cmp > 0) {
+ a = mid;
+ } else if (cmp < 0) {
+ b = mid;
+ } else {
+ a = b = mid;
+ }
+ }
+ if (cmp != 0) {
+ error(errSyntaxError, -1,
+ "Unknown operator '{0:t}' in PostScript function",
+ tok);
+ delete tok;
+ return gFalse;
+ }
+ delete tok;
+ resizeCode(*codePtr);
+ code[*codePtr].type = psOperator;
+ code[*codePtr].op = (PSOp)a;
+ ++*codePtr;
+ }
+ }
+ return gTrue;
+}
+
+GooString *PostScriptFunction::getToken(Stream *str) {
+ GooString *s;
+ int c;
+ GBool comment;
+
+ s = new GooString();
+ comment = gFalse;
+ while (1) {
+ if ((c = str->getChar()) == EOF) {
+ break;
+ }
+ codeString->append(c);
+ if (comment) {
+ if (c == '\x0a' || c == '\x0d') {
+ comment = gFalse;
+ }
+ } else if (c == '%') {
+ comment = gTrue;
+ } else if (!isspace(c)) {
+ break;
+ }
+ }
+ if (c == '{' || c == '}') {
+ s->append((char)c);
+ } else if (isdigit(c) || c == '.' || c == '-') {
+ while (1) {
+ s->append((char)c);
+ c = str->lookChar();
+ if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
+ break;
+ }
+ str->getChar();
+ codeString->append(c);
+ }
+ } else {
+ while (1) {
+ s->append((char)c);
+ c = str->lookChar();
+ if (c == EOF || !isalnum(c)) {
+ break;
+ }
+ str->getChar();
+ codeString->append(c);
+ }
+ }
+ return s;
+}
+
+void PostScriptFunction::resizeCode(int newSize) {
+ if (newSize >= codeSize) {
+ codeSize += 64;
+ code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
+ }
+}
+
+void PostScriptFunction::exec(PSStack *stack, int codePtr) {
+ int i1, i2;
+ double r1, r2, result;
+ GBool b1, b2;
+
+ while (1) {
+ switch (code[codePtr].type) {
+ case psInt:
+ stack->pushInt(code[codePtr++].intg);
+ break;
+ case psReal:
+ stack->pushReal(code[codePtr++].real);
+ break;
+ case psOperator:
+ switch (code[codePtr++].op) {
+ case psOpAbs:
+ if (stack->topIsInt()) {
+ stack->pushInt(abs(stack->popInt()));
+ } else {
+ stack->pushReal(fabs(stack->popNum()));
+ }
+ break;
+ case psOpAdd:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 + i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 + r2);
+ }
+ break;
+ case psOpAnd:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 & i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 && b2);
+ }
+ break;
+ case psOpAtan:
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ result = atan2(r1, r2) * 180.0 / M_PI;
+ if (result < 0) result += 360.0;
+ stack->pushReal(result);
+ break;
+ case psOpBitshift:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ if (i2 > 0) {
+ stack->pushInt(i1 << i2);
+ } else if (i2 < 0) {
+ stack->pushInt((int)((Guint)i1 >> -i2));
+ } else {
+ stack->pushInt(i1);
+ }
+ break;
+ case psOpCeiling:
+ if (!stack->topIsInt()) {
+ stack->pushReal(ceil(stack->popNum()));
+ }
+ break;
+ case psOpCopy:
+ stack->copy(stack->popInt());
+ break;
+ case psOpCos:
+ stack->pushReal(cos(stack->popNum() * M_PI / 180.0));
+ break;
+ case psOpCvi:
+ if (!stack->topIsInt()) {
+ stack->pushInt((int)stack->popNum());
+ }
+ break;
+ case psOpCvr:
+ if (!stack->topIsReal()) {
+ stack->pushReal(stack->popNum());
+ }
+ break;
+ case psOpDiv:
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 / r2);
+ break;
+ case psOpDup:
+ stack->copy(1);
+ break;
+ case psOpEq:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 == i2);
+ } else if (stack->topTwoAreNums()) {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 == r2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 == b2);
+ }
+ break;
+ case psOpExch:
+ stack->roll(2, 1);
+ break;
+ case psOpExp:
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(pow(r1, r2));
+ break;
+ case psOpFalse:
+ stack->pushBool(gFalse);
+ break;
+ case psOpFloor:
+ if (!stack->topIsInt()) {
+ stack->pushReal(floor(stack->popNum()));
+ }
+ break;
+ case psOpGe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 >= i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 >= r2);
+ }
+ break;
+ case psOpGt:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 > i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 > r2);
+ }
+ break;
+ case psOpIdiv:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 / i2);
+ break;
+ case psOpIndex:
+ stack->index(stack->popInt());
+ break;
+ case psOpLe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 <= i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 <= r2);
+ }
+ break;
+ case psOpLn:
+ stack->pushReal(log(stack->popNum()));
+ break;
+ case psOpLog:
+ stack->pushReal(log10(stack->popNum()));
+ break;
+ case psOpLt:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 < i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 < r2);
+ }
+ break;
+ case psOpMod:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 % i2);
+ break;
+ case psOpMul:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ //~ should check for out-of-range, and push a real instead
+ stack->pushInt(i1 * i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 * r2);
+ }
+ break;
+ case psOpNe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 != i2);
+ } else if (stack->topTwoAreNums()) {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 != r2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 != b2);
+ }
+ break;
+ case psOpNeg:
+ if (stack->topIsInt()) {
+ stack->pushInt(-stack->popInt());
+ } else {
+ stack->pushReal(-stack->popNum());
+ }
+ break;
+ case psOpNot:
+ if (stack->topIsInt()) {
+ stack->pushInt(~stack->popInt());
+ } else {
+ stack->pushBool(!stack->popBool());
+ }
+ break;
+ case psOpOr:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 | i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 || b2);
+ }
+ break;
+ case psOpPop:
+ stack->pop();
+ break;
+ case psOpRoll:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->roll(i1, i2);
+ break;
+ case psOpRound:
+ if (!stack->topIsInt()) {
+ r1 = stack->popNum();
+ stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
+ }
+ break;
+ case psOpSin:
+ stack->pushReal(sin(stack->popNum() * M_PI / 180.0));
+ break;
+ case psOpSqrt:
+ stack->pushReal(sqrt(stack->popNum()));
+ break;
+ case psOpSub:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 - i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 - r2);
+ }
+ break;
+ case psOpTrue:
+ stack->pushBool(gTrue);
+ break;
+ case psOpTruncate:
+ if (!stack->topIsInt()) {
+ r1 = stack->popNum();
+ stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
+ }
+ break;
+ case psOpXor:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 ^ i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 ^ b2);
+ }
+ break;
+ case psOpIf:
+ b1 = stack->popBool();
+ if (b1) {
+ exec(stack, codePtr + 2);
+ }
+ codePtr = code[codePtr + 1].blk;
+ break;
+ case psOpIfelse:
+ b1 = stack->popBool();
+ if (b1) {
+ exec(stack, codePtr + 2);
+ } else {
+ exec(stack, code[codePtr].blk);
+ }
+ codePtr = code[codePtr + 1].blk;
+ break;
+ case psOpReturn:
+ return;
+ }
+ break;
+ default:
+ error(errSyntaxError, -1, "Internal: bad object in PostScript function code");
+ break;
+ }
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Function.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Function.h
new file mode 100644
index 00000000000..90e2a768ad0
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Function.h
@@ -0,0 +1,258 @@
+//========================================================================
+//
+// Function.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef FUNCTION_H
+#define FUNCTION_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "Object.h"
+#include <set>
+
+class Dict;
+class Stream;
+struct PSObject;
+class PSStack;
+class PopplerCache;
+
+//------------------------------------------------------------------------
+// Function
+//------------------------------------------------------------------------
+
+#define funcMaxInputs 32
+#define funcMaxOutputs 32
+#define sampledFuncMaxInputs 16
+
+class Function {
+public:
+
+ Function();
+
+ virtual ~Function();
+
+ // Construct a function. Returns NULL if unsuccessful.
+ static Function *parse(Object *funcObj);
+
+ // Initialize the entries common to all function types.
+ GBool init(Dict *dict);
+
+ virtual Function *copy() = 0;
+
+ // Return the function type:
+ // -1 : identity
+ // 0 : sampled
+ // 2 : exponential
+ // 3 : stitching
+ // 4 : PostScript
+ virtual int getType() = 0;
+
+ // Return size of input and output tuples.
+ int getInputSize() { return m; }
+ int getOutputSize() { return n; }
+
+ double getDomainMin(int i) { return domain[i][0]; }
+ double getDomainMax(int i) { return domain[i][1]; }
+ double getRangeMin(int i) { return range[i][0]; }
+ double getRangeMax(int i) { return range[i][1]; }
+ GBool getHasRange() { return hasRange; }
+ virtual GBool hasDifferentResultSet(Function *func) { return gFalse; }
+
+ // Transform an input tuple into an output tuple.
+ virtual void transform(double *in, double *out) = 0;
+
+ virtual GBool isOk() = 0;
+
+protected:
+ static Function *parse(Object *funcObj, std::set<int> *usedParents);
+
+ Function(const Function *func);
+
+ int m, n; // size of input and output tuples
+ double // min and max values for function domain
+ domain[funcMaxInputs][2];
+ double // min and max values for function range
+ range[funcMaxOutputs][2];
+ GBool hasRange; // set if range is defined
+};
+
+//------------------------------------------------------------------------
+// IdentityFunction
+//------------------------------------------------------------------------
+
+class IdentityFunction: public Function {
+public:
+
+ IdentityFunction();
+ virtual ~IdentityFunction();
+ virtual Function *copy() { return new IdentityFunction(); }
+ virtual int getType() { return -1; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return gTrue; }
+
+private:
+};
+
+//------------------------------------------------------------------------
+// SampledFunction
+//------------------------------------------------------------------------
+
+class SampledFunction: public Function {
+public:
+
+ SampledFunction(Object *funcObj, Dict *dict);
+ virtual ~SampledFunction();
+ virtual Function *copy() { return new SampledFunction(this); }
+ virtual int getType() { return 0; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+ virtual GBool hasDifferentResultSet(Function *func);
+
+ int getSampleSize(int i) { return sampleSize[i]; }
+ double getEncodeMin(int i) { return encode[i][0]; }
+ double getEncodeMax(int i) { return encode[i][1]; }
+ double getDecodeMin(int i) { return decode[i][0]; }
+ double getDecodeMax(int i) { return decode[i][1]; }
+ double *getSamples() { return samples; }
+ int getSampleNumber() { return nSamples; }
+
+private:
+
+ SampledFunction(const SampledFunction *func);
+
+ int // number of samples for each domain element
+ sampleSize[funcMaxInputs];
+ double // min and max values for domain encoder
+ encode[funcMaxInputs][2];
+ double // min and max values for range decoder
+ decode[funcMaxOutputs][2];
+ double // input multipliers
+ inputMul[funcMaxInputs];
+ int *idxOffset;
+ double *samples; // the samples
+ int nSamples; // size of the samples array
+ double *sBuf; // buffer for the transform function
+ double cacheIn[funcMaxInputs];
+ double cacheOut[funcMaxOutputs];
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// ExponentialFunction
+//------------------------------------------------------------------------
+
+class ExponentialFunction: public Function {
+public:
+
+ ExponentialFunction(Object *funcObj, Dict *dict);
+ virtual ~ExponentialFunction();
+ virtual Function *copy() { return new ExponentialFunction(this); }
+ virtual int getType() { return 2; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+ double *getC0() { return c0; }
+ double *getC1() { return c1; }
+ double getE() { return e; }
+
+private:
+
+ ExponentialFunction(const ExponentialFunction *func);
+
+ double c0[funcMaxOutputs];
+ double c1[funcMaxOutputs];
+ double e;
+ bool isLinear;
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// StitchingFunction
+//------------------------------------------------------------------------
+
+class StitchingFunction: public Function {
+public:
+
+ StitchingFunction(Object *funcObj, Dict *dict, std::set<int> *usedParents);
+ virtual ~StitchingFunction();
+ virtual Function *copy() { return new StitchingFunction(this); }
+ virtual int getType() { return 3; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+ int getNumFuncs() { return k; }
+ Function *getFunc(int i) { return funcs[i]; }
+ double *getBounds() { return bounds; }
+ double *getEncode() { return encode; }
+ double *getScale() { return scale; }
+
+private:
+
+ StitchingFunction(const StitchingFunction *func);
+
+ int k;
+ Function **funcs;
+ double *bounds;
+ double *encode;
+ double *scale;
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// PostScriptFunction
+//------------------------------------------------------------------------
+
+class PostScriptFunction: public Function {
+public:
+
+ PostScriptFunction(Object *funcObj, Dict *dict);
+ virtual ~PostScriptFunction();
+ virtual Function *copy() { return new PostScriptFunction(this); }
+ virtual int getType() { return 4; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+ GooString *getCodeString() { return codeString; }
+
+private:
+
+ PostScriptFunction(const PostScriptFunction *func);
+ GBool parseCode(Stream *str, int *codePtr);
+ GooString *getToken(Stream *str);
+ void resizeCode(int newSize);
+ void exec(PSStack *stack, int codePtr);
+
+ GooString *codeString;
+ PSObject *code;
+ int codeSize;
+ double cacheIn[funcMaxInputs];
+ double cacheOut[funcMaxOutputs];
+ GBool ok;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Gfx.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Gfx.cc
new file mode 100644
index 00000000000..07d95b355a8
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Gfx.cc
@@ -0,0 +1,5501 @@
+//========================================================================
+//
+// Gfx.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
+// Copyright (C) 2005-2013, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Thorkild Stray <thorkild@ifi.uio.no>
+// Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006-2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2007, 2008 Brad Hards <bradh@kde.org>
+// Copyright (C) 2007, 2011 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2007, 2008 Iñigo Martínez <inigomartinez@gmail.com>
+// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2008 Pino Toscano <pino@kde.org>
+// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
+// Copyright (C) 2008 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2009 M Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+// Copyright (C) 2009-2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2009 William Bader <williambader@hotmail.com>
+// Copyright (C) 2009, 2010 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2010 Nils Höglund <nils.hoglund@gmail.com>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2011 Axel Strübing <axel.struebing@freenet.de>
+// Copyright (C) 2012 Even Rouault <even.rouault@mines-paris.org>
+// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012 Lu Wang <coolwanglu@gmail.com>
+// Copyright (C) 2014 Jason Crain <jason@aquaticape.us>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <math.h>
+#include "goo/gmem.h"
+#include "goo/GooTimer.h"
+#include "goo/GooHash.h"
+#include "GlobalParams.h"
+#include "CharTypes.h"
+#include "Object.h"
+#include "PDFDoc.h"
+#include "Array.h"
+#include "Annot.h"
+#include "Dict.h"
+#include "Stream.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "GfxFont.h"
+#include "GfxState.h"
+#include "OutputDev.h"
+#include "Page.h"
+#include "Annot.h"
+#include "Error.h"
+#include "Gfx.h"
+#include "ProfileData.h"
+#include "Catalog.h"
+#include "OptionalContent.h"
+
+// the MSVC math.h doesn't define this
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//------------------------------------------------------------------------
+// constants
+//------------------------------------------------------------------------
+
+// Max recursive depth for a function shading fill.
+#define functionMaxDepth 6
+
+// Max delta allowed in any color component for a function shading fill.
+#define functionColorDelta (dblToCol(1 / 256.0))
+
+// Max number of splits along the t axis for an axial shading fill.
+#define axialMaxSplits 256
+
+// Max delta allowed in any color component for an axial shading fill.
+#define axialColorDelta (dblToCol(1 / 256.0))
+
+// Max number of splits along the t axis for a radial shading fill.
+#define radialMaxSplits 256
+
+// Max delta allowed in any color component for a radial shading fill.
+#define radialColorDelta (dblToCol(1 / 256.0))
+
+// Max recursive depth for a Gouraud triangle shading fill.
+//
+// Triangles will be split at most gouraudMaxDepth times (each time into 4
+// smaller ones). That makes pow(4,gouraudMaxDepth) many triangles for
+// every triangle.
+#define gouraudMaxDepth 6
+
+// Max delta allowed in any color component for a Gouraud triangle
+// shading fill.
+#define gouraudColorDelta (dblToCol(3. / 256.0))
+
+// Gouraud triangle: if the three color parameters differ by at more than this percend of
+// the total color parameter range, the triangle will be refined
+#define gouraudParameterizedColorDelta 5e-3
+
+// Max recursive depth for a patch mesh shading fill.
+#define patchMaxDepth 6
+
+// Max delta allowed in any color component for a patch mesh shading
+// fill.
+#define patchColorDelta (dblToCol((3. / 256.0)))
+
+//------------------------------------------------------------------------
+// Operator table
+//------------------------------------------------------------------------
+
+#ifdef _MSC_VER // this works around a bug in the VC7 compiler
+# pragma optimize("",off)
+#endif
+
+Operator Gfx::opTab[] = {
+ {"\"", 3, {tchkNum, tchkNum, tchkString},
+ &Gfx::opMoveSetShowText},
+ {"'", 1, {tchkString},
+ &Gfx::opMoveShowText},
+ {"B", 0, {tchkNone},
+ &Gfx::opFillStroke},
+ {"B*", 0, {tchkNone},
+ &Gfx::opEOFillStroke},
+ {"BDC", 2, {tchkName, tchkProps},
+ &Gfx::opBeginMarkedContent},
+ {"BI", 0, {tchkNone},
+ &Gfx::opBeginImage},
+ {"BMC", 1, {tchkName},
+ &Gfx::opBeginMarkedContent},
+ {"BT", 0, {tchkNone},
+ &Gfx::opBeginText},
+ {"BX", 0, {tchkNone},
+ &Gfx::opBeginIgnoreUndef},
+ {"CS", 1, {tchkName},
+ &Gfx::opSetStrokeColorSpace},
+ {"DP", 2, {tchkName, tchkProps},
+ &Gfx::opMarkPoint},
+ {"Do", 1, {tchkName},
+ &Gfx::opXObject},
+ {"EI", 0, {tchkNone},
+ &Gfx::opEndImage},
+ {"EMC", 0, {tchkNone},
+ &Gfx::opEndMarkedContent},
+ {"ET", 0, {tchkNone},
+ &Gfx::opEndText},
+ {"EX", 0, {tchkNone},
+ &Gfx::opEndIgnoreUndef},
+ {"F", 0, {tchkNone},
+ &Gfx::opFill},
+ {"G", 1, {tchkNum},
+ &Gfx::opSetStrokeGray},
+ {"ID", 0, {tchkNone},
+ &Gfx::opImageData},
+ {"J", 1, {tchkInt},
+ &Gfx::opSetLineCap},
+ {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeCMYKColor},
+ {"M", 1, {tchkNum},
+ &Gfx::opSetMiterLimit},
+ {"MP", 1, {tchkName},
+ &Gfx::opMarkPoint},
+ {"Q", 0, {tchkNone},
+ &Gfx::opRestore},
+ {"RG", 3, {tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeRGBColor},
+ {"S", 0, {tchkNone},
+ &Gfx::opStroke},
+ {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeColor},
+ {"SCN", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN},
+ &Gfx::opSetStrokeColorN},
+ {"T*", 0, {tchkNone},
+ &Gfx::opTextNextLine},
+ {"TD", 2, {tchkNum, tchkNum},
+ &Gfx::opTextMoveSet},
+ {"TJ", 1, {tchkArray},
+ &Gfx::opShowSpaceText},
+ {"TL", 1, {tchkNum},
+ &Gfx::opSetTextLeading},
+ {"Tc", 1, {tchkNum},
+ &Gfx::opSetCharSpacing},
+ {"Td", 2, {tchkNum, tchkNum},
+ &Gfx::opTextMove},
+ {"Tf", 2, {tchkName, tchkNum},
+ &Gfx::opSetFont},
+ {"Tj", 1, {tchkString},
+ &Gfx::opShowText},
+ {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opSetTextMatrix},
+ {"Tr", 1, {tchkInt},
+ &Gfx::opSetTextRender},
+ {"Ts", 1, {tchkNum},
+ &Gfx::opSetTextRise},
+ {"Tw", 1, {tchkNum},
+ &Gfx::opSetWordSpacing},
+ {"Tz", 1, {tchkNum},
+ &Gfx::opSetHorizScaling},
+ {"W", 0, {tchkNone},
+ &Gfx::opClip},
+ {"W*", 0, {tchkNone},
+ &Gfx::opEOClip},
+ {"b", 0, {tchkNone},
+ &Gfx::opCloseFillStroke},
+ {"b*", 0, {tchkNone},
+ &Gfx::opCloseEOFillStroke},
+ {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opCurveTo},
+ {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opConcat},
+ {"cs", 1, {tchkName},
+ &Gfx::opSetFillColorSpace},
+ {"d", 2, {tchkArray, tchkNum},
+ &Gfx::opSetDash},
+ {"d0", 2, {tchkNum, tchkNum},
+ &Gfx::opSetCharWidth},
+ {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opSetCacheDevice},
+ {"f", 0, {tchkNone},
+ &Gfx::opFill},
+ {"f*", 0, {tchkNone},
+ &Gfx::opEOFill},
+ {"g", 1, {tchkNum},
+ &Gfx::opSetFillGray},
+ {"gs", 1, {tchkName},
+ &Gfx::opSetExtGState},
+ {"h", 0, {tchkNone},
+ &Gfx::opClosePath},
+ {"i", 1, {tchkNum},
+ &Gfx::opSetFlat},
+ {"j", 1, {tchkInt},
+ &Gfx::opSetLineJoin},
+ {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillCMYKColor},
+ {"l", 2, {tchkNum, tchkNum},
+ &Gfx::opLineTo},
+ {"m", 2, {tchkNum, tchkNum},
+ &Gfx::opMoveTo},
+ {"n", 0, {tchkNone},
+ &Gfx::opEndPath},
+ {"q", 0, {tchkNone},
+ &Gfx::opSave},
+ {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opRectangle},
+ {"rg", 3, {tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillRGBColor},
+ {"ri", 1, {tchkName},
+ &Gfx::opSetRenderingIntent},
+ {"s", 0, {tchkNone},
+ &Gfx::opCloseStroke},
+ {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillColor},
+ {"scn", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN},
+ &Gfx::opSetFillColorN},
+ {"sh", 1, {tchkName},
+ &Gfx::opShFill},
+ {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opCurveTo1},
+ {"w", 1, {tchkNum},
+ &Gfx::opSetLineWidth},
+ {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opCurveTo2},
+};
+
+#ifdef _MSC_VER // this works around a bug in the VC7 compiler
+# pragma optimize("",on)
+#endif
+
+#define numOps (sizeof(opTab) / sizeof(Operator))
+
+static inline GBool isSameGfxColor(const GfxColor &colorA, const GfxColor &colorB, Guint nComps, double delta) {
+ for (Guint k = 0; k < nComps; ++k) {
+ if (abs(colorA.c[k] - colorB.c[k]) > delta) {
+ return false;
+ }
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------
+// GfxResources
+//------------------------------------------------------------------------
+
+GfxResources::GfxResources(XRef *xref, Dict *resDictA, GfxResources *nextA) :
+ gStateCache(2, xref) {
+ Object obj1, obj2;
+ Ref r;
+
+ if (resDictA) {
+
+ // build font dictionary
+ Dict *resDict = resDictA->copy(xref);
+ fonts = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ fonts = new GfxFontDict(xref, &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ fonts = new GfxFontDict(xref, NULL, obj1.getDict());
+ }
+ obj1.free();
+
+ // get XObject dictionary
+ resDict->lookup("XObject", &xObjDict);
+
+ // get color space dictionary
+ resDict->lookup("ColorSpace", &colorSpaceDict);
+
+ // get pattern dictionary
+ resDict->lookup("Pattern", &patternDict);
+
+ // get shading dictionary
+ resDict->lookup("Shading", &shadingDict);
+
+ // get graphics state parameter dictionary
+ resDict->lookup("ExtGState", &gStateDict);
+
+ // get properties dictionary
+ resDict->lookup("Properties", &propertiesDict);
+
+ delete resDict;
+ } else {
+ fonts = NULL;
+ xObjDict.initNull();
+ colorSpaceDict.initNull();
+ patternDict.initNull();
+ shadingDict.initNull();
+ gStateDict.initNull();
+ propertiesDict.initNull();
+ }
+
+ next = nextA;
+}
+
+GfxResources::~GfxResources() {
+ if (fonts) {
+ delete fonts;
+ }
+ xObjDict.free();
+ colorSpaceDict.free();
+ patternDict.free();
+ shadingDict.free();
+ gStateDict.free();
+ propertiesDict.free();
+}
+
+GfxFont *GfxResources::lookupFont(char *name) {
+ GfxFont *font;
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->fonts) {
+ if ((font = resPtr->fonts->lookup(name)))
+ return font;
+ }
+ }
+ error(errSyntaxError, -1, "Unknown font tag '{0:s}'", name);
+ return NULL;
+}
+
+GBool GfxResources::lookupXObject(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->xObjDict.isDict()) {
+ if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
+ return gTrue;
+ obj->free();
+ }
+ }
+ error(errSyntaxError, -1, "XObject '{0:s}' is unknown", name);
+ return gFalse;
+}
+
+GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->xObjDict.isDict()) {
+ if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull())
+ return gTrue;
+ obj->free();
+ }
+ }
+ error(errSyntaxError, -1, "XObject '{0:s}' is unknown", name);
+ return gFalse;
+}
+
+GBool GfxResources::lookupMarkedContentNF(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->propertiesDict.isDict()) {
+ if (!resPtr->propertiesDict.dictLookupNF(name, obj)->isNull())
+ return gTrue;
+ obj->free();
+ }
+ }
+ error(errSyntaxError, -1, "Marked Content '{0:s}' is unknown", name);
+ return gFalse;
+}
+
+void GfxResources::lookupColorSpace(const char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->colorSpaceDict.isDict()) {
+ if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
+ return;
+ }
+ obj->free();
+ }
+ }
+ obj->initNull();
+}
+
+GfxPattern *GfxResources::lookupPattern(char *name, OutputDev *out, GfxState *state) {
+ GfxResources *resPtr;
+ GfxPattern *pattern;
+ Object obj;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->patternDict.isDict()) {
+ if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
+ pattern = GfxPattern::parse(resPtr, &obj, out, state);
+ obj.free();
+ return pattern;
+ }
+ obj.free();
+ }
+ }
+ error(errSyntaxError, -1, "Unknown pattern '{0:s}'", name);
+ return NULL;
+}
+
+GfxShading *GfxResources::lookupShading(char *name, OutputDev *out, GfxState *state) {
+ GfxResources *resPtr;
+ GfxShading *shading;
+ Object obj;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->shadingDict.isDict()) {
+ if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
+ shading = GfxShading::parse(resPtr, &obj, out, state);
+ obj.free();
+ return shading;
+ }
+ obj.free();
+ }
+ }
+ error(errSyntaxError, -1, "ExtGState '{0:s}' is unknown", name);
+ return NULL;
+}
+
+GBool GfxResources::lookupGState(char *name, Object *obj) {
+ if (!lookupGStateNF(name, obj))
+ return gFalse;
+
+ if (!obj->isRef())
+ return gTrue;
+
+ const Ref ref = obj->getRef();
+ if (!gStateCache.lookup(ref, obj)->isNull())
+ return gTrue;
+ obj->free();
+
+ gStateCache.put(ref)->copy(obj);
+ return gTrue;
+}
+
+GBool GfxResources::lookupGStateNF(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->gStateDict.isDict()) {
+ if (!resPtr->gStateDict.dictLookupNF(name, obj)->isNull()) {
+ return gTrue;
+ }
+ obj->free();
+ }
+ }
+ error(errSyntaxError, -1, "ExtGState '{0:s}' is unknown", name);
+ return gFalse;
+}
+
+//------------------------------------------------------------------------
+// Gfx
+//------------------------------------------------------------------------
+
+Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
+ double hDPI, double vDPI, PDFRectangle *box,
+ PDFRectangle *cropBox, int rotate,
+ GBool (*abortCheckCbkA)(void *data),
+ void *abortCheckCbkDataA, XRef *xrefA)
+{
+ int i;
+
+ doc = docA;
+ xref = (xrefA == NULL) ? doc->getXRef() : xrefA;
+ catalog = doc->getCatalog();
+ subPage = gFalse;
+ printCommands = globalParams->getPrintCommands();
+ profileCommands = globalParams->getProfileCommands();
+ mcStack = NULL;
+ parser = NULL;
+
+ // start the resource stack
+ res = new GfxResources(xref, resDict, NULL);
+
+ // initialize
+ out = outA;
+ state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown());
+ stackHeight = 1;
+ pushStateGuard();
+ fontChanged = gFalse;
+ clip = clipNone;
+ ignoreUndef = 0;
+ out->startPage(pageNum, state, xref);
+ out->setDefaultCTM(state->getCTM());
+ out->updateAll(state);
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = state->getCTM()[i];
+ }
+ formDepth = 0;
+ ocState = gTrue;
+ parser = NULL;
+ abortCheckCbk = abortCheckCbkA;
+ abortCheckCbkData = abortCheckCbkDataA;
+
+ // set crop box
+ if (cropBox) {
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+#ifdef USE_CMS
+ initDisplayProfile();
+#endif
+}
+
+Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict,
+ PDFRectangle *box, PDFRectangle *cropBox,
+ GBool (*abortCheckCbkA)(void *data),
+ void *abortCheckCbkDataA, XRef *xrefA)
+{
+ int i;
+
+ doc = docA;
+ xref = (xrefA == NULL) ? doc->getXRef() : xrefA;
+ catalog = doc->getCatalog();
+ subPage = gTrue;
+ printCommands = globalParams->getPrintCommands();
+ profileCommands = globalParams->getProfileCommands();
+ mcStack = NULL;
+ parser = NULL;
+
+ // start the resource stack
+ res = new GfxResources(xref, resDict, NULL);
+
+ // initialize
+ out = outA;
+ state = new GfxState(72, 72, box, 0, gFalse);
+ stackHeight = 1;
+ pushStateGuard();
+ fontChanged = gFalse;
+ clip = clipNone;
+ ignoreUndef = 0;
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = state->getCTM()[i];
+ }
+ formDepth = 0;
+ ocState = gTrue;
+ parser = NULL;
+ abortCheckCbk = abortCheckCbkA;
+ abortCheckCbkData = abortCheckCbkDataA;
+
+ // set crop box
+ if (cropBox) {
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+#ifdef USE_CMS
+ initDisplayProfile();
+#endif
+}
+
+#ifdef USE_CMS
+
+#ifdef USE_LCMS1
+#include <lcms.h>
+#else
+#include <lcms2.h>
+#define LCMS_FLAGS cmsFLAGS_NOOPTIMIZE
+#endif
+
+void Gfx::initDisplayProfile() {
+ Object catDict;
+ xref->getCatalog(&catDict);
+ if (catDict.isDict()) {
+ Object outputIntents;
+ catDict.dictLookup("OutputIntents", &outputIntents);
+ if (outputIntents.isArray() && outputIntents.arrayGetLength() == 1) {
+ Object firstElement;
+ outputIntents.arrayGet(0, &firstElement);
+ if (firstElement.isDict()) {
+ Object profile;
+ firstElement.dictLookup("DestOutputProfile", &profile);
+ if (profile.isStream()) {
+ Stream *iccStream = profile.getStream();
+ int length = 0;
+ Guchar *profBuf = iccStream->toUnsignedChars(&length, 65536, 65536);
+ cmsHPROFILE hp = cmsOpenProfileFromMem(profBuf,length);
+ if (hp == 0) {
+ error(errSyntaxWarning, -1, "read ICCBased color space profile error");
+ } else {
+ state->setDisplayProfile(hp);
+ }
+ gfree(profBuf);
+ }
+ profile.free();
+ }
+ firstElement.free();
+ }
+ outputIntents.free();
+ }
+ catDict.free();
+}
+
+#endif
+
+Gfx::~Gfx() {
+ while (stateGuards.size()) {
+ popStateGuard();
+ }
+ if (!subPage) {
+ out->endPage();
+ }
+ // There shouldn't be more saves, but pop them if there were any
+ while (state->hasSaves()) {
+ error(errSyntaxError, -1, "Found state under last state guard. Popping.");
+ restoreState();
+ }
+ delete state;
+ while (res) {
+ popResources();
+ }
+ while (mcStack) {
+ popMarkedContent();
+ }
+}
+
+void Gfx::display(Object *obj, GBool topLevel) {
+ Object obj2;
+ int i;
+
+ if (obj->isArray()) {
+ for (i = 0; i < obj->arrayGetLength(); ++i) {
+ obj->arrayGet(i, &obj2);
+ if (!obj2.isStream()) {
+ error(errSyntaxError, -1, "Weird page contents");
+ obj2.free();
+ return;
+ }
+ obj2.free();
+ }
+ } else if (!obj->isStream()) {
+ error(errSyntaxError, -1, "Weird page contents");
+ return;
+ }
+ parser = new Parser(xref, new Lexer(xref, obj), gFalse);
+ go(topLevel);
+ delete parser;
+ parser = NULL;
+}
+
+void Gfx::go(GBool topLevel) {
+ Object obj;
+ Object args[maxArgs];
+ int numArgs, i;
+ int lastAbortCheck;
+
+ // scan a sequence of objects
+ pushStateGuard();
+ updateLevel = 1; // make sure even empty pages trigger a call to dump()
+ lastAbortCheck = 0;
+ numArgs = 0;
+ parser->getObj(&obj);
+ while (!obj.isEOF()) {
+ commandAborted = gFalse;
+
+ // got a command - execute it
+ if (obj.isCmd()) {
+ if (printCommands) {
+ obj.print(stdout);
+ for (i = 0; i < numArgs; ++i) {
+ printf(" ");
+ args[i].print(stdout);
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+ GooTimer timer;
+
+ // Run the operation
+ execOp(&obj, args, numArgs);
+
+ // Update the profile information
+ if (profileCommands) {
+ GooHash *hash;
+
+ hash = out->getProfileHash ();
+ if (hash) {
+ GooString *cmd_g;
+ ProfileData *data_p;
+
+ cmd_g = new GooString (obj.getCmd());
+ data_p = (ProfileData *)hash->lookup (cmd_g);
+ if (data_p == NULL) {
+ data_p = new ProfileData();
+ hash->add (cmd_g, data_p);
+ }
+
+ data_p->addElement(timer.getElapsed ());
+ }
+ }
+ obj.free();
+ for (i = 0; i < numArgs; ++i)
+ args[i].free();
+ numArgs = 0;
+
+ // periodically update display
+ if (++updateLevel >= 20000) {
+ out->dump();
+ updateLevel = 0;
+ }
+
+ // did the command throw an exception
+ if (commandAborted) {
+ // don't propogate; recursive drawing comes from Form XObjects which
+ // should probably be drawn in a separate context anyway for caching
+ commandAborted = gFalse;
+ break;
+ }
+
+ // check for an abort
+ if (abortCheckCbk) {
+ if (updateLevel - lastAbortCheck > 10) {
+ if ((*abortCheckCbk)(abortCheckCbkData)) {
+ break;
+ }
+ lastAbortCheck = updateLevel;
+ }
+ }
+
+ // got an argument - save it
+ } else if (numArgs < maxArgs) {
+ args[numArgs++] = obj;
+
+ // too many arguments - something is wrong
+ } else {
+ error(errSyntaxError, getPos(), "Too many args in content stream");
+ if (printCommands) {
+ printf("throwing away arg: ");
+ obj.print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+ obj.free();
+ }
+
+ // grab the next object
+ parser->getObj(&obj);
+ }
+ obj.free();
+
+ // args at end with no command
+ if (numArgs > 0) {
+ error(errSyntaxError, getPos(), "Leftover args in content stream");
+ if (printCommands) {
+ printf("%d leftovers:", numArgs);
+ for (i = 0; i < numArgs; ++i) {
+ printf(" ");
+ args[i].print(stdout);
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+ for (i = 0; i < numArgs; ++i)
+ args[i].free();
+ }
+
+ popStateGuard();
+
+ // update display
+ if (topLevel && updateLevel > 0) {
+ out->dump();
+ }
+}
+
+void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
+ Operator *op;
+ char *name;
+ Object *argPtr;
+ int i;
+
+ // find operator
+ name = cmd->getCmd();
+ if (!(op = findOp(name))) {
+ if (ignoreUndef == 0)
+ error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name);
+ return;
+ }
+
+ // type check args
+ argPtr = args;
+ if (op->numArgs >= 0) {
+ if (numArgs < op->numArgs) {
+ error(errSyntaxError, getPos(), "Too few ({0:d}) args to '{1:s}' operator", numArgs, name);
+ commandAborted = gTrue;
+ return;
+ }
+ if (numArgs > op->numArgs) {
+#if 0
+ error(errSyntaxWarning, getPos(),
+ "Too many ({0:d}) args to '{1:s}' operator", numArgs, name);
+#endif
+ argPtr += numArgs - op->numArgs;
+ numArgs = op->numArgs;
+ }
+ } else {
+ if (numArgs > -op->numArgs) {
+ error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator",
+ numArgs, name);
+ return;
+ }
+ }
+ for (i = 0; i < numArgs; ++i) {
+ if (!checkArg(&argPtr[i], op->tchk[i])) {
+ error(errSyntaxError, getPos(), "Arg #{0:d} to '{1:s}' operator is wrong type ({2:s})",
+ i, name, argPtr[i].getTypeName());
+ return;
+ }
+ }
+
+ // do it
+ (this->*op->func)(argPtr, numArgs);
+}
+
+Operator *Gfx::findOp(char *name) {
+ int a, b, m, cmp;
+
+ a = -1;
+ b = numOps;
+ cmp = 0; // make gcc happy
+ // invariant: opTab[a] < name < opTab[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ cmp = strcmp(opTab[m].name, name);
+ if (cmp < 0)
+ a = m;
+ else if (cmp > 0)
+ b = m;
+ else
+ a = b = m;
+ }
+ if (cmp != 0)
+ return NULL;
+ return &opTab[a];
+}
+
+GBool Gfx::checkArg(Object *arg, TchkType type) {
+ switch (type) {
+ case tchkBool: return arg->isBool();
+ case tchkInt: return arg->isInt();
+ case tchkNum: return arg->isNum();
+ case tchkString: return arg->isString();
+ case tchkName: return arg->isName();
+ case tchkArray: return arg->isArray();
+ case tchkProps: return arg->isDict() || arg->isName();
+ case tchkSCN: return arg->isNum() || arg->isName();
+ case tchkNone: return gFalse;
+ }
+ return gFalse;
+}
+
+Goffset Gfx::getPos() {
+ return parser ? parser->getPos() : -1;
+}
+
+//------------------------------------------------------------------------
+// graphics state operators
+//------------------------------------------------------------------------
+
+void Gfx::opSave(Object args[], int numArgs) {
+ saveState();
+}
+
+void Gfx::opRestore(Object args[], int numArgs) {
+ restoreState();
+}
+
+void Gfx::opConcat(Object args[], int numArgs) {
+ state->concatCTM(args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ out->updateCTM(state, args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ fontChanged = gTrue;
+}
+
+void Gfx::opSetDash(Object args[], int numArgs) {
+ Array *a;
+ int length;
+ Object obj;
+ double *dash;
+ int i;
+
+ a = args[0].getArray();
+ length = a->getLength();
+ if (length == 0) {
+ dash = NULL;
+ } else {
+ dash = (double *)gmallocn(length, sizeof(double));
+ for (i = 0; i < length; ++i) {
+ a->get(i, &obj);
+ if (obj.isNum()) {
+ dash[i] = obj.getNum();
+ }
+ obj.free();
+ }
+ }
+ state->setLineDash(dash, length, args[1].getNum());
+ out->updateLineDash(state);
+}
+
+void Gfx::opSetFlat(Object args[], int numArgs) {
+ state->setFlatness((int)args[0].getNum());
+ out->updateFlatness(state);
+}
+
+void Gfx::opSetLineJoin(Object args[], int numArgs) {
+ state->setLineJoin(args[0].getInt());
+ out->updateLineJoin(state);
+}
+
+void Gfx::opSetLineCap(Object args[], int numArgs) {
+ state->setLineCap(args[0].getInt());
+ out->updateLineCap(state);
+}
+
+void Gfx::opSetMiterLimit(Object args[], int numArgs) {
+ state->setMiterLimit(args[0].getNum());
+ out->updateMiterLimit(state);
+}
+
+void Gfx::opSetLineWidth(Object args[], int numArgs) {
+ state->setLineWidth(args[0].getNum());
+ out->updateLineWidth(state);
+}
+
+void Gfx::opSetExtGState(Object args[], int numArgs) {
+ Object obj1, obj2, obj3, obj4, obj5;
+ Object args2[2];
+ GfxBlendMode mode;
+ GBool haveFillOP;
+ Function *funcs[4];
+ GfxColor backdropColor;
+ GBool haveBackdropColor;
+ GfxColorSpace *blendingColorSpace;
+ GBool alpha, isolated, knockout;
+ double opac;
+ int i;
+
+ if (!res->lookupGState(args[0].getName(), &obj1)) {
+ return;
+ }
+ if (!obj1.isDict()) {
+ error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type", args[0].getName());
+ obj1.free();
+ return;
+ }
+ if (printCommands) {
+ printf(" gfx state dict: ");
+ obj1.print();
+ printf("\n");
+ }
+
+ // parameters that are also set by individual PDF operators
+ if (obj1.dictLookup("LW", &obj2)->isNum()) {
+ opSetLineWidth(&obj2, 1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("LC", &obj2)->isInt()) {
+ opSetLineCap(&obj2, 1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("LJ", &obj2)->isInt()) {
+ opSetLineJoin(&obj2, 1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("ML", &obj2)->isNum()) {
+ opSetMiterLimit(&obj2, 1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("D", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 2) {
+ obj2.arrayGet(0, &args2[0]);
+ obj2.arrayGet(1, &args2[1]);
+ if (args2[0].isArray() && args2[1].isNum()) {
+ opSetDash(args2, 2);
+ }
+ args2[0].free();
+ args2[1].free();
+ }
+ obj2.free();
+#if 0 //~ need to add a new version of GfxResources::lookupFont() that
+ //~ takes an indirect ref instead of a name
+ if (obj1.dictLookup("Font", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 2) {
+ obj2.arrayGet(0, &args2[0]);
+ obj2.arrayGet(1, &args2[1]);
+ if (args2[0].isDict() && args2[1].isNum()) {
+ opSetFont(args2, 2);
+ }
+ args2[0].free();
+ args2[1].free();
+ }
+ obj2.free();
+#endif
+ if (obj1.dictLookup("FL", &obj2)->isNum()) {
+ opSetFlat(&obj2, 1);
+ }
+ obj2.free();
+
+ // transparency support: blend mode, fill/stroke opacity
+ if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+ if (state->parseBlendMode(&obj2, &mode)) {
+ state->setBlendMode(mode);
+ out->updateBlendMode(state);
+ } else {
+ error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("ca", &obj2)->isNum()) {
+ opac = obj2.getNum();
+ state->setFillOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
+ out->updateFillOpacity(state);
+ }
+ obj2.free();
+ if (obj1.dictLookup("CA", &obj2)->isNum()) {
+ opac = obj2.getNum();
+ state->setStrokeOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
+ out->updateStrokeOpacity(state);
+ }
+ obj2.free();
+
+ // fill/stroke overprint, overprint mode
+ if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
+ state->setFillOverprint(obj2.getBool());
+ out->updateFillOverprint(state);
+ }
+ obj2.free();
+ if (obj1.dictLookup("OP", &obj2)->isBool()) {
+ state->setStrokeOverprint(obj2.getBool());
+ out->updateStrokeOverprint(state);
+ if (!haveFillOP) {
+ state->setFillOverprint(obj2.getBool());
+ out->updateFillOverprint(state);
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("OPM", &obj2)->isInt()) {
+ state->setOverprintMode(obj2.getInt());
+ out->updateOverprintMode(state);
+ }
+ obj2.free();
+
+ // stroke adjust
+ if (obj1.dictLookup("SA", &obj2)->isBool()) {
+ state->setStrokeAdjust(obj2.getBool());
+ out->updateStrokeAdjust(state);
+ }
+ obj2.free();
+
+ // transfer function
+ if (obj1.dictLookup("TR2", &obj2)->isNull()) {
+ obj2.free();
+ obj1.dictLookup("TR", &obj2);
+ }
+ if (obj2.isName("Default") ||
+ obj2.isName("Identity")) {
+ funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL;
+ state->setTransfer(funcs);
+ out->updateTransfer(state);
+ } else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
+ for (i = 0; i < 4; ++i) {
+ obj2.arrayGet(i, &obj3);
+ funcs[i] = Function::parse(&obj3);
+ obj3.free();
+ if (!funcs[i]) {
+ break;
+ }
+ }
+ if (i == 4) {
+ state->setTransfer(funcs);
+ out->updateTransfer(state);
+ }
+ } else if (obj2.isName() || obj2.isDict() || obj2.isStream()) {
+ if ((funcs[0] = Function::parse(&obj2))) {
+ funcs[1] = funcs[2] = funcs[3] = NULL;
+ state->setTransfer(funcs);
+ out->updateTransfer(state);
+ }
+ } else if (!obj2.isNull()) {
+ error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState");
+ }
+ obj2.free();
+
+ // alpha is shape
+ if (obj1.dictLookup("AIS", &obj2)->isBool()) {
+ state->setAlphaIsShape(obj2.getBool());
+ out->updateAlphaIsShape(state);
+ }
+ obj2.free();
+
+ // text knockout
+ if (obj1.dictLookup("TK", &obj2)->isBool()) {
+ state->setTextKnockout(obj2.getBool());
+ out->updateTextKnockout(state);
+ }
+ obj2.free();
+
+ // soft mask
+ if (!obj1.dictLookup("SMask", &obj2)->isNull()) {
+ if (obj2.isName("None")) {
+ out->clearSoftMask(state);
+ } else if (obj2.isDict()) {
+ if (obj2.dictLookup("S", &obj3)->isName("Alpha")) {
+ alpha = gTrue;
+ } else { // "Luminosity"
+ alpha = gFalse;
+ }
+ obj3.free();
+ funcs[0] = NULL;
+ if (!obj2.dictLookup("TR", &obj3)->isNull()) {
+ if (obj3.isName("Default") ||
+ obj3.isName("Identity")) {
+ funcs[0] = NULL;
+ } else {
+ funcs[0] = Function::parse(&obj3);
+ if (funcs[0] == NULL ||
+ funcs[0]->getInputSize() != 1 ||
+ funcs[0]->getOutputSize() != 1) {
+ error(errSyntaxError, getPos(),
+ "Invalid transfer function in soft mask in ExtGState");
+ delete funcs[0];
+ funcs[0] = NULL;
+ }
+ }
+ }
+ obj3.free();
+ if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) {
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ backdropColor.c[i] = 0;
+ }
+ for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+ obj3.arrayGet(i, &obj4);
+ if (obj4.isNum()) {
+ backdropColor.c[i] = dblToCol(obj4.getNum());
+ }
+ obj4.free();
+ }
+ }
+ obj3.free();
+ if (obj2.dictLookup("G", &obj3)->isStream()) {
+ if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) {
+ blendingColorSpace = NULL;
+ isolated = knockout = gFalse;
+ if (!obj4.dictLookup("CS", &obj5)->isNull()) {
+ blendingColorSpace = GfxColorSpace::parse(res, &obj5, out, state);
+ }
+ obj5.free();
+ if (obj4.dictLookup("I", &obj5)->isBool()) {
+ isolated = obj5.getBool();
+ }
+ obj5.free();
+ if (obj4.dictLookup("K", &obj5)->isBool()) {
+ knockout = obj5.getBool();
+ }
+ obj5.free();
+ if (!haveBackdropColor) {
+ if (blendingColorSpace) {
+ blendingColorSpace->getDefaultColor(&backdropColor);
+ } else {
+ //~ need to get the parent or default color space (?)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ backdropColor.c[i] = 0;
+ }
+ }
+ }
+ doSoftMask(&obj3, alpha, blendingColorSpace,
+ isolated, knockout, funcs[0], &backdropColor);
+ if (funcs[0]) {
+ delete funcs[0];
+ }
+ } else {
+ error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
+ }
+ obj4.free();
+ } else {
+ error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
+ }
+ obj3.free();
+ } else if (!obj2.isNull()) {
+ error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("Font", &obj2)->isArray()) {
+ GfxFont *font;
+ if (obj2.arrayGetLength() == 2) {
+ Object fargs0, fargs1;
+
+ obj2.arrayGetNF(0,&fargs0);
+ obj2.arrayGet(1,&fargs1);
+ if (fargs0.isRef() && fargs1.isNum()) {
+ Object fobj;
+ Ref r;
+
+ fargs0.fetch(xref, &fobj);
+ if (fobj.isDict()) {
+ r = fargs0.getRef();
+ font = GfxFont::makeFont(xref,args[0].getName(),r,fobj.getDict());
+ state->setFont(font,fargs1.getNum());
+ fontChanged = gTrue;
+ }
+ fobj.free();
+ }
+ fargs0.free();
+ fargs1.free();
+ } else {
+ error(errSyntaxError, getPos(), "Number of args mismatch for /Font in ExtGState");
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("LW", &obj2)->isNum()) {
+ opSetLineWidth(&obj2,1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("LC", &obj2)->isInt()) {
+ opSetLineCap(&obj2,1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("LJ", &obj2)->isInt()) {
+ opSetLineJoin(&obj2,1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("ML", &obj2)->isNum()) {
+ opSetMiterLimit(&obj2,1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("D", &obj2)->isArray()) {
+ if (obj2.arrayGetLength() == 2) {
+ Object dargs[2];
+
+ obj2.arrayGetNF(0,&dargs[0]);
+ obj2.arrayGet(1,&dargs[1]);
+ if (dargs[0].isArray() && dargs[1].isInt()) {
+ opSetDash(dargs,2);
+ }
+ dargs[0].free();
+ dargs[1].free();
+ } else {
+ error(errSyntaxError, getPos(), "Number of args mismatch for /D in ExtGState");
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("RI", &obj2)->isName()) {
+ opSetRenderingIntent(&obj2,1);
+ }
+ obj2.free();
+ if (obj1.dictLookup("FL", &obj2)->isNum()) {
+ opSetFlat(&obj2,1);
+ }
+ obj2.free();
+
+ obj1.free();
+}
+
+void Gfx::doSoftMask(Object *str, GBool alpha,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ Function *transferFunc, GfxColor *backdropColor) {
+ Dict *dict, *resDict;
+ double m[6], bbox[4];
+ Object obj1, obj2;
+ int i;
+
+ // check for excessive recursion
+ if (formDepth > 20) {
+ return;
+ }
+
+ // get stream dict
+ dict = str->streamGetDict();
+
+ // check form type
+ dict->lookup("FormType", &obj1);
+ if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
+ error(errSyntaxError, getPos(), "Unknown form type");
+ }
+ obj1.free();
+
+ // get bounding box
+ dict->lookup("BBox", &obj1);
+ if (!obj1.isArray()) {
+ obj1.free();
+ error(errSyntaxError, getPos(), "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (likely(obj2.isNum())) bbox[i] = obj2.getNum();
+ else {
+ obj2.free();
+ obj1.free();
+ error(errSyntaxError, getPos(), "Bad form bounding box (non number)");
+ return;
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ // get matrix
+ dict->lookup("Matrix", &obj1);
+ if (obj1.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (likely(obj2.isNum())) m[i] = obj2.getNum();
+ else m[i] = 0;
+ obj2.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ obj1.free();
+
+ // get resources
+ dict->lookup("Resources", &obj1);
+ resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
+
+ // draw it
+ ++formDepth;
+ drawForm(str, resDict, m, bbox, gTrue, gTrue,
+ blendingColorSpace, isolated, knockout,
+ alpha, transferFunc, backdropColor);
+ --formDepth;
+
+ if (blendingColorSpace) {
+ delete blendingColorSpace;
+ }
+ obj1.free();
+}
+
+void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
+ state->setRenderingIntent(args[0].getName());
+}
+
+//------------------------------------------------------------------------
+// color operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetFillGray(Object args[], int numArgs) {
+ GfxColor color;
+ GfxColorSpace *colorSpace = NULL;
+ Object obj;
+
+ state->setFillPattern(NULL);
+ res->lookupColorSpace("DefaultGray", &obj);
+ if (!obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(res, &obj, out, state);
+ }
+ if (colorSpace == NULL) {
+ colorSpace = new GfxDeviceGrayColorSpace();
+ }
+ obj.free();
+ state->setFillColorSpace(colorSpace);
+ out->updateFillColorSpace(state);
+ color.c[0] = dblToCol(args[0].getNum());
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeGray(Object args[], int numArgs) {
+ GfxColor color;
+ GfxColorSpace *colorSpace = NULL;
+ Object obj;
+
+ state->setStrokePattern(NULL);
+ res->lookupColorSpace("DefaultGray", &obj);
+ if (!obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(res, &obj, out, state);
+ }
+ if (colorSpace == NULL) {
+ colorSpace = new GfxDeviceGrayColorSpace();
+ }
+ obj.free();
+ state->setStrokeColorSpace(colorSpace);
+ out->updateStrokeColorSpace(state);
+ color.c[0] = dblToCol(args[0].getNum());
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
+ GfxColor color;
+ GfxColorSpace *colorSpace = NULL;
+ Object obj;
+ int i;
+
+ res->lookupColorSpace("DefaultCMYK", &obj);
+ if (!obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(res, &obj, out, state);
+ }
+ if (colorSpace == NULL) {
+ colorSpace = new GfxDeviceCMYKColorSpace();
+ }
+ obj.free();
+ state->setFillPattern(NULL);
+ state->setFillColorSpace(colorSpace);
+ out->updateFillColorSpace(state);
+ for (i = 0; i < 4; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
+ GfxColor color;
+ GfxColorSpace *colorSpace = NULL;
+ Object obj;
+ int i;
+
+ state->setStrokePattern(NULL);
+ res->lookupColorSpace("DefaultCMYK", &obj);
+ if (!obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(res, &obj, out, state);
+ }
+ if (colorSpace == NULL) {
+ colorSpace = new GfxDeviceCMYKColorSpace();
+ }
+ obj.free();
+ state->setStrokeColorSpace(colorSpace);
+ out->updateStrokeColorSpace(state);
+ for (i = 0; i < 4; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
+ Object obj;
+ GfxColorSpace *colorSpace = NULL;
+ GfxColor color;
+ int i;
+
+ state->setFillPattern(NULL);
+ res->lookupColorSpace("DefaultRGB", &obj);
+ if (!obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(res, &obj, out, state);
+ }
+ if (colorSpace == NULL) {
+ colorSpace = new GfxDeviceRGBColorSpace();
+ }
+ obj.free();
+ state->setFillColorSpace(colorSpace);
+ out->updateFillColorSpace(state);
+ for (i = 0; i < 3; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
+ Object obj;
+ GfxColorSpace *colorSpace = NULL;
+ GfxColor color;
+ int i;
+
+ state->setStrokePattern(NULL);
+ res->lookupColorSpace("DefaultRGB", &obj);
+ if (!obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(res, &obj, out, state);
+ }
+ if (colorSpace == NULL) {
+ colorSpace = new GfxDeviceRGBColorSpace();
+ }
+ obj.free();
+ state->setStrokeColorSpace(colorSpace);
+ out->updateStrokeColorSpace(state);
+ for (i = 0; i < 3; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
+ Object obj;
+ GfxColorSpace *colorSpace;
+ GfxColor color;
+
+ res->lookupColorSpace(args[0].getName(), &obj);
+ if (obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(res, &args[0], out, state);
+ } else {
+ colorSpace = GfxColorSpace::parse(res, &obj, out, state);
+ }
+ obj.free();
+ if (colorSpace) {
+ state->setFillPattern(NULL);
+ state->setFillColorSpace(colorSpace);
+ out->updateFillColorSpace(state);
+ colorSpace->getDefaultColor(&color);
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+ } else {
+ error(errSyntaxError, getPos(), "Bad color space (fill)");
+ }
+}
+
+void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
+ Object obj;
+ GfxColorSpace *colorSpace;
+ GfxColor color;
+
+ state->setStrokePattern(NULL);
+ res->lookupColorSpace(args[0].getName(), &obj);
+ if (obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(res, &args[0], out, state);
+ } else {
+ colorSpace = GfxColorSpace::parse(res, &obj, out, state);
+ }
+ obj.free();
+ if (colorSpace) {
+ state->setStrokeColorSpace(colorSpace);
+ out->updateStrokeColorSpace(state);
+ colorSpace->getDefaultColor(&color);
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ } else {
+ error(errSyntaxError, getPos(), "Bad color space (stroke)");
+ }
+}
+
+void Gfx::opSetFillColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ if (numArgs != state->getFillColorSpace()->getNComps()) {
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'sc' command");
+ return;
+ }
+ state->setFillPattern(NULL);
+ for (i = 0; i < numArgs; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ if (numArgs != state->getStrokeColorSpace()->getNComps()) {
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SC' command");
+ return;
+ }
+ state->setStrokePattern(NULL);
+ for (i = 0; i < numArgs; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillColorN(Object args[], int numArgs) {
+ GfxColor color;
+ GfxPattern *pattern;
+ int i;
+
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ if (numArgs > 1) {
+ if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
+ numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
+ ->getUnder()->getNComps()) {
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
+ return;
+ }
+ for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = dblToCol(args[i].getNum());
+ } else {
+ color.c[i] = 0; // TODO Investigate if this is what Adobe does
+ }
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+ }
+ if (numArgs > 0) {
+ if (args[numArgs-1].isName() &&
+ (pattern = res->lookupPattern(args[numArgs-1].getName(), out, state))) {
+ state->setFillPattern(pattern);
+ }
+ }
+
+ } else {
+ if (numArgs != state->getFillColorSpace()->getNComps()) {
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
+ return;
+ }
+ state->setFillPattern(NULL);
+ for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = dblToCol(args[i].getNum());
+ } else {
+ color.c[i] = 0; // TODO Investigate if this is what Adobe does
+ }
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+ }
+}
+
+void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
+ GfxColor color;
+ GfxPattern *pattern;
+ int i;
+
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ if (numArgs > 1) {
+ if (!((GfxPatternColorSpace *)state->getStrokeColorSpace())
+ ->getUnder() ||
+ numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
+ ->getUnder()->getNComps()) {
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
+ return;
+ }
+ for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = dblToCol(args[i].getNum());
+ } else {
+ color.c[i] = 0; // TODO Investigate if this is what Adobe does
+ }
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ }
+ if (unlikely(numArgs <= 0)) {
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
+ return;
+ }
+ if (args[numArgs-1].isName() &&
+ (pattern = res->lookupPattern(args[numArgs-1].getName(), out, state))) {
+ state->setStrokePattern(pattern);
+ }
+
+ } else {
+ if (numArgs != state->getStrokeColorSpace()->getNComps()) {
+ error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
+ return;
+ }
+ state->setStrokePattern(NULL);
+ for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = dblToCol(args[i].getNum());
+ } else {
+ color.c[i] = 0; // TODO Investigate if this is what Adobe does
+ }
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ }
+}
+
+//------------------------------------------------------------------------
+// path segment operators
+//------------------------------------------------------------------------
+
+void Gfx::opMoveTo(Object args[], int numArgs) {
+ state->moveTo(args[0].getNum(), args[1].getNum());
+}
+
+void Gfx::opLineTo(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ error(errSyntaxError, getPos(), "No current point in lineto");
+ return;
+ }
+ state->lineTo(args[0].getNum(), args[1].getNum());
+}
+
+void Gfx::opCurveTo(Object args[], int numArgs) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(errSyntaxError, getPos(), "No current point in curveto");
+ return;
+ }
+ x1 = args[0].getNum();
+ y1 = args[1].getNum();
+ x2 = args[2].getNum();
+ y2 = args[3].getNum();
+ x3 = args[4].getNum();
+ y3 = args[5].getNum();
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opCurveTo1(Object args[], int numArgs) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(errSyntaxError, getPos(), "No current point in curveto1");
+ return;
+ }
+ x1 = state->getCurX();
+ y1 = state->getCurY();
+ x2 = args[0].getNum();
+ y2 = args[1].getNum();
+ x3 = args[2].getNum();
+ y3 = args[3].getNum();
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opCurveTo2(Object args[], int numArgs) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(errSyntaxError, getPos(), "No current point in curveto2");
+ return;
+ }
+ x1 = args[0].getNum();
+ y1 = args[1].getNum();
+ x2 = args[2].getNum();
+ y2 = args[3].getNum();
+ x3 = x2;
+ y3 = y2;
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opRectangle(Object args[], int numArgs) {
+ double x, y, w, h;
+
+ x = args[0].getNum();
+ y = args[1].getNum();
+ w = args[2].getNum();
+ h = args[3].getNum();
+ state->moveTo(x, y);
+ state->lineTo(x + w, y);
+ state->lineTo(x + w, y + h);
+ state->lineTo(x, y + h);
+ state->closePath();
+}
+
+void Gfx::opClosePath(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ error(errSyntaxError, getPos(), "No current point in closepath");
+ return;
+ }
+ state->closePath();
+}
+
+//------------------------------------------------------------------------
+// path painting operators
+//------------------------------------------------------------------------
+
+void Gfx::opEndPath(Object args[], int numArgs) {
+ doEndPath();
+}
+
+void Gfx::opStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(errSyntaxError, getPos(), "No path in stroke");
+ return;
+ }
+ if (state->isPath()) {
+ if (ocState) {
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(errSyntaxError, getPos(), "No path in closepath/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ if (ocState) {
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opFill(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(errSyntaxError, getPos(), "No path in fill");
+ return;
+ }
+ if (state->isPath()) {
+ if (ocState) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opEOFill(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(errSyntaxError, getPos(), "No path in eofill");
+ return;
+ }
+ if (state->isPath()) {
+ if (ocState) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(errSyntaxError, getPos(), "No path in fill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ if (ocState) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opCloseFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(errSyntaxError, getPos(), "No path in closepath/fill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ if (ocState) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opEOFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(errSyntaxError, getPos(), "No path in eofill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ if (ocState) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(errSyntaxError, getPos(), "No path in closepath/eofill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ if (ocState) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::doPatternFill(GBool eoFill) {
+ GfxPattern *pattern;
+
+ // this is a bit of a kludge -- patterns can be really slow, so we
+ // skip them if we're only doing text extraction, since they almost
+ // certainly don't contain any text
+ if (!out->needNonText()) {
+ return;
+ }
+
+ if (!(pattern = state->getFillPattern())) {
+ return;
+ }
+ switch (pattern->getType()) {
+ case 1:
+ doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill, gFalse);
+ break;
+ case 2:
+ doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill, gFalse);
+ break;
+ default:
+ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in fill",
+ pattern->getType());
+ break;
+ }
+}
+
+void Gfx::doPatternStroke() {
+ GfxPattern *pattern;
+
+ // this is a bit of a kludge -- patterns can be really slow, so we
+ // skip them if we're only doing text extraction, since they almost
+ // certainly don't contain any text
+ if (!out->needNonText()) {
+ return;
+ }
+
+ if (!(pattern = state->getStrokePattern())) {
+ return;
+ }
+ switch (pattern->getType()) {
+ case 1:
+ doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse, gFalse);
+ break;
+ case 2:
+ doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse, gFalse);
+ break;
+ default:
+ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in stroke",
+ pattern->getType());
+ break;
+ }
+}
+
+void Gfx::doPatternText() {
+ GfxPattern *pattern;
+
+ // this is a bit of a kludge -- patterns can be really slow, so we
+ // skip them if we're only doing text extraction, since they almost
+ // certainly don't contain any text
+ if (!out->needNonText()) {
+ return;
+ }
+
+ if (!(pattern = state->getFillPattern())) {
+ return;
+ }
+ switch (pattern->getType()) {
+ case 1:
+ doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, gFalse, gTrue);
+ break;
+ case 2:
+ doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, gFalse, gTrue);
+ break;
+ default:
+ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in fill",
+ pattern->getType());
+ break;
+ }
+}
+
+void Gfx::doPatternImageMask(Object *ref, Stream *str, int width, int height,
+ GBool invert, GBool inlineImg) {
+ saveState();
+
+ out->setSoftMaskFromImageMask(state, ref, str,
+ width, height, invert, inlineImg, baseMatrix);
+
+ state->clearPath();
+ state->moveTo(0, 0);
+ state->lineTo(1, 0);
+ state->lineTo(1, 1);
+ state->lineTo(0, 1);
+ state->closePath();
+ doPatternText();
+
+ out->unsetSoftMaskFromImageMask(state, baseMatrix);
+ restoreState();
+}
+
+void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
+ GBool stroke, GBool eoFill, GBool text) {
+ GfxPatternColorSpace *patCS;
+ GfxColorSpace *cs;
+ GfxColor color;
+ GfxState *savedState;
+ double xMin, yMin, xMax, yMax, x, y, x1, y1;
+ double cxMin, cyMin, cxMax, cyMax;
+ int xi0, yi0, xi1, yi1, xi, yi;
+ double *ctm, *btm, *ptm;
+ double m[6], ictm[6], m1[6], imb[6];
+ double det;
+ double xstep, ystep;
+ int i;
+
+ // get color space
+ patCS = (GfxPatternColorSpace *)(stroke ? state->getStrokeColorSpace()
+ : state->getFillColorSpace());
+
+ // construct a (pattern space) -> (current space) transform matrix
+ ctm = state->getCTM();
+ btm = baseMatrix;
+ ptm = tPat->getMatrix();
+ // iCTM = invert CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ // m1 = PTM * BTM = PTM * base transform matrix
+ m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
+ m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
+ m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
+ m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
+ m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
+ m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
+ // m = m1 * iCTM = (PTM * BTM) * (iCTM)
+ m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
+ m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
+ m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
+ m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
+ m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
+ m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
+
+ // construct a (device space) -> (pattern space) transform matrix
+ det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
+ imb[0] = m1[3] * det;
+ imb[1] = -m1[1] * det;
+ imb[2] = -m1[2] * det;
+ imb[3] = m1[0] * det;
+ imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det;
+ imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
+
+ // save current graphics state
+ savedState = saveStateStack();
+
+ // set underlying color space (for uncolored tiling patterns); set
+ // various other parameters (stroke color, line width) to match
+ // Adobe's behavior
+ state->setFillPattern(NULL);
+ state->setStrokePattern(NULL);
+ if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
+ state->setFillColorSpace(cs->copy());
+ out->updateFillColorSpace(state);
+ state->setStrokeColorSpace(cs->copy());
+ out->updateStrokeColorSpace(state);
+ if (stroke) {
+ state->setFillColor(state->getStrokeColor());
+ } else {
+ state->setStrokeColor(state->getFillColor());
+ }
+ out->updateFillColor(state);
+ out->updateStrokeColor(state);
+ } else {
+ cs = new GfxDeviceGrayColorSpace();
+ state->setFillColorSpace(cs);
+ cs->getDefaultColor(&color);
+ state->setFillColor(&color);
+ out->updateFillColorSpace(state);
+ state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+ state->setStrokeColor(&color);
+ out->updateStrokeColorSpace(state);
+ }
+ if (!stroke) {
+ state->setLineWidth(0);
+ out->updateLineWidth(state);
+ }
+
+ // clip to current path
+ if (stroke) {
+ state->clipToStrokePath();
+ out->clipToStrokePath(state);
+ } else if (!text) {
+ state->clip();
+ if (eoFill) {
+ out->eoClip(state);
+ } else {
+ out->clip(state);
+ }
+ }
+ state->clearPath();
+
+ // get the clip region, check for empty
+ state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
+ if (cxMin > cxMax || cyMin > cyMax) {
+ goto restore;
+ }
+
+ // transform clip region bbox to pattern space
+ xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4];
+ yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5];
+ x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+
+ // draw the pattern
+ //~ this should treat negative steps differently -- start at right/top
+ //~ edge instead of left/bottom (?)
+ xstep = fabs(tPat->getXStep());
+ ystep = fabs(tPat->getYStep());
+ if (tPat->getBBox()[0] < tPat->getBBox()[2]) {
+ xi0 = (int)ceil((xMin - tPat->getBBox()[2]) / xstep);
+ xi1 = (int)floor((xMax - tPat->getBBox()[0]) / xstep) + 1;
+ } else {
+ xi0 = (int)ceil((xMin - tPat->getBBox()[0]) / xstep);
+ xi1 = (int)floor((xMax - tPat->getBBox()[2]) / xstep) + 1;
+ }
+ if (tPat->getBBox()[1] < tPat->getBBox()[3]) {
+ yi0 = (int)ceil((yMin - tPat->getBBox()[3]) / ystep);
+ yi1 = (int)floor((yMax - tPat->getBBox()[1]) / ystep) + 1;
+ } else {
+ yi0 = (int)ceil((yMin - tPat->getBBox()[1]) / ystep);
+ yi1 = (int)floor((yMax - tPat->getBBox()[3]) / ystep) + 1;
+ }
+ for (i = 0; i < 4; ++i) {
+ m1[i] = m[i];
+ }
+ m1[4] = m[4];
+ m1[5] = m[5];
+ if (out->useTilingPatternFill() &&
+ out->tilingPatternFill(state, this, catalog, tPat->getContentStream(),
+ tPat->getMatrix(), tPat->getPaintType(), tPat->getTilingType(),
+ tPat->getResDict(), m1, tPat->getBBox(),
+ xi0, yi0, xi1, yi1, xstep, ystep)) {
+ goto restore;
+ } else {
+ for (yi = yi0; yi < yi1; ++yi) {
+ for (xi = xi0; xi < xi1; ++xi) {
+ x = xi * xstep;
+ y = yi * ystep;
+ m1[4] = x * m[0] + y * m[2] + m[4];
+ m1[5] = x * m[1] + y * m[3] + m[5];
+ drawForm(tPat->getContentStream(), tPat->getResDict(),
+ m1, tPat->getBBox());
+ }
+ }
+ }
+
+ // restore graphics state
+ restore:
+ restoreStateStack(savedState);
+}
+
+void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
+ GBool stroke, GBool eoFill, GBool text) {
+ GfxShading *shading;
+ GfxState *savedState;
+ double *ctm, *btm, *ptm;
+ double m[6], ictm[6], m1[6];
+ double xMin, yMin, xMax, yMax;
+ double det;
+
+ shading = sPat->getShading();
+
+ // save current graphics state
+ savedState = saveStateStack();
+
+ // clip to current path
+ if (stroke) {
+ state->clipToStrokePath();
+ out->clipToStrokePath(state);
+ } else if (!text) {
+ state->clip();
+ if (eoFill) {
+ out->eoClip(state);
+ } else {
+ out->clip(state);
+ }
+ }
+ state->clearPath();
+
+ // construct a (pattern space) -> (current space) transform matrix
+ ctm = state->getCTM();
+ btm = baseMatrix;
+ ptm = sPat->getMatrix();
+ // iCTM = invert CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ // m1 = PTM * BTM = PTM * base transform matrix
+ m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
+ m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
+ m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
+ m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
+ m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
+ m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
+ // m = m1 * iCTM = (PTM * BTM) * (iCTM)
+ m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
+ m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
+ m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
+ m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
+ m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
+ m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
+
+ // set the new matrix
+ state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
+ out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+ out->updateFillColorSpace(state);
+
+ // background color fill
+ if (shading->getHasBackground()) {
+ state->setFillColor(shading->getBackground());
+ out->updateFillColor(state);
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+ }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ GBool vaa = out->getVectorAntialias();
+ if (vaa) {
+ out->setVectorAntialias(gFalse);
+ }
+#endif
+
+ // do shading type-specific operations
+ switch (shading->getType()) {
+ case 1:
+ doFunctionShFill((GfxFunctionShading *)shading);
+ break;
+ case 2:
+ doAxialShFill((GfxAxialShading *)shading);
+ break;
+ case 3:
+ doRadialShFill((GfxRadialShading *)shading);
+ break;
+ case 4:
+ case 5:
+ doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
+ break;
+ case 6:
+ case 7:
+ doPatchMeshShFill((GfxPatchMeshShading *)shading);
+ break;
+ }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ if (vaa) {
+ out->setVectorAntialias(gTrue);
+ }
+#endif
+
+ // restore graphics state
+ restoreStateStack(savedState);
+}
+
+void Gfx::opShFill(Object args[], int numArgs) {
+ GfxShading *shading;
+ GfxState *savedState;
+ double xMin, yMin, xMax, yMax;
+
+ if (!ocState) {
+ return;
+ }
+
+ if (!(shading = res->lookupShading(args[0].getName(), out, state))) {
+ return;
+ }
+
+ // save current graphics state
+ savedState = saveStateStack();
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+ out->updateFillColorSpace(state);
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ GBool vaa = out->getVectorAntialias();
+ if (vaa) {
+ out->setVectorAntialias(gFalse);
+ }
+#endif
+
+ // do shading type-specific operations
+ switch (shading->getType()) {
+ case 1:
+ doFunctionShFill((GfxFunctionShading *)shading);
+ break;
+ case 2:
+ doAxialShFill((GfxAxialShading *)shading);
+ break;
+ case 3:
+ doRadialShFill((GfxRadialShading *)shading);
+ break;
+ case 4:
+ case 5:
+ doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
+ break;
+ case 6:
+ case 7:
+ doPatchMeshShFill((GfxPatchMeshShading *)shading);
+ break;
+ }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ if (vaa) {
+ out->setVectorAntialias(gTrue);
+ }
+#endif
+
+ // restore graphics state
+ restoreStateStack(savedState);
+
+ delete shading;
+}
+
+void Gfx::doFunctionShFill(GfxFunctionShading *shading) {
+ double x0, y0, x1, y1;
+ GfxColor colors[4];
+
+ if (out->useShadedFills( shading->getType() ) &&
+ out->functionShadedFill(state, shading)) {
+ return;
+ }
+
+ shading->getDomain(&x0, &y0, &x1, &y1);
+ shading->getColor(x0, y0, &colors[0]);
+ shading->getColor(x0, y1, &colors[1]);
+ shading->getColor(x1, y0, &colors[2]);
+ shading->getColor(x1, y1, &colors[3]);
+ doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
+}
+
+void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
+ double x0, double y0,
+ double x1, double y1,
+ GfxColor *colors, int depth) {
+ GfxColor fillColor;
+ GfxColor color0M, color1M, colorM0, colorM1, colorMM;
+ GfxColor colors2[4];
+ double *matrix;
+ double xM, yM;
+ int nComps, i, j;
+
+ nComps = shading->getColorSpace()->getNComps();
+ matrix = shading->getMatrix();
+
+ // compare the four corner colors
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < nComps; ++j) {
+ if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
+ break;
+ }
+ }
+ if (j < nComps) {
+ break;
+ }
+ }
+
+ // center of the rectangle
+ xM = 0.5 * (x0 + x1);
+ yM = 0.5 * (y0 + y1);
+
+ // the four corner colors are close (or we hit the recursive limit)
+ // -- fill the rectangle; but require at least one subdivision
+ // (depth==0) to avoid problems when the four outer corners of the
+ // shaded region are the same color
+ if ((i == 4 && depth > 0) || depth == functionMaxDepth) {
+
+ // use the center color
+ shading->getColor(xM, yM, &fillColor);
+ state->setFillColor(&fillColor);
+ out->updateFillColor(state);
+
+ // fill the rectangle
+ state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4],
+ x0 * matrix[1] + y0 * matrix[3] + matrix[5]);
+ state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4],
+ x1 * matrix[1] + y0 * matrix[3] + matrix[5]);
+ state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4],
+ x1 * matrix[1] + y1 * matrix[3] + matrix[5]);
+ state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
+ x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+
+ // the four corner colors are not close enough -- subdivide the
+ // rectangle
+ } else {
+
+ // colors[0] colorM0 colors[2]
+ // (x0,y0) (xM,y0) (x1,y0)
+ // +----------+----------+
+ // | | |
+ // | UL | UR |
+ // color0M | colorMM | color1M
+ // (x0,yM) +----------+----------+ (x1,yM)
+ // | (xM,yM) |
+ // | LL | LR |
+ // | | |
+ // +----------+----------+
+ // colors[1] colorM1 colors[3]
+ // (x0,y1) (xM,y1) (x1,y1)
+
+ shading->getColor(x0, yM, &color0M);
+ shading->getColor(x1, yM, &color1M);
+ shading->getColor(xM, y0, &colorM0);
+ shading->getColor(xM, y1, &colorM1);
+ shading->getColor(xM, yM, &colorMM);
+
+ // upper-left sub-rectangle
+ colors2[0] = colors[0];
+ colors2[1] = color0M;
+ colors2[2] = colorM0;
+ colors2[3] = colorMM;
+ doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
+
+ // lower-left sub-rectangle
+ colors2[0] = color0M;
+ colors2[1] = colors[1];
+ colors2[2] = colorMM;
+ colors2[3] = colorM1;
+ doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
+
+ // upper-right sub-rectangle
+ colors2[0] = colorM0;
+ colors2[1] = colorMM;
+ colors2[2] = colors[2];
+ colors2[3] = color1M;
+ doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1);
+
+ // lower-right sub-rectangle
+ colors2[0] = colorMM;
+ colors2[1] = colorM1;
+ colors2[2] = color1M;
+ colors2[3] = colors[3];
+ doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1);
+ }
+}
+
+static void bubbleSort(double array[])
+{
+ for (int j = 0; j < 3; ++j) {
+ int kk = j;
+ for (int k = j + 1; k < 4; ++k) {
+ if (array[k] < array[kk]) {
+ kk = k;
+ }
+ }
+ double tmp = array[j];
+ array[j] = array[kk];
+ array[kk] = tmp;
+ }
+}
+
+void Gfx::doAxialShFill(GfxAxialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, x1, y1;
+ double dx, dy, mul;
+ GBool dxZero, dyZero;
+ double bboxIntersections[4];
+ double tMin, tMax, tx, ty;
+ double s[4], sMin, sMax, tmp;
+ double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
+ double t0, t1, tt;
+ double ta[axialMaxSplits + 1];
+ int next[axialMaxSplits + 1];
+ GfxColor color0, color1;
+ int nComps;
+ int i, j, k;
+ GBool needExtend = gTrue;
+
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ // compute min and max t values, based on the four corners of the
+ // clip region bbox
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ dxZero = fabs(dx) < 0.01;
+ dyZero = fabs(dy) < 0.01;
+ if (dxZero && dyZero) {
+ tMin = tMax = 0;
+ } else {
+ mul = 1 / (dx * dx + dy * dy);
+ bboxIntersections[0] = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
+ bboxIntersections[1] = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
+ bboxIntersections[2] = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
+ bboxIntersections[3] = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
+ bubbleSort(bboxIntersections);
+ tMin = bboxIntersections[0];
+ tMax = bboxIntersections[3];
+ if (tMin < 0 && !shading->getExtend0()) {
+ tMin = 0;
+ }
+ if (tMax > 1 && !shading->getExtend1()) {
+ tMax = 1;
+ }
+ }
+
+ if (out->useShadedFills( shading->getType() ) &&
+ out->axialShadedFill(state, shading, tMin, tMax)) {
+ return;
+ }
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // Traverse the t axis and do the shading.
+ //
+ // For each point (tx, ty) on the t axis, consider a line through
+ // that point perpendicular to the t axis:
+ //
+ // x(s) = tx + s * -dy --> s = (x - tx) / -dy
+ // y(s) = ty + s * dx --> s = (y - ty) / dx
+ //
+ // Then look at the intersection of this line with the bounding box
+ // (xMin, yMin, xMax, yMax). In the general case, there are four
+ // intersection points:
+ //
+ // s0 = (xMin - tx) / -dy
+ // s1 = (xMax - tx) / -dy
+ // s2 = (yMin - ty) / dx
+ // s3 = (yMax - ty) / dx
+ //
+ // and we want the middle two s values.
+ //
+ // In the case where dx = 0, take s0 and s1; in the case where dy =
+ // 0, take s2 and s3.
+ //
+ // Each filled polygon is bounded by two of these line segments
+ // perpdendicular to the t axis.
+ //
+ // The t axis is bisected into smaller regions until the color
+ // difference across a region is small enough, and then the region
+ // is painted with a single color.
+
+ // set up: require at least one split to avoid problems when the two
+ // ends of the t axis have the same color
+ nComps = shading->getColorSpace()->getNComps();
+ ta[0] = tMin;
+ next[0] = axialMaxSplits / 2;
+ ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax);
+ next[axialMaxSplits / 2] = axialMaxSplits;
+ ta[axialMaxSplits] = tMax;
+
+ // compute the color at t = tMin
+ if (tMin < 0) {
+ tt = t0;
+ } else if (tMin > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * tMin;
+ }
+ shading->getColor(tt, &color0);
+
+ if (out->useFillColorStop()) {
+ // make sure we add stop color when t = tMin
+ state->setFillColor(&color0);
+ out->updateFillColorStop(state, 0);
+ }
+
+ // compute the coordinates of the point on the t axis at t = tMin;
+ // then compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + tMin * dx;
+ ty = y0 + tMin * dy;
+ if (dxZero && dyZero) {
+ sMin = sMax = 0;
+ } else if (dxZero) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dyZero) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ bubbleSort(s);
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux0 = tx - sMin * dy;
+ uy0 = ty + sMin * dx;
+ vx0 = tx - sMax * dy;
+ vy0 = ty + sMax * dx;
+
+ i = 0;
+ bool doneBBox1, doneBBox2;
+ if (dxZero && dyZero) {
+ doneBBox1 = doneBBox2 = true;
+ } else {
+ doneBBox1 = bboxIntersections[1] < tMin;
+ doneBBox2 = bboxIntersections[2] > tMax;
+ }
+
+ // If output device doesn't support the extended mode required
+ // we have to do it here
+ needExtend = !out->axialShadedSupportExtend(state, shading);
+
+ while (i < axialMaxSplits) {
+
+ // bisect until color difference is small enough or we hit the
+ // bisection limit
+ j = next[i];
+ while (j > i + 1) {
+ if (ta[j] < 0) {
+ tt = t0;
+ } else if (ta[j] > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * ta[j];
+ }
+ shading->getColor(tt, &color1);
+ if (isSameGfxColor(color1, color0, nComps, axialColorDelta)) {
+ // in these two if what we guarantee is that if we are skipping lots of
+ // positions because the colors are the same, we still create a region
+ // with vertexs passing by bboxIntersections[1] and bboxIntersections[2]
+ // otherwise we can have empty regions that should really be painted
+ // like happened in bug 19896
+ // What we do to ensure that we pass a line through this points
+ // is making sure use the exact bboxIntersections[] value as one of the used ta[] values
+ if (!doneBBox1 && ta[i] < bboxIntersections[1] && ta[j] > bboxIntersections[1]) {
+ int teoricalj = (int) ((bboxIntersections[1] - tMin) * axialMaxSplits / (tMax - tMin));
+ if (teoricalj <= i) teoricalj = i + 1;
+ if (teoricalj < j) {
+ next[i] = teoricalj;
+ next[teoricalj] = j;
+ }
+ else {
+ teoricalj = j;
+ }
+ ta[teoricalj] = bboxIntersections[1];
+ j = teoricalj;
+ doneBBox1 = true;
+ }
+ if (!doneBBox2 && ta[i] < bboxIntersections[2] && ta[j] > bboxIntersections[2]) {
+ int teoricalj = (int) ((bboxIntersections[2] - tMin) * axialMaxSplits / (tMax - tMin));
+ if (teoricalj <= i) teoricalj = i + 1;
+ if (teoricalj < j) {
+ next[i] = teoricalj;
+ next[teoricalj] = j;
+ }
+ else {
+ teoricalj = j;
+ }
+ ta[teoricalj] = bboxIntersections[2];
+ j = teoricalj;
+ doneBBox2 = true;
+ }
+ break;
+ }
+ k = (i + j) / 2;
+ ta[k] = 0.5 * (ta[i] + ta[j]);
+ next[i] = k;
+ next[k] = j;
+ j = k;
+ }
+
+ // use the average of the colors of the two sides of the region
+ for (k = 0; k < nComps; ++k) {
+ color0.c[k] = (color0.c[k] + color1.c[k]) / 2;
+ }
+
+ // compute the coordinates of the point on the t axis; then
+ // compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + ta[j] * dx;
+ ty = y0 + ta[j] * dy;
+ if (dxZero && dyZero) {
+ sMin = sMax = 0;
+ } else if (dxZero) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dyZero) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ bubbleSort(s);
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux1 = tx - sMin * dy;
+ uy1 = ty + sMin * dx;
+ vx1 = tx - sMax * dy;
+ vy1 = ty + sMax * dx;
+
+ // set the color
+ state->setFillColor(&color0);
+ if (out->useFillColorStop())
+ out->updateFillColorStop(state, (ta[j] - tMin)/(tMax - tMin));
+ else
+ out->updateFillColor(state);
+
+ if (needExtend) {
+ // fill the region
+ state->moveTo(ux0, uy0);
+ state->lineTo(vx0, vy0);
+ state->lineTo(vx1, vy1);
+ state->lineTo(ux1, uy1);
+ state->closePath();
+ }
+
+ if (!out->useFillColorStop()) {
+ out->fill(state);
+ state->clearPath();
+ }
+
+ // set up for next region
+ ux0 = ux1;
+ uy0 = uy1;
+ vx0 = vx1;
+ vy0 = vy1;
+ color0 = color1;
+ i = next[i];
+ }
+
+ if (out->useFillColorStop()) {
+ if (!needExtend) {
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMin, yMax);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMax, yMin);
+ state->closePath();
+ }
+ out->fill(state);
+ state->clearPath();
+ }
+}
+
+static inline void getShadingColorRadialHelper(double t0, double t1, double t, GfxRadialShading *shading, GfxColor *color)
+{
+ if (t0 < t1) {
+ if (t < t0) {
+ shading->getColor(t0, color);
+ } else if (t > t1) {
+ shading->getColor(t1, color);
+ } else {
+ shading->getColor(t, color);
+ }
+ } else {
+ if (t > t0) {
+ shading->getColor(t0, color);
+ } else if (t < t1) {
+ shading->getColor(t1, color);
+ } else {
+ shading->getColor(t, color);
+ }
+ }
+}
+
+void Gfx::doRadialShFill(GfxRadialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, r0, x1, y1, r1, t0, t1;
+ int nComps;
+ GfxColor colorA, colorB;
+ double xa, ya, xb, yb, ra, rb;
+ double ta, tb, sa, sb;
+ double sz, xz, yz, sMin, sMax;
+ GBool enclosed;
+ int ia, ib, k, n;
+ double *ctm;
+ double theta, alpha, angle, t;
+ GBool needExtend = gTrue;
+
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+ nComps = shading->getColorSpace()->getNComps();
+
+ // Compute the point at which r(s) = 0; check for the enclosed
+ // circles case; and compute the angles for the tangent lines.
+ if (x0 == x1 && y0 == y1) {
+ enclosed = gTrue;
+ theta = 0; // make gcc happy
+ sz = 0; // make gcc happy
+ } else if (r0 == r1) {
+ enclosed = gFalse;
+ theta = 0;
+ sz = 0; // make gcc happy
+ } else {
+ sz = (r1 > r0) ? -r0 / (r1 - r0) : -r1 / (r0 - r1);
+ xz = x0 + sz * (x1 - x0);
+ yz = y0 + sz * (y1 - y0);
+ enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
+ theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
+ if (r0 > r1) {
+ theta = -theta;
+ }
+ }
+ if (enclosed) {
+ alpha = 0;
+ } else {
+ alpha = atan2(y1 - y0, x1 - x0);
+ }
+
+ // compute the (possibly extended) s range
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ if (enclosed) {
+ sMin = 0;
+ sMax = 1;
+ } else {
+ sMin = 1;
+ sMax = 0;
+ // solve for x(s) + r(s) = xMin
+ if ((x1 + r1) - (x0 + r0) != 0) {
+ sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for x(s) - r(s) = xMax
+ if ((x1 - r1) - (x0 - r0) != 0) {
+ sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for y(s) + r(s) = yMin
+ if ((y1 + r1) - (y0 + r0) != 0) {
+ sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for y(s) - r(s) = yMax
+ if ((y1 - r1) - (y0 - r0) != 0) {
+ sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // check against sz
+ if (r0 < r1) {
+ if (sMin < sz) {
+ sMin = sz;
+ }
+ } else if (r0 > r1) {
+ if (sMax > sz) {
+ sMax = sz;
+ }
+ }
+ // check the 'extend' flags
+ if (!shading->getExtend0() && sMin < 0) {
+ sMin = 0;
+ }
+ if (!shading->getExtend1() && sMax > 1) {
+ sMax = 1;
+ }
+ }
+
+ if (out->useShadedFills( shading->getType() ) &&
+ out->radialShadedFill(state, shading, sMin, sMax)) {
+ return;
+ }
+
+ // compute the number of steps into which circles must be divided to
+ // achieve a curve flatness of 0.1 pixel in device space for the
+ // largest circle (note that "device space" is 72 dpi when generating
+ // PostScript, hence the relatively small 0.1 pixel accuracy)
+ ctm = state->getCTM();
+ t = fabs(ctm[0]);
+ if (fabs(ctm[1]) > t) {
+ t = fabs(ctm[1]);
+ }
+ if (fabs(ctm[2]) > t) {
+ t = fabs(ctm[2]);
+ }
+ if (fabs(ctm[3]) > t) {
+ t = fabs(ctm[3]);
+ }
+ if (r0 > r1) {
+ t *= r0;
+ } else {
+ t *= r1;
+ }
+ if (t < 1) {
+ n = 3;
+ } else {
+ n = (int)(M_PI / acos(1 - 0.1 / t));
+ if (n < 3) {
+ n = 3;
+ } else if (n > 200) {
+ n = 200;
+ }
+ }
+
+ // setup for the start circle
+ ia = 0;
+ sa = sMin;
+ ta = t0 + sa * (t1 - t0);
+ xa = x0 + sa * (x1 - x0);
+ ya = y0 + sa * (y1 - y0);
+ ra = r0 + sa * (r1 - r0);
+ getShadingColorRadialHelper(t0, t1, ta, shading, &colorA);
+
+ needExtend = !out->radialShadedSupportExtend(state, shading);
+
+ // fill the circles
+ while (ia < radialMaxSplits) {
+
+ // go as far along the t axis (toward t1) as we can, such that the
+ // color difference is within the tolerance (radialColorDelta) --
+ // this uses bisection (between the current value, t, and t1),
+ // limited to radialMaxSplits points along the t axis; require at
+ // least one split to avoid problems when the innermost and
+ // outermost colors are the same
+ ib = radialMaxSplits;
+ sb = sMax;
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ while (ib - ia > 1) {
+ if (isSameGfxColor(colorB, colorA, nComps, radialColorDelta)) {
+ // The shading is not necessarily lineal so having two points with the
+ // same color does not mean all the areas in between have the same color too
+ int ic = ia + 1;
+ for (; ic <= ib; ic++) {
+ GfxColor colorC;
+ const double sc = sMin + ((double)ic / (double)radialMaxSplits) * (sMax - sMin);
+ const double tc = t0 + sc * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tc, shading, &colorC);
+ if (!isSameGfxColor(colorC, colorA, nComps, radialColorDelta)) {
+ break;
+ }
+ }
+ ib = (ic > ia + 1) ? ic - 1 : ia + 1;
+ sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ break;
+ }
+ ib = (ia + ib) / 2;
+ sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ }
+
+ // compute center and radius of the circle
+ xb = x0 + sb * (x1 - x0);
+ yb = y0 + sb * (y1 - y0);
+ rb = r0 + sb * (r1 - r0);
+
+ // use the average of the colors at the two circles
+ for (k = 0; k < nComps; ++k) {
+ colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2;
+ }
+ state->setFillColor(&colorA);
+ if (out->useFillColorStop())
+ out->updateFillColorStop(state, (sa - sMin)/(sMax - sMin));
+ else
+ out->updateFillColor(state);
+
+ if (needExtend) {
+ if (enclosed) {
+ // construct path for first circle (counterclockwise)
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+
+ // construct and append path for second circle (clockwise)
+ state->moveTo(xb + rb, yb);
+ for (k = 1; k < n; ++k) {
+ angle = -((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ state->closePath();
+ } else {
+ // construct the first subpath (clockwise)
+ state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI),
+ ya + ra * sin(alpha + theta + 0.5 * M_PI));
+ for (k = 0; k < n; ++k) {
+ angle = alpha + theta + 0.5 * M_PI
+ - ((double)k / (double)n) * (2 * theta + M_PI);
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ for (k = 0; k < n; ++k) {
+ angle = alpha - theta - 0.5 * M_PI
+ + ((double)k / (double)n) * (2 * theta - M_PI);
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+
+ // construct the second subpath (counterclockwise)
+ state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI),
+ ya + ra * sin(alpha + theta + 0.5 * M_PI));
+ for (k = 0; k < n; ++k) {
+ angle = alpha + theta + 0.5 * M_PI
+ + ((double)k / (double)n) * (-2 * theta + M_PI);
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ for (k = 0; k < n; ++k) {
+ angle = alpha - theta - 0.5 * M_PI
+ + ((double)k / (double)n) * (2 * theta + M_PI);
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+ }
+ }
+
+ if (!out->useFillColorStop()) {
+ // fill the path
+ out->fill(state);
+ state->clearPath();
+ }
+
+ // step to the next value of t
+ ia = ib;
+ sa = sb;
+ ta = tb;
+ xa = xb;
+ ya = yb;
+ ra = rb;
+ colorA = colorB;
+ }
+
+ if (out->useFillColorStop()) {
+ // make sure we add stop color when sb = sMax
+ state->setFillColor(&colorA);
+ out->updateFillColorStop(state, (sb - sMin)/(sMax - sMin));
+
+ // fill the path
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMin, yMax);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMax, yMin);
+ state->closePath();
+
+ out->fill(state);
+ state->clearPath();
+ }
+
+ if (!needExtend)
+ return;
+
+ if (enclosed) {
+ // extend the smaller circle
+ if ((shading->getExtend0() && r0 <= r1) ||
+ (shading->getExtend1() && r1 < r0)) {
+ if (r0 <= r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ shading->getColor(ta, &colorA);
+ state->setFillColor(&colorA);
+ out->updateFillColor(state);
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+ }
+
+ // extend the larger circle
+ if ((shading->getExtend0() && r0 > r1) ||
+ (shading->getExtend1() && r1 >= r0)) {
+ if (r0 > r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ shading->getColor(ta, &colorA);
+ state->setFillColor(&colorA);
+ out->updateFillColor(state);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMin, yMax);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMax, yMin);
+ state->closePath();
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+ }
+ }
+}
+
+void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
+ double x0, y0, x1, y1, x2, y2;
+ int i;
+
+ if (out->useShadedFills( shading->getType())) {
+ if (out->gouraudTriangleShadedFill( state, shading))
+ return;
+ }
+
+ // preallocate a path (speed improvements)
+ state->moveTo(0., 0.);
+ state->lineTo(1., 0.);
+ state->lineTo(0., 1.);
+ state->closePath();
+
+ GfxState::ReusablePathIterator *reusablePath = state->getReusablePath();
+
+ if (shading->isParameterized()) {
+ // work with parameterized values:
+ double color0, color1, color2;
+ // a relative threshold:
+ const double refineColorThreshold = gouraudParameterizedColorDelta *
+ (shading->getParameterDomainMax() - shading->getParameterDomainMin());
+ for (i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getTriangle(i, &x0, &y0, &color0,
+ &x1, &y1, &color1,
+ &x2, &y2, &color2);
+ gouraudFillTriangle(x0, y0, color0, x1, y1, color1, x2, y2, color2, refineColorThreshold, 0, shading, reusablePath);
+ }
+
+ } else {
+ // this always produces output -- even for parameterized ranges.
+ // But it ignores the parameterized color map (the function).
+ //
+ // Note that using this code in for parameterized shadings might be
+ // correct in circumstances (namely if the function is linear in the actual
+ // triangle), but in general, it will simply be wrong.
+ GfxColor color0, color1, color2;
+ for (i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getTriangle(i, &x0, &y0, &color0,
+ &x1, &y1, &color1,
+ &x2, &y2, &color2);
+ gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2, shading->getColorSpace()->getNComps(), 0, reusablePath);
+ }
+ }
+
+ delete reusablePath;
+}
+
+static inline void checkTrue(bool b, const char *message) {
+ if (unlikely(!b)) {
+ error(errSyntaxError, -1, message);
+ }
+}
+
+void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
+ double x1, double y1, GfxColor *color1,
+ double x2, double y2, GfxColor *color2,
+ int nComps, int depth, GfxState::ReusablePathIterator *path) {
+ double x01, y01, x12, y12, x20, y20;
+ GfxColor color01, color12, color20;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
+ abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
+ break;
+ }
+ }
+ if (i == nComps || depth == gouraudMaxDepth) {
+ state->setFillColor(color0);
+ out->updateFillColor(state);
+
+ path->reset(); checkTrue(!path->isEnd(), "Path should not be at end");
+ path->setCoord(x0,y0); path->next(); checkTrue(!path->isEnd(), "Path should not be at end");
+ path->setCoord(x1,y1); path->next(); checkTrue(!path->isEnd(), "Path should not be at end");
+ path->setCoord(x2,y2); path->next(); checkTrue(!path->isEnd(), "Path should not be at end");
+ path->setCoord(x0,y0); path->next(); checkTrue( path->isEnd(), "Path should be at end");
+ out->fill(state);
+
+ } else {
+ x01 = 0.5 * (x0 + x1);
+ y01 = 0.5 * (y0 + y1);
+ x12 = 0.5 * (x1 + x2);
+ y12 = 0.5 * (y1 + y2);
+ x20 = 0.5 * (x2 + x0);
+ y20 = 0.5 * (y2 + y0);
+ for (i = 0; i < nComps; ++i) {
+ color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
+ color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
+ color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
+ }
+ gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
+ x20, y20, &color20, nComps, depth + 1, path);
+ gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
+ x12, y12, &color12, nComps, depth + 1, path);
+ gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
+ x20, y20, &color20, nComps, depth + 1, path);
+ gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
+ x2, y2, color2, nComps, depth + 1, path);
+ }
+}
+void Gfx::gouraudFillTriangle(double x0, double y0, double color0,
+ double x1, double y1, double color1,
+ double x2, double y2, double color2,
+ double refineColorThreshold, int depth, GfxGouraudTriangleShading *shading, GfxState::ReusablePathIterator *path) {
+ const double meanColor = (color0 + color1 + color2) / 3;
+
+ const bool isFineEnough =
+ fabs(color0 - meanColor) < refineColorThreshold &&
+ fabs(color1 - meanColor) < refineColorThreshold &&
+ fabs(color2 - meanColor) < refineColorThreshold;
+
+ if (isFineEnough || depth == gouraudMaxDepth) {
+ GfxColor color;
+
+ shading->getParameterizedColor(meanColor, &color);
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+
+ path->reset(); checkTrue(!path->isEnd(), "Path should not be at end");
+ path->setCoord(x0,y0); path->next(); checkTrue(!path->isEnd(), "Path should not be at end");
+ path->setCoord(x1,y1); path->next(); checkTrue(!path->isEnd(), "Path should not be at end");
+ path->setCoord(x2,y2); path->next(); checkTrue(!path->isEnd(), "Path should not be at end");
+ path->setCoord(x0,y0); path->next(); checkTrue( path->isEnd(), "Path should be at end");
+ out->fill(state);
+
+ } else {
+ const double x01 = 0.5 * (x0 + x1);
+ const double y01 = 0.5 * (y0 + y1);
+ const double x12 = 0.5 * (x1 + x2);
+ const double y12 = 0.5 * (y1 + y2);
+ const double x20 = 0.5 * (x2 + x0);
+ const double y20 = 0.5 * (y2 + y0);
+ const double color01 = (color0 + color1) / 2.;
+ const double color12 = (color1 + color2) / 2.;
+ const double color20 = (color2 + color0) / 2.;
+ ++depth;
+ gouraudFillTriangle(x0, y0, color0,
+ x01, y01, color01,
+ x20, y20, color20,
+ refineColorThreshold, depth, shading, path);
+ gouraudFillTriangle(x01, y01, color01,
+ x1, y1, color1,
+ x12, y12, color12,
+ refineColorThreshold, depth, shading, path);
+ gouraudFillTriangle(x01, y01, color01,
+ x12, y12, color12,
+ x20, y20, color20,
+ refineColorThreshold, depth, shading, path);
+ gouraudFillTriangle(x20, y20, color20,
+ x12, y12, color12,
+ x2, y2, color2,
+ refineColorThreshold, depth, shading, path);
+ }
+}
+
+void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) {
+ int start, i;
+
+ if (out->useShadedFills( shading->getType())) {
+ if (out->patchMeshShadedFill( state, shading))
+ return;
+ }
+
+ if (shading->getNPatches() > 128) {
+ start = 3;
+ } else if (shading->getNPatches() > 64) {
+ start = 2;
+ } else if (shading->getNPatches() > 16) {
+ start = 1;
+ } else {
+ start = 0;
+ }
+ /*
+ * Parameterized shadings take one parameter [t_0,t_e]
+ * and map it into the color space.
+ *
+ * Consequently, all color values are stored as doubles.
+ *
+ * These color values are interpreted as parameters for parameterized
+ * shadings and as colorspace entities otherwise.
+ *
+ * The only difference is that color space entities are stored into
+ * DOUBLE arrays, not into arrays of type GfxColorComp.
+ */
+ const int colorComps = shading->getColorSpace()->getNComps();
+ double refineColorThreshold;
+ if( shading->isParameterized() ) {
+ refineColorThreshold = gouraudParameterizedColorDelta *
+ (shading->getParameterDomainMax() - shading->getParameterDomainMin());
+
+ } else {
+ refineColorThreshold = patchColorDelta;
+ }
+
+ for (i = 0; i < shading->getNPatches(); ++i) {
+ fillPatch(shading->getPatch(i),
+ colorComps,
+ shading->isParameterized() ? 1 : colorComps,
+ refineColorThreshold,
+ start,
+ shading);
+ }
+}
+
+
+void Gfx::fillPatch(GfxPatch *patch, int colorComps, int patchColorComps, double refineColorThreshold, int depth, GfxPatchMeshShading *shading) {
+ GfxPatch patch00, patch01, patch10, patch11;
+ double xx[4][8], yy[4][8];
+ double xxm, yym;
+ int i;
+
+ for (i = 0; i < patchColorComps; ++i) {
+ // these comparisons are done in double arithmetics.
+ //
+ // For non-parameterized shadings, they are done in color space
+ // components.
+ if (fabs(patch->color[0][0].c[i] - patch->color[0][1].c[i]) > refineColorThreshold ||
+ fabs(patch->color[0][1].c[i] - patch->color[1][1].c[i]) > refineColorThreshold ||
+ fabs(patch->color[1][1].c[i] - patch->color[1][0].c[i]) > refineColorThreshold ||
+ fabs(patch->color[1][0].c[i] - patch->color[0][0].c[i]) > refineColorThreshold) {
+ break;
+ }
+ }
+ if (i == patchColorComps || depth == patchMaxDepth) {
+ GfxColor flatColor;
+ if( shading->isParameterized() ) {
+ shading->getParameterizedColor( patch->color[0][0].c[0], &flatColor );
+ } else {
+ for( i = 0; i<colorComps; ++i ) {
+ // simply cast to the desired type; that's all what is needed.
+ flatColor.c[i] = GfxColorComp(patch->color[0][0].c[i]);
+ }
+ }
+ state->setFillColor(&flatColor);
+ out->updateFillColor(state);
+ state->moveTo(patch->x[0][0], patch->y[0][0]);
+ state->curveTo(patch->x[0][1], patch->y[0][1],
+ patch->x[0][2], patch->y[0][2],
+ patch->x[0][3], patch->y[0][3]);
+ state->curveTo(patch->x[1][3], patch->y[1][3],
+ patch->x[2][3], patch->y[2][3],
+ patch->x[3][3], patch->y[3][3]);
+ state->curveTo(patch->x[3][2], patch->y[3][2],
+ patch->x[3][1], patch->y[3][1],
+ patch->x[3][0], patch->y[3][0]);
+ state->curveTo(patch->x[2][0], patch->y[2][0],
+ patch->x[1][0], patch->y[1][0],
+ patch->x[0][0], patch->y[0][0]);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+ } else {
+ for (i = 0; i < 4; ++i) {
+ xx[i][0] = patch->x[i][0];
+ yy[i][0] = patch->y[i][0];
+ xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
+ yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
+ xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
+ yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
+ xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
+ yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
+ xx[i][2] = 0.5 * (xx[i][1] + xxm);
+ yy[i][2] = 0.5 * (yy[i][1] + yym);
+ xx[i][5] = 0.5 * (xxm + xx[i][6]);
+ yy[i][5] = 0.5 * (yym + yy[i][6]);
+ xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
+ yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
+ xx[i][7] = patch->x[i][3];
+ yy[i][7] = patch->y[i][3];
+ }
+ for (i = 0; i < 4; ++i) {
+ patch00.x[0][i] = xx[0][i];
+ patch00.y[0][i] = yy[0][i];
+ patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
+ patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
+ xxm = 0.5 * (xx[1][i] + xx[2][i]);
+ yym = 0.5 * (yy[1][i] + yy[2][i]);
+ patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
+ patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
+ patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
+ patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
+ patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
+ patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
+ patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
+ patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
+ patch10.x[0][i] = patch00.x[3][i];
+ patch10.y[0][i] = patch00.y[3][i];
+ patch10.x[3][i] = xx[3][i];
+ patch10.y[3][i] = yy[3][i];
+ }
+ for (i = 4; i < 8; ++i) {
+ patch01.x[0][i-4] = xx[0][i];
+ patch01.y[0][i-4] = yy[0][i];
+ patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
+ patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
+ xxm = 0.5 * (xx[1][i] + xx[2][i]);
+ yym = 0.5 * (yy[1][i] + yy[2][i]);
+ patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
+ patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
+ patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
+ patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
+ patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
+ patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
+ patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
+ patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
+ patch11.x[0][i-4] = patch01.x[3][i-4];
+ patch11.y[0][i-4] = patch01.y[3][i-4];
+ patch11.x[3][i-4] = xx[3][i];
+ patch11.y[3][i-4] = yy[3][i];
+ }
+ for (i = 0; i < patchColorComps; ++i) {
+ patch00.color[0][0].c[i] = patch->color[0][0].c[i];
+ patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
+ patch->color[0][1].c[i]) / 2;
+ patch01.color[0][0].c[i] = patch00.color[0][1].c[i];
+ patch01.color[0][1].c[i] = patch->color[0][1].c[i];
+ patch01.color[1][1].c[i] = (patch->color[0][1].c[i] +
+ patch->color[1][1].c[i]) / 2;
+ patch11.color[0][1].c[i] = patch01.color[1][1].c[i];
+ patch11.color[1][1].c[i] = patch->color[1][1].c[i];
+ patch11.color[1][0].c[i] = (patch->color[1][1].c[i] +
+ patch->color[1][0].c[i]) / 2;
+ patch10.color[1][1].c[i] = patch11.color[1][0].c[i];
+ patch10.color[1][0].c[i] = patch->color[1][0].c[i];
+ patch10.color[0][0].c[i] = (patch->color[1][0].c[i] +
+ patch->color[0][0].c[i]) / 2;
+ patch00.color[1][0].c[i] = patch10.color[0][0].c[i];
+ patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] +
+ patch01.color[1][1].c[i]) / 2;
+ patch01.color[1][0].c[i] = patch00.color[1][1].c[i];
+ patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
+ patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
+ }
+ fillPatch(&patch00, colorComps, patchColorComps, refineColorThreshold, depth + 1, shading);
+ fillPatch(&patch10, colorComps, patchColorComps, refineColorThreshold, depth + 1, shading);
+ fillPatch(&patch01, colorComps, patchColorComps, refineColorThreshold, depth + 1, shading);
+ fillPatch(&patch11, colorComps, patchColorComps, refineColorThreshold, depth + 1, shading);
+ }
+}
+
+void Gfx::doEndPath() {
+ if (state->isCurPt() && clip != clipNone) {
+ state->clip();
+ if (clip == clipNormal) {
+ out->clip(state);
+ } else {
+ out->eoClip(state);
+ }
+ }
+ clip = clipNone;
+ state->clearPath();
+}
+
+//------------------------------------------------------------------------
+// path clipping operators
+//------------------------------------------------------------------------
+
+void Gfx::opClip(Object args[], int numArgs) {
+ clip = clipNormal;
+}
+
+void Gfx::opEOClip(Object args[], int numArgs) {
+ clip = clipEO;
+}
+
+//------------------------------------------------------------------------
+// text object operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginText(Object args[], int numArgs) {
+ out->beginTextObject(state);
+ state->setTextMat(1, 0, 0, 1, 0, 0);
+ state->textMoveTo(0, 0);
+ out->updateTextMat(state);
+ out->updateTextPos(state);
+ fontChanged = gTrue;
+}
+
+void Gfx::opEndText(Object args[], int numArgs) {
+ out->endTextObject(state);
+}
+
+//------------------------------------------------------------------------
+// text state operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetCharSpacing(Object args[], int numArgs) {
+ state->setCharSpace(args[0].getNum());
+ out->updateCharSpace(state);
+}
+
+void Gfx::opSetFont(Object args[], int numArgs) {
+ GfxFont *font;
+
+ if (!(font = res->lookupFont(args[0].getName()))) {
+ // unsetting the font (drawing no text) is better than using the
+ // previous one and drawing random glyphs from it
+ state->setFont(NULL, args[1].getNum());
+ fontChanged = gTrue;
+ return;
+ }
+ if (printCommands) {
+ printf(" font: tag=%s name='%s' %g\n",
+ font->getTag()->getCString(),
+ font->getName() ? font->getName()->getCString() : "???",
+ args[1].getNum());
+ fflush(stdout);
+ }
+
+ font->incRefCnt();
+ state->setFont(font, args[1].getNum());
+ fontChanged = gTrue;
+}
+
+void Gfx::opSetTextLeading(Object args[], int numArgs) {
+ state->setLeading(args[0].getNum());
+}
+
+void Gfx::opSetTextRender(Object args[], int numArgs) {
+ state->setRender(args[0].getInt());
+ out->updateRender(state);
+}
+
+void Gfx::opSetTextRise(Object args[], int numArgs) {
+ state->setRise(args[0].getNum());
+ out->updateRise(state);
+}
+
+void Gfx::opSetWordSpacing(Object args[], int numArgs) {
+ state->setWordSpace(args[0].getNum());
+ out->updateWordSpace(state);
+}
+
+void Gfx::opSetHorizScaling(Object args[], int numArgs) {
+ state->setHorizScaling(args[0].getNum());
+ out->updateHorizScaling(state);
+ fontChanged = gTrue;
+}
+
+//------------------------------------------------------------------------
+// text positioning operators
+//------------------------------------------------------------------------
+
+void Gfx::opTextMove(Object args[], int numArgs) {
+ double tx, ty;
+
+ tx = state->getLineX() + args[0].getNum();
+ ty = state->getLineY() + args[1].getNum();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+void Gfx::opTextMoveSet(Object args[], int numArgs) {
+ double tx, ty;
+
+ tx = state->getLineX() + args[0].getNum();
+ ty = args[1].getNum();
+ state->setLeading(-ty);
+ ty += state->getLineY();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+void Gfx::opSetTextMatrix(Object args[], int numArgs) {
+ state->setTextMat(args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ state->textMoveTo(0, 0);
+ out->updateTextMat(state);
+ out->updateTextPos(state);
+ fontChanged = gTrue;
+}
+
+void Gfx::opTextNextLine(Object args[], int numArgs) {
+ double tx, ty;
+
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+//------------------------------------------------------------------------
+// text string operators
+//------------------------------------------------------------------------
+
+void Gfx::opShowText(Object args[], int numArgs) {
+ if (!state->getFont()) {
+ error(errSyntaxError, getPos(), "No font in show");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ out->beginStringOp(state);
+ doShowText(args[0].getString());
+ out->endStringOp(state);
+ if (!ocState) {
+ doIncCharCount(args[0].getString());
+ }
+}
+
+void Gfx::opMoveShowText(Object args[], int numArgs) {
+ double tx, ty;
+
+ if (!state->getFont()) {
+ error(errSyntaxError, getPos(), "No font in move/show");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+ out->beginStringOp(state);
+ doShowText(args[0].getString());
+ out->endStringOp(state);
+ if (!ocState) {
+ doIncCharCount(args[0].getString());
+ }
+}
+
+void Gfx::opMoveSetShowText(Object args[], int numArgs) {
+ double tx, ty;
+
+ if (!state->getFont()) {
+ error(errSyntaxError, getPos(), "No font in move/set/show");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ state->setWordSpace(args[0].getNum());
+ state->setCharSpace(args[1].getNum());
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateWordSpace(state);
+ out->updateCharSpace(state);
+ out->updateTextPos(state);
+ out->beginStringOp(state);
+ doShowText(args[2].getString());
+ out->endStringOp(state);
+ if (ocState) {
+ doIncCharCount(args[2].getString());
+ }
+}
+
+void Gfx::opShowSpaceText(Object args[], int numArgs) {
+ Array *a;
+ Object obj;
+ int wMode;
+ int i;
+
+ if (!state->getFont()) {
+ error(errSyntaxError, getPos(), "No font in show/space");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ out->beginStringOp(state);
+ wMode = state->getFont()->getWMode();
+ a = args[0].getArray();
+ for (i = 0; i < a->getLength(); ++i) {
+ a->get(i, &obj);
+ if (obj.isNum()) {
+ // this uses the absolute value of the font size to match
+ // Acrobat's behavior
+ if (wMode) {
+ state->textShift(0, -obj.getNum() * 0.001 *
+ state->getFontSize());
+ } else {
+ state->textShift(-obj.getNum() * 0.001 *
+ state->getFontSize() *
+ state->getHorizScaling(), 0);
+ }
+ out->updateTextShift(state, obj.getNum());
+ } else if (obj.isString()) {
+ doShowText(obj.getString());
+ } else {
+ error(errSyntaxError, getPos(),
+ "Element of show/space array must be number or string");
+ }
+ obj.free();
+ }
+ out->endStringOp(state);
+ if (!ocState) {
+ a = args[0].getArray();
+ for (i = 0; i < a->getLength(); ++i) {
+ a->get(i, &obj);
+ if (obj.isString()) {
+ doIncCharCount(obj.getString());
+ }
+ obj.free();
+ }
+ }
+}
+
+void Gfx::doShowText(GooString *s) {
+ GfxFont *font;
+ int wMode;
+ double riseX, riseY;
+ CharCode code;
+ Unicode *u = NULL;
+ double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, ddx, ddy;
+ double originX, originY, tOriginX, tOriginY;
+ double x0, y0, x1, y1;
+ double oldCTM[6], newCTM[6];
+ double *mat;
+ Object charProc;
+ Dict *resDict;
+ Parser *oldParser;
+ GfxState *savedState;
+ char *p;
+ int render;
+ GBool patternFill;
+ int len, n, uLen, nChars, nSpaces, i;
+
+ font = state->getFont();
+ wMode = font->getWMode();
+
+ if (out->useDrawChar()) {
+ out->beginString(state, s);
+ }
+
+ // if we're doing a pattern fill, set up clipping
+ render = state->getRender();
+ if (!(render & 1) &&
+ state->getFillColorSpace()->getMode() == csPattern) {
+ patternFill = gTrue;
+ saveState();
+ // disable fill, enable clipping, leave stroke unchanged
+ if ((render ^ (render >> 1)) & 1) {
+ render = 5;
+ } else {
+ render = 7;
+ }
+ state->setRender(render);
+ out->updateRender(state);
+ } else {
+ patternFill = gFalse;
+ }
+
+ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
+ x0 = state->getCurX() + riseX;
+ y0 = state->getCurY() + riseY;
+
+ // handle a Type 3 char
+ if (font->getType() == fontType3 && out->interpretType3Chars()) {
+ mat = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ oldCTM[i] = mat[i];
+ }
+ mat = state->getTextMat();
+ newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
+ newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
+ newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
+ newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
+ mat = font->getFontMatrix();
+ newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
+ newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
+ newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
+ newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
+ newCTM[0] *= state->getFontSize();
+ newCTM[1] *= state->getFontSize();
+ newCTM[2] *= state->getFontSize();
+ newCTM[3] *= state->getFontSize();
+ newCTM[0] *= state->getHorizScaling();
+ newCTM[2] *= state->getHorizScaling();
+ curX = state->getCurX();
+ curY = state->getCurY();
+ oldParser = parser;
+ p = s->getCString();
+ len = s->getLength();
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ &u, &uLen,
+ &dx, &dy, &originX, &originY);
+ dx = dx * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dx += state->getWordSpace();
+ }
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ state->transform(curX + riseX, curY + riseY, &x, &y);
+ savedState = saveStateStack();
+ state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
+ //~ the CTM concat values here are wrong (but never used)
+ out->updateCTM(state, 1, 0, 0, 1, 0, 0);
+ state->transformDelta(dx, dy, &ddx, &ddy);
+ if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy,
+ code, u, uLen)) {
+ ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+ pushResources(resDict);
+ }
+ if (charProc.isStream()) {
+ display(&charProc, gFalse);
+ } else {
+ error(errSyntaxError, getPos(), "Missing or bad Type3 CharProc entry");
+ }
+ out->endType3Char(state);
+ if (resDict) {
+ popResources();
+ }
+ charProc.free();
+ }
+ restoreStateStack(savedState);
+ // GfxState::restore() does *not* restore the current position,
+ // so we deal with it here using (curX, curY) and (lineX, lineY)
+ curX += tdx;
+ curY += tdy;
+ state->moveTo(curX, curY);
+ p += n;
+ len -= n;
+ }
+ parser = oldParser;
+
+ } else if (out->useDrawChar()) {
+ p = s->getCString();
+ len = s->getLength();
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ &u, &uLen,
+ &dx, &dy, &originX, &originY);
+ if (wMode) {
+ dx *= state->getFontSize();
+ dy = dy * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dy += state->getWordSpace();
+ }
+ } else {
+ dx = dx * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dx += state->getWordSpace();
+ }
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
+ }
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ originX *= state->getFontSize();
+ originY *= state->getFontSize();
+ state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
+ if (ocState)
+ out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
+ tdx, tdy, tOriginX, tOriginY, code, n, u, uLen);
+ state->shift(tdx, tdy);
+ p += n;
+ len -= n;
+ }
+ } else {
+ dx = dy = 0;
+ p = s->getCString();
+ len = s->getLength();
+ nChars = nSpaces = 0;
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ &u, &uLen,
+ &dx2, &dy2, &originX, &originY);
+ dx += dx2;
+ dy += dy2;
+ if (n == 1 && *p == ' ') {
+ ++nSpaces;
+ }
+ ++nChars;
+ p += n;
+ len -= n;
+ }
+ if (wMode) {
+ dx *= state->getFontSize();
+ dy = dy * state->getFontSize()
+ + nChars * state->getCharSpace()
+ + nSpaces * state->getWordSpace();
+ } else {
+ dx = dx * state->getFontSize()
+ + nChars * state->getCharSpace()
+ + nSpaces * state->getWordSpace();
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
+ }
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ if (ocState)
+ out->drawString(state, s);
+ state->shift(tdx, tdy);
+ }
+
+ if (out->useDrawChar()) {
+ out->endString(state);
+ }
+
+ if (patternFill && ocState) {
+ out->saveTextPos(state);
+ // tell the OutputDev to do the clipping
+ out->endTextObject(state);
+ // set up a clipping bbox so doPatternText will work -- assume
+ // that the text bounding box does not extend past the baseline in
+ // any direction by more than twice the font size
+ x1 = state->getCurX() + riseX;
+ y1 = state->getCurY() + riseY;
+ if (x0 > x1) {
+ x = x0; x0 = x1; x1 = x;
+ }
+ if (y0 > y1) {
+ y = y0; y0 = y1; y1 = y;
+ }
+ state->textTransformDelta(0, state->getFontSize(), &dx, &dy);
+ state->textTransformDelta(state->getFontSize(), 0, &dx2, &dy2);
+ dx = fabs(dx);
+ dx2 = fabs(dx2);
+ if (dx2 > dx) {
+ dx = dx2;
+ }
+ dy = fabs(dy);
+ dy2 = fabs(dy2);
+ if (dy2 > dy) {
+ dy = dy2;
+ }
+ state->clipToRect(x0 - 2 * dx, y0 - 2 * dy, x1 + 2 * dx, y1 + 2 * dy);
+ // set render mode to fill-only
+ state->setRender(0);
+ out->updateRender(state);
+ doPatternText();
+ restoreState();
+ out->restoreTextPos(state);
+ }
+
+ updateLevel += 10 * s->getLength();
+}
+
+// NB: this is only called when ocState is false.
+void Gfx::doIncCharCount(GooString *s) {
+ if (out->needCharCount()) {
+ out->incCharCount(s->getLength());
+ }
+}
+
+//------------------------------------------------------------------------
+// XObject operators
+//------------------------------------------------------------------------
+
+void Gfx::opXObject(Object args[], int numArgs) {
+ char *name;
+ Object obj1, obj2, obj3, refObj;
+#if OPI_SUPPORT
+ Object opiDict;
+#endif
+
+ if (!ocState && !out->needCharCount()) {
+ return;
+ }
+ name = args[0].getName();
+ if (!res->lookupXObject(name, &obj1)) {
+ return;
+ }
+ if (!obj1.isStream()) {
+ error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name);
+ obj1.free();
+ return;
+ }
+
+#if OPI_SUPPORT
+ obj1.streamGetDict()->lookup("OPI", &opiDict);
+ if (opiDict.isDict()) {
+ out->opiBegin(state, opiDict.getDict());
+ }
+#endif
+ obj1.streamGetDict()->lookup("Subtype", &obj2);
+ if (obj2.isName("Image")) {
+ if (out->needNonText()) {
+ res->lookupXObjectNF(name, &refObj);
+ doImage(&refObj, obj1.getStream(), gFalse);
+ refObj.free();
+ }
+ } else if (obj2.isName("Form")) {
+ res->lookupXObjectNF(name, &refObj);
+ GBool shouldDoForm = gTrue;
+ std::set<int>::iterator drawingFormIt;
+ if (refObj.isRef()) {
+ const int num = refObj.getRef().num;
+ if (formsDrawing.find(num) == formsDrawing.end()) {
+ drawingFormIt = formsDrawing.insert(num).first;
+ } else {
+ shouldDoForm = gFalse;
+ }
+ }
+ if (shouldDoForm) {
+ if (out->useDrawForm() && refObj.isRef()) {
+ out->drawForm(refObj.getRef());
+ } else {
+ doForm(&obj1);
+ }
+ }
+ if (refObj.isRef() && shouldDoForm) {
+ formsDrawing.erase(drawingFormIt);
+ }
+ refObj.free();
+ } else if (obj2.isName("PS")) {
+ obj1.streamGetDict()->lookup("Level1", &obj3);
+ out->psXObject(obj1.getStream(),
+ obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
+ } else if (obj2.isName()) {
+ error(errSyntaxError, getPos(), "Unknown XObject subtype '{0:s}'", obj2.getName());
+ } else {
+ error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type");
+ }
+ obj2.free();
+#if OPI_SUPPORT
+ if (opiDict.isDict()) {
+ out->opiEnd(state, opiDict.getDict());
+ }
+ opiDict.free();
+#endif
+ obj1.free();
+}
+
+void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
+ Dict *dict, *maskDict;
+ int width, height;
+ int bits, maskBits;
+ GBool interpolate;
+ StreamColorSpaceMode csMode;
+ GBool mask;
+ GBool invert;
+ GfxColorSpace *colorSpace, *maskColorSpace;
+ GfxImageColorMap *colorMap, *maskColorMap;
+ Object maskObj, smaskObj;
+ GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
+ int maskColors[2*gfxColorMaxComps];
+ int maskWidth, maskHeight;
+ GBool maskInvert;
+ GBool maskInterpolate;
+ Stream *maskStr;
+ Object obj1, obj2;
+ int i, n;
+
+ // get info from the stream
+ bits = 0;
+ csMode = streamCSNone;
+ str->getImageParams(&bits, &csMode);
+
+ // get stream dict
+ dict = str->getDict();
+
+ // check for optional content key
+ if (ref) {
+ dict->lookupNF("OC", &obj1);
+ if (catalog->getOptContentConfig() && !catalog->getOptContentConfig()->optContentIsVisible(&obj1)) {
+ obj1.free();
+ return;
+ }
+ obj1.free();
+ }
+
+ // get size
+ dict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("W", &obj1);
+ }
+ if (obj1.isInt())
+ width = obj1.getInt();
+ else if (obj1.isReal())
+ width = (int)obj1.getReal();
+ else
+ goto err2;
+ obj1.free();
+ dict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("H", &obj1);
+ }
+ if (obj1.isInt())
+ height = obj1.getInt();
+ else if (obj1.isReal())
+ height = (int)obj1.getReal();
+ else
+ goto err2;
+ obj1.free();
+
+ if (width < 1 || height < 1)
+ goto err1;
+
+ // image interpolation
+ dict->lookup("Interpolate", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("I", &obj1);
+ }
+ if (obj1.isBool())
+ interpolate = obj1.getBool();
+ else
+ interpolate = gFalse;
+ obj1.free();
+ maskInterpolate = gFalse;
+
+ // image or mask?
+ dict->lookup("ImageMask", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("IM", &obj1);
+ }
+ mask = gFalse;
+ if (obj1.isBool())
+ mask = obj1.getBool();
+ else if (!obj1.isNull())
+ goto err2;
+ obj1.free();
+
+ // bit depth
+ if (bits == 0) {
+ dict->lookup("BitsPerComponent", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("BPC", &obj1);
+ }
+ if (obj1.isInt()) {
+ bits = obj1.getInt();
+ } else if (mask) {
+ bits = 1;
+ } else {
+ goto err2;
+ }
+ obj1.free();
+ }
+
+ // display a mask
+ if (mask) {
+
+ // check for inverted mask
+ if (bits != 1)
+ goto err1;
+ invert = gFalse;
+ dict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("D", &obj1);
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ // Table 4.39 says /Decode must be [1 0] or [0 1]. Adobe
+ // accepts [1.0 0.0] as well.
+ if (obj2.isNum() && obj2.getNum() >= 0.9)
+ invert = gTrue;
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+ }
+ obj1.free();
+
+ // if drawing is disabled, skip over inline image data
+ if (!ocState || !out->needNonText()) {
+ str->reset();
+ n = height * ((width + 7) / 8);
+ for (i = 0; i < n; ++i) {
+ str->getChar();
+ }
+ str->close();
+
+ // draw it
+ } else {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternImageMask(ref, str, width, height, invert, inlineImg);
+ } else {
+ out->drawImageMask(state, ref, str, width, height, invert, interpolate, inlineImg);
+ }
+ }
+ } else {
+
+ // get color space and color map
+ dict->lookup("ColorSpace", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("CS", &obj1);
+ }
+ if (obj1.isName() && inlineImg) {
+ res->lookupColorSpace(obj1.getName(), &obj2);
+ if (!obj2.isNull()) {
+ obj1.free();
+ obj1 = obj2;
+ } else {
+ obj2.free();
+ }
+ }
+ if (!obj1.isNull()) {
+ Object objIntent;
+ char *tempIntent = NULL;
+ dict->lookup("Intent", &objIntent);
+ if (objIntent.isName()) {
+ tempIntent = state->getRenderingIntent();
+ if (tempIntent != NULL) {
+ tempIntent = strdup(tempIntent);
+ }
+ state->setRenderingIntent(objIntent.getName());
+ }
+ colorSpace = GfxColorSpace::parse(res, &obj1, out, state);
+ if (objIntent.isName()) {
+ state->setRenderingIntent(tempIntent);
+ free(tempIntent);
+ }
+ objIntent.free();
+ } else if (csMode == streamCSDeviceGray) {
+ Object objCS;
+ res->lookupColorSpace("DefaultGray", &objCS);
+ if (objCS.isNull()) {
+ colorSpace = new GfxDeviceGrayColorSpace();
+ } else {
+ colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
+ }
+ objCS.free();
+ } else if (csMode == streamCSDeviceRGB) {
+ Object objCS;
+ res->lookupColorSpace("DefaultRGB", &objCS);
+ if (objCS.isNull()) {
+ colorSpace = new GfxDeviceRGBColorSpace();
+ } else {
+ colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
+ }
+ objCS.free();
+ } else if (csMode == streamCSDeviceCMYK) {
+ Object objCS;
+ res->lookupColorSpace("DefaultCMYK", &objCS);
+ if (objCS.isNull()) {
+ colorSpace = new GfxDeviceCMYKColorSpace();
+ } else {
+ colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ colorSpace = NULL;
+ }
+ obj1.free();
+ if (!colorSpace) {
+ goto err1;
+ }
+ dict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("D", &obj1);
+ }
+ if (bits == 0) {
+ delete colorSpace;
+ goto err2;
+ }
+ colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
+ obj1.free();
+ if (!colorMap->isOk()) {
+ delete colorMap;
+ goto err1;
+ }
+
+ // get the mask
+ haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
+ maskStr = NULL; // make gcc happy
+ maskWidth = maskHeight = 0; // make gcc happy
+ maskInvert = gFalse; // make gcc happy
+ maskColorMap = NULL; // make gcc happy
+ dict->lookup("Mask", &maskObj);
+ dict->lookup("SMask", &smaskObj);
+ if (smaskObj.isStream()) {
+ // soft mask
+ if (inlineImg) {
+ goto err1;
+ }
+ maskStr = smaskObj.getStream();
+ maskDict = smaskObj.streamGetDict();
+ maskDict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("W", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskWidth = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("H", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskHeight = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("Interpolate", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("I", &obj1);
+ }
+ if (obj1.isBool())
+ maskInterpolate = obj1.getBool();
+ else
+ maskInterpolate = gFalse;
+ obj1.free();
+ maskDict->lookup("BitsPerComponent", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("BPC", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskBits = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("ColorSpace", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("CS", &obj1);
+ }
+ if (obj1.isName()) {
+ res->lookupColorSpace(obj1.getName(), &obj2);
+ if (!obj2.isNull()) {
+ obj1.free();
+ obj1 = obj2;
+ } else {
+ obj2.free();
+ }
+ }
+ maskColorSpace = GfxColorSpace::parse(NULL, &obj1, out, state);
+ obj1.free();
+ if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
+ goto err1;
+ }
+ maskDict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("D", &obj1);
+ }
+ maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
+ obj1.free();
+ if (!maskColorMap->isOk()) {
+ delete maskColorMap;
+ goto err1;
+ }
+ //~ handle the Matte entry
+ haveSoftMask = gTrue;
+ } else if (maskObj.isArray()) {
+ // color key mask
+ for (i = 0;
+ i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
+ ++i) {
+ maskObj.arrayGet(i, &obj1);
+ if (obj1.isInt()) {
+ maskColors[i] = obj1.getInt();
+ } else if (obj1.isReal()) {
+ error(errSyntaxError, -1, "Mask entry should be an integer but it's a real, trying to use it");
+ maskColors[i] = (int) obj1.getReal();
+ } else {
+ error(errSyntaxError, -1, "Mask entry should be an integer but it's of type {0:d}", obj1.getType());
+ obj1.free();
+ goto err1;
+ }
+ obj1.free();
+ }
+ haveColorKeyMask = gTrue;
+ } else if (maskObj.isStream()) {
+ // explicit mask
+ if (inlineImg) {
+ goto err1;
+ }
+ maskStr = maskObj.getStream();
+ maskDict = maskObj.streamGetDict();
+ maskDict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("W", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskWidth = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("H", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskHeight = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("Interpolate", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("I", &obj1);
+ }
+ if (obj1.isBool())
+ maskInterpolate = obj1.getBool();
+ else
+ maskInterpolate = gFalse;
+ obj1.free();
+ maskDict->lookup("ImageMask", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("IM", &obj1);
+ }
+ if (!obj1.isBool() || !obj1.getBool()) {
+ goto err2;
+ }
+ obj1.free();
+ maskInvert = gFalse;
+ maskDict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("D", &obj1);
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ // Table 4.39 says /Decode must be [1 0] or [0 1]. Adobe
+ // accepts [1.0 0.0] as well.
+ if (obj2.isNum() && obj2.getNum() >= 0.9) {
+ maskInvert = gTrue;
+ }
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+ }
+ obj1.free();
+ haveExplicitMask = gTrue;
+ }
+
+ // if drawing is disabled, skip over inline image data
+ if (!ocState || !out->needNonText()) {
+ str->reset();
+ n = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ for (i = 0; i < n; ++i) {
+ str->getChar();
+ }
+ str->close();
+
+ // draw it
+ } else {
+ if (haveSoftMask) {
+ out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate,
+ maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate);
+ delete maskColorMap;
+ } else if (haveExplicitMask) {
+ out->drawMaskedImage(state, ref, str, width, height, colorMap, interpolate,
+ maskStr, maskWidth, maskHeight, maskInvert, maskInterpolate);
+ } else {
+ out->drawImage(state, ref, str, width, height, colorMap, interpolate,
+ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
+ }
+ }
+ delete colorMap;
+
+ maskObj.free();
+ smaskObj.free();
+ }
+
+ if ((i = width * height) > 1000) {
+ i = 1000;
+ }
+ updateLevel += i;
+
+ return;
+
+ err2:
+ obj1.free();
+ err1:
+ error(errSyntaxError, getPos(), "Bad image parameters");
+}
+
+GBool Gfx::checkTransparencyGroup(Dict *resDict) {
+ // check the effect of compositing objects as a group:
+ // look for ExtGState entries with ca != 1 or CA != 1 or BM != normal
+ Object extGStates;
+ GBool transpGroup = gFalse;
+ double opac;
+
+ if (resDict == NULL)
+ return gFalse;
+ pushResources(resDict);
+ resDict->lookup("ExtGState", &extGStates);
+ if (extGStates.isDict()) {
+ Dict *dict = extGStates.getDict();
+ for (int i = 0; i < dict->getLength() && !transpGroup; i++) {
+ Object obj1, obj2;
+ GfxBlendMode mode;
+
+ if (res->lookupGState(dict->getKey(i), &obj1) && obj1.isDict()) {
+ if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+ if (state->parseBlendMode(&obj2, &mode)) {
+ if (mode != gfxBlendNormal)
+ transpGroup = gTrue;
+ } else {
+ error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("ca", &obj2)->isNum()) {
+ opac = obj2.getNum();
+ opac = opac < 0 ? 0 : opac > 1 ? 1 : opac;
+ if (opac != 1)
+ transpGroup = gTrue;
+ }
+ obj2.free();
+ if (obj1.dictLookup("CA", &obj2)->isNum()) {
+ opac = obj2.getNum();
+ opac = opac < 0 ? 0 : opac > 1 ? 1 : opac;
+ if (opac != 1)
+ transpGroup = gTrue;
+ }
+ obj2.free();
+ // alpha is shape
+ if (!transpGroup && obj1.dictLookup("AIS", &obj2)->isBool()) {
+ transpGroup = obj2.getBool();
+ }
+ obj2.free();
+ // soft mask
+ if (!transpGroup && !obj1.dictLookup("SMask", &obj2)->isNull()) {
+ if (!obj2.isName("None")) {
+ transpGroup = gTrue;
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ }
+ extGStates.free();
+ popResources();
+ return transpGroup;
+}
+
+void Gfx::doForm(Object *str) {
+ Dict *dict;
+ GBool transpGroup, isolated, knockout;
+ GfxColorSpace *blendingColorSpace;
+ Object matrixObj, bboxObj;
+ double m[6], bbox[4];
+ Object resObj;
+ Dict *resDict;
+ GBool ocSaved;
+ Object obj1, obj2, obj3;
+ int i;
+
+ // check for excessive recursion
+ if (formDepth > 100) {
+ return;
+ }
+
+ // get stream dict
+ dict = str->streamGetDict();
+
+ // check form type
+ dict->lookup("FormType", &obj1);
+ if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
+ error(errSyntaxError, getPos(), "Unknown form type");
+ }
+ obj1.free();
+
+ // check for optional content key
+ ocSaved = ocState;
+ dict->lookupNF("OC", &obj1);
+ if (catalog->getOptContentConfig() && !catalog->getOptContentConfig()->optContentIsVisible(&obj1)) {
+ obj1.free();
+ if (out->needCharCount()) {
+ ocState = gFalse;
+ } else {
+ return;
+ }
+ }
+ obj1.free();
+
+ // get bounding box
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ bboxObj.free();
+ error(errSyntaxError, getPos(), "Bad form bounding box");
+ ocState = ocSaved;
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ bboxObj.arrayGet(i, &obj1);
+ if (likely(obj1.isNum())) {
+ bbox[i] = obj1.getNum();
+ obj1.free();
+ } else {
+ obj1.free();
+ error(errSyntaxError, getPos(), "Bad form bounding box value");
+ return;
+ }
+ }
+ bboxObj.free();
+
+ // get matrix
+ dict->lookup("Matrix", &matrixObj);
+ if (matrixObj.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ matrixObj.arrayGet(i, &obj1);
+ if (likely(obj1.isNum())) m[i] = obj1.getNum();
+ else m[i] = 0;
+ obj1.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ matrixObj.free();
+
+ // get resources
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ // check for a transparency group
+ transpGroup = isolated = knockout = gFalse;
+ blendingColorSpace = NULL;
+ if (dict->lookup("Group", &obj1)->isDict()) {
+ if (obj1.dictLookup("S", &obj2)->isName("Transparency")) {
+ if (!obj1.dictLookup("CS", &obj3)->isNull()) {
+ blendingColorSpace = GfxColorSpace::parse(res, &obj3, out, state);
+ }
+ obj3.free();
+ if (obj1.dictLookup("I", &obj3)->isBool()) {
+ isolated = obj3.getBool();
+ }
+ obj3.free();
+ if (obj1.dictLookup("K", &obj3)->isBool()) {
+ knockout = obj3.getBool();
+ }
+ obj3.free();
+ transpGroup = isolated || out->checkTransparencyGroup(state, knockout) || checkTransparencyGroup(resDict);
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ // draw it
+ ++formDepth;
+ drawForm(str, resDict, m, bbox,
+ transpGroup, gFalse, blendingColorSpace, isolated, knockout);
+ --formDepth;
+
+ if (blendingColorSpace) {
+ delete blendingColorSpace;
+ }
+ resObj.free();
+
+ ocState = ocSaved;
+}
+
+void Gfx::drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
+ GBool transpGroup, GBool softMask,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ GBool alpha, Function *transferFunc,
+ GfxColor *backdropColor) {
+ Parser *oldParser;
+ GfxState *savedState;
+ double oldBaseMatrix[6];
+ int i;
+
+ // push new resources on stack
+ pushResources(resDict);
+
+ // save current graphics state
+ savedState = saveStateStack();
+
+ // kill any pre-existing path
+ state->clearPath();
+
+ // save current parser
+ oldParser = parser;
+
+ // set form transformation matrix
+ state->concatCTM(matrix[0], matrix[1], matrix[2],
+ matrix[3], matrix[4], matrix[5]);
+ out->updateCTM(state, matrix[0], matrix[1], matrix[2],
+ matrix[3], matrix[4], matrix[5]);
+
+ // set form bounding box
+ state->moveTo(bbox[0], bbox[1]);
+ state->lineTo(bbox[2], bbox[1]);
+ state->lineTo(bbox[2], bbox[3]);
+ state->lineTo(bbox[0], bbox[3]);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+
+ if (softMask || transpGroup) {
+ if (state->getBlendMode() != gfxBlendNormal) {
+ state->setBlendMode(gfxBlendNormal);
+ out->updateBlendMode(state);
+ }
+ if (state->getFillOpacity() != 1) {
+ state->setFillOpacity(1);
+ out->updateFillOpacity(state);
+ }
+ if (state->getStrokeOpacity() != 1) {
+ state->setStrokeOpacity(1);
+ out->updateStrokeOpacity(state);
+ }
+ out->clearSoftMask(state);
+ out->beginTransparencyGroup(state, bbox, blendingColorSpace,
+ isolated, knockout, softMask);
+ }
+
+ // set new base matrix
+ for (i = 0; i < 6; ++i) {
+ oldBaseMatrix[i] = baseMatrix[i];
+ baseMatrix[i] = state->getCTM()[i];
+ }
+
+ GfxState *stateBefore = state;
+
+ // draw the form
+ display(str, gFalse);
+
+ if (stateBefore != state) {
+ if (state->isParentState(stateBefore)) {
+ error(errSyntaxError, -1, "There's a form with more q than Q, trying to fix");
+ while (stateBefore != state) {
+ restoreState();
+ }
+ } else {
+ error(errSyntaxError, -1, "There's a form with more Q than q");
+ }
+ }
+
+ if (softMask || transpGroup) {
+ out->endTransparencyGroup(state);
+ }
+
+ // restore base matrix
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = oldBaseMatrix[i];
+ }
+
+ // restore parser
+ parser = oldParser;
+
+ // restore graphics state
+ restoreStateStack(savedState);
+
+ // pop resource stack
+ popResources();
+
+ if (softMask) {
+ out->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
+ } else if (transpGroup) {
+ out->paintTransparencyGroup(state, bbox);
+ }
+
+ return;
+}
+
+//------------------------------------------------------------------------
+// in-line image operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginImage(Object args[], int numArgs) {
+ Stream *str;
+ int c1, c2;
+
+ // NB: this function is run even if ocState is false -- doImage() is
+ // responsible for skipping over the inline image data
+
+ // build dict/stream
+ str = buildImageStream();
+
+ // display the image
+ if (str) {
+ doImage(NULL, str, gTrue);
+
+ // skip 'EI' tag
+ c1 = str->getUndecodedStream()->getChar();
+ c2 = str->getUndecodedStream()->getChar();
+ while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
+ c1 = c2;
+ c2 = str->getUndecodedStream()->getChar();
+ }
+ delete str;
+ }
+}
+
+Stream *Gfx::buildImageStream() {
+ Object dict;
+ Object obj;
+ char *key;
+ Stream *str;
+
+ // build dictionary
+ dict.initDict(xref);
+ parser->getObj(&obj);
+ while (!obj.isCmd("ID") && !obj.isEOF()) {
+ if (!obj.isName()) {
+ error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object");
+ obj.free();
+ } else {
+ key = copyString(obj.getName());
+ obj.free();
+ parser->getObj(&obj);
+ if (obj.isEOF() || obj.isError()) {
+ gfree(key);
+ break;
+ }
+ dict.dictAdd(key, &obj);
+ }
+ parser->getObj(&obj);
+ }
+ if (obj.isEOF()) {
+ error(errSyntaxError, getPos(), "End of file in inline image");
+ obj.free();
+ dict.free();
+ return NULL;
+ }
+ obj.free();
+
+ // make stream
+ if (parser->getStream()) {
+ str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
+ str = str->addFilters(&dict);
+ } else {
+ str = NULL;
+ dict.free();
+ }
+
+ return str;
+}
+
+void Gfx::opImageData(Object args[], int numArgs) {
+ error(errInternal, getPos(), "Got 'ID' operator");
+}
+
+void Gfx::opEndImage(Object args[], int numArgs) {
+ error(errInternal, getPos(), "Got 'EI' operator");
+}
+
+//------------------------------------------------------------------------
+// type 3 font operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetCharWidth(Object args[], int numArgs) {
+ out->type3D0(state, args[0].getNum(), args[1].getNum());
+}
+
+void Gfx::opSetCacheDevice(Object args[], int numArgs) {
+ out->type3D1(state, args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+}
+
+//------------------------------------------------------------------------
+// compatibility operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) {
+ ++ignoreUndef;
+}
+
+void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
+ if (ignoreUndef > 0)
+ --ignoreUndef;
+}
+
+//------------------------------------------------------------------------
+// marked content operators
+//------------------------------------------------------------------------
+
+enum GfxMarkedContentKind {
+ gfxMCOptionalContent,
+ gfxMCActualText,
+ gfxMCOther
+};
+
+struct MarkedContentStack {
+ GfxMarkedContentKind kind;
+ GBool ocSuppressed; // are we ignoring content based on OptionalContent?
+ MarkedContentStack *next; // next object on stack
+};
+
+void Gfx::popMarkedContent() {
+ MarkedContentStack *mc = mcStack;
+ mcStack = mc->next;
+ delete mc;
+}
+
+void Gfx::pushMarkedContent() {
+ MarkedContentStack *mc = new MarkedContentStack();
+ mc->ocSuppressed = gFalse;
+ mc->kind = gfxMCOther;
+ mc->next = mcStack;
+ mcStack = mc;
+}
+
+GBool Gfx::contentIsHidden() {
+ MarkedContentStack *mc = mcStack;
+ bool hidden = mc && mc->ocSuppressed;
+ while (!hidden && mc && mc->next) {
+ mc = mc->next;
+ hidden = mc->ocSuppressed;
+ }
+ return hidden;
+}
+
+void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
+ // push a new stack entry
+ pushMarkedContent();
+
+ OCGs *contentConfig = catalog->getOptContentConfig();
+ char* name0 = args[0].getName();
+ if ( strncmp( name0, "OC", 2) == 0 && contentConfig) {
+ if ( numArgs >= 2 ) {
+ if (!args[1].isName()) {
+ error(errSyntaxError, getPos(), "Unexpected MC Type: {0:d}", args[1].getType());
+ }
+ char* name1 = args[1].getName();
+ Object markedContent;
+ MarkedContentStack *mc = mcStack;
+ mc->kind = gfxMCOptionalContent;
+ if ( res->lookupMarkedContentNF( name1, &markedContent ) ) {
+ bool visible = contentConfig->optContentIsVisible(&markedContent);
+ mc->ocSuppressed = !(visible);
+ } else {
+ error(errSyntaxError, getPos(), "DID NOT find {0:s}", name1);
+ }
+ markedContent.free();
+ } else {
+ error(errSyntaxError, getPos(), "insufficient arguments for Marked Content");
+ }
+ } else if (args[0].isName("Span") && numArgs == 2 && args[1].isDict()) {
+ Object obj;
+ if (args[1].dictLookup("ActualText", &obj)->isString()) {
+ out->beginActualText(state, obj.getString());
+ MarkedContentStack *mc = mcStack;
+ mc->kind = gfxMCActualText;
+ }
+ obj.free();
+ }
+
+ if (printCommands) {
+ printf(" marked content: %s ", args[0].getName());
+ if (numArgs == 2)
+ args[1].print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+ ocState = !contentIsHidden();
+
+ if (numArgs == 2 && args[1].isDict()) {
+ out->beginMarkedContent(args[0].getName(), args[1].getDict());
+ } else if(numArgs == 1) {
+ out->beginMarkedContent(args[0].getName(), NULL);
+ }
+}
+
+void Gfx::opEndMarkedContent(Object args[], int numArgs) {
+ if (!mcStack) {
+ error(errSyntaxWarning, getPos(), "Mismatched EMC operator");
+ return;
+ }
+
+ MarkedContentStack *mc = mcStack;
+ GfxMarkedContentKind mcKind = mc->kind;
+
+ // pop the stack
+ popMarkedContent();
+
+ if (mcKind == gfxMCActualText)
+ out->endActualText(state);
+ ocState = !contentIsHidden();
+
+ out->endMarkedContent(state);
+}
+
+void Gfx::opMarkPoint(Object args[], int numArgs) {
+ if (printCommands) {
+ printf(" mark point: %s ", args[0].getName());
+ if (numArgs == 2)
+ args[1].print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+
+ if(numArgs == 2 && args[1].isDict()) {
+ out->markPoint(args[0].getName(),args[1].getDict());
+ } else {
+ out->markPoint(args[0].getName());
+ }
+
+}
+
+//------------------------------------------------------------------------
+// misc
+//------------------------------------------------------------------------
+
+struct GfxStackStateSaver {
+ GfxStackStateSaver(Gfx *gfx) : gfx(gfx) {
+ gfx->saveState();
+ }
+
+ ~GfxStackStateSaver() {
+ gfx->restoreState();
+ }
+
+ Gfx * const gfx;
+};
+
+void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
+ double xMin, double yMin, double xMax, double yMax, int rotate) {
+ Dict *dict, *resDict;
+ Object matrixObj, bboxObj, resObj, obj1;
+ double formXMin, formYMin, formXMax, formYMax;
+ double x, y, sx, sy, tx, ty;
+ double m[6], bbox[4];
+ double r, g, b;
+ GfxColor color;
+ double *dash, *dash2;
+ int dashLength;
+ int i;
+
+ // this function assumes that we are in the default user space,
+ // i.e., baseMatrix = ctm
+
+ // if the bounding box has zero width or height, don't draw anything
+ // at all
+ if (xMin == xMax || yMin == yMax) {
+ return;
+ }
+
+ // saves gfx state and automatically restores it on return
+ GfxStackStateSaver stackStateSaver(this);
+
+ // Rotation around the topleft corner (for the NoRotate flag)
+ if (rotate != 0) {
+ const double angle_rad = rotate * M_PI / 180;
+ const double c = cos(angle_rad);
+ const double s = sin(angle_rad);
+
+ // (xMin, yMax) is the pivot
+ const double unrotateMTX[6] = {
+ +c, -s,
+ +s, +c,
+ -c*xMin - s*yMax + xMin, -c*yMax + s*xMin + yMax
+ };
+
+ state->concatCTM(unrotateMTX[0], unrotateMTX[1], unrotateMTX[2],
+ unrotateMTX[3], unrotateMTX[4], unrotateMTX[5]);
+ out->updateCTM(state, unrotateMTX[0], unrotateMTX[1], unrotateMTX[2],
+ unrotateMTX[3], unrotateMTX[4], unrotateMTX[5]);
+ }
+
+ // draw the appearance stream (if there is one)
+ if (str->isStream()) {
+
+ // get stream dict
+ dict = str->streamGetDict();
+
+ // get the form bounding box
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ bboxObj.free();
+ error(errSyntaxError, getPos(), "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ bboxObj.arrayGet(i, &obj1);
+ if (likely(obj1.isNum())) {
+ bbox[i] = obj1.getNum();
+ obj1.free();
+ } else {
+ obj1.free();
+ bboxObj.free();
+ error(errSyntaxError, getPos(), "Bad form bounding box value");
+ return;
+ }
+ }
+ bboxObj.free();
+
+ // get the form matrix
+ dict->lookup("Matrix", &matrixObj);
+ if (matrixObj.isArray() && matrixObj.arrayGetLength() >= 6) {
+ for (i = 0; i < 6; ++i) {
+ matrixObj.arrayGet(i, &obj1);
+ if (likely(obj1.isNum())) {
+ m[i] = obj1.getNum();
+ obj1.free();
+ } else {
+ obj1.free();
+ matrixObj.free();
+ error(errSyntaxError, getPos(), "Bad form matrix");
+ return;
+ }
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ matrixObj.free();
+
+ // transform the four corners of the form bbox to default user
+ // space, and construct the transformed bbox
+ x = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
+ y = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
+ formXMin = formXMax = x;
+ formYMin = formYMax = y;
+ x = bbox[0] * m[0] + bbox[3] * m[2] + m[4];
+ y = bbox[0] * m[1] + bbox[3] * m[3] + m[5];
+ if (x < formXMin) {
+ formXMin = x;
+ } else if (x > formXMax) {
+ formXMax = x;
+ }
+ if (y < formYMin) {
+ formYMin = y;
+ } else if (y > formYMax) {
+ formYMax = y;
+ }
+ x = bbox[2] * m[0] + bbox[1] * m[2] + m[4];
+ y = bbox[2] * m[1] + bbox[1] * m[3] + m[5];
+ if (x < formXMin) {
+ formXMin = x;
+ } else if (x > formXMax) {
+ formXMax = x;
+ }
+ if (y < formYMin) {
+ formYMin = y;
+ } else if (y > formYMax) {
+ formYMax = y;
+ }
+ x = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
+ y = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
+ if (x < formXMin) {
+ formXMin = x;
+ } else if (x > formXMax) {
+ formXMax = x;
+ }
+ if (y < formYMin) {
+ formYMin = y;
+ } else if (y > formYMax) {
+ formYMax = y;
+ }
+
+ // construct a mapping matrix, [sx 0 0], which maps the transformed
+ // [0 sy 0]
+ // [tx ty 1]
+ // bbox to the annotation rectangle
+ if (formXMin == formXMax) {
+ // this shouldn't happen
+ sx = 1;
+ } else {
+ sx = (xMax - xMin) / (formXMax - formXMin);
+ }
+ if (formYMin == formYMax) {
+ // this shouldn't happen
+ sy = 1;
+ } else {
+ sy = (yMax - yMin) / (formYMax - formYMin);
+ }
+ tx = -formXMin * sx + xMin;
+ ty = -formYMin * sy + yMin;
+
+ // the final transform matrix is (form matrix) * (mapping matrix)
+ m[0] *= sx;
+ m[1] *= sy;
+ m[2] *= sx;
+ m[3] *= sy;
+ m[4] = m[4] * sx + tx;
+ m[5] = m[5] * sy + ty;
+
+ // get the resources
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ // draw it
+ drawForm(str, resDict, m, bbox);
+
+ resObj.free();
+ }
+
+ // draw the border
+ if (border && border->getWidth() > 0) {
+ if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) {
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
+ out->updateStrokeColorSpace(state);
+ }
+ if (aColor && (aColor->getSpace() == AnnotColor::colorRGB)) {
+ const double *values = aColor->getValues();
+ r = values[0];
+ g = values[1];
+ b = values[2];
+ } else {
+ r = g = b = 0;
+ };
+ color.c[0] = dblToCol(r);
+ color.c[1] = dblToCol(g);
+ color.c[2] = dblToCol(b);
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ state->setLineWidth(border->getWidth());
+ out->updateLineWidth(state);
+ dashLength = border->getDashLength();
+ dash = border->getDash();
+ if (border->getStyle() == AnnotBorder::borderDashed && dashLength > 0) {
+ dash2 = (double *)gmallocn(dashLength, sizeof(double));
+ memcpy(dash2, dash, dashLength * sizeof(double));
+ state->setLineDash(dash2, dashLength, 0);
+ out->updateLineDash(state);
+ }
+ //~ this doesn't currently handle the beveled and engraved styles
+ state->clearPath();
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ if (border->getStyle() != AnnotBorder::borderUnderlined) {
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ }
+ out->stroke(state);
+ }
+}
+
+int Gfx::bottomGuard() {
+ return stateGuards[stateGuards.size()-1];
+}
+
+void Gfx::pushStateGuard() {
+ stateGuards.push_back(stackHeight);
+}
+
+void Gfx::popStateGuard() {
+ while (stackHeight > bottomGuard() && state->hasSaves())
+ restoreState();
+ stateGuards.pop_back();
+}
+
+void Gfx::saveState() {
+ out->saveState(state);
+ state = state->save();
+ stackHeight++;
+}
+
+void Gfx::restoreState() {
+ if (stackHeight <= bottomGuard() || !state->hasSaves()) {
+ error(errSyntaxError, -1, "Restoring state when no valid states to pop");
+ commandAborted = gTrue;
+ return;
+ }
+ state = state->restore();
+ out->restoreState(state);
+ stackHeight--;
+}
+
+// Create a new state stack, and initialize it with a copy of the
+// current state.
+GfxState *Gfx::saveStateStack() {
+ GfxState *oldState;
+
+ out->saveState(state);
+ oldState = state;
+ state = state->copy(gTrue);
+ return oldState;
+}
+
+// Switch back to the previous state stack.
+void Gfx::restoreStateStack(GfxState *oldState) {
+ while (state->hasSaves()) {
+ restoreState();
+ }
+ delete state;
+ state = oldState;
+ out->restoreState(state);
+}
+
+void Gfx::pushResources(Dict *resDict) {
+ res = new GfxResources(xref, resDict, res);
+}
+
+void Gfx::popResources() {
+ GfxResources *resPtr;
+
+ resPtr = res->getNext();
+ delete res;
+ res = resPtr;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Gfx.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Gfx.h
new file mode 100644
index 00000000000..a82f9f4af24
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Gfx.h
@@ -0,0 +1,387 @@
+//========================================================================
+//
+// Gfx.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
+// Copyright (C) 2007 Iñigo Martínez <inigomartinez@gmail.com>
+// Copyright (C) 2008 Brad Hards <bradh@kde.org>
+// Copyright (C) 2008, 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009-2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009, 2010, 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2010 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef GFX_H
+#define GFX_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "goo/gtypes.h"
+#include "goo/GooList.h"
+#include "GfxState.h"
+#include "Object.h"
+#include "PopplerCache.h"
+
+#include <vector>
+
+class GooString;
+class PDFDoc;
+class XRef;
+class Array;
+class Stream;
+class Parser;
+class Dict;
+class Function;
+class OutputDev;
+class GfxFontDict;
+class GfxFont;
+class GfxPattern;
+class GfxTilingPattern;
+class GfxShadingPattern;
+class GfxShading;
+class GfxFunctionShading;
+class GfxAxialShading;
+class GfxRadialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
+struct GfxPatch;
+class GfxState;
+struct GfxColor;
+class GfxColorSpace;
+class Gfx;
+class PDFRectangle;
+class AnnotBorder;
+class AnnotColor;
+class Catalog;
+struct MarkedContentStack;
+
+//------------------------------------------------------------------------
+
+enum GfxClipType {
+ clipNone,
+ clipNormal,
+ clipEO
+};
+
+enum TchkType {
+ tchkBool, // boolean
+ tchkInt, // integer
+ tchkNum, // number (integer or real)
+ tchkString, // string
+ tchkName, // name
+ tchkArray, // array
+ tchkProps, // properties (dictionary or name)
+ tchkSCN, // scn/SCN args (number of name)
+ tchkNone // used to avoid empty initializer lists
+};
+
+#define maxArgs 33
+
+struct Operator {
+ char name[4];
+ int numArgs;
+ TchkType tchk[maxArgs];
+ void (Gfx::*func)(Object args[], int numArgs);
+};
+
+//------------------------------------------------------------------------
+
+class GfxResources {
+public:
+
+ GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA);
+ ~GfxResources();
+
+ GfxFont *lookupFont(char *name);
+ GBool lookupXObject(char *name, Object *obj);
+ GBool lookupXObjectNF(char *name, Object *obj);
+ GBool lookupMarkedContentNF(char *name, Object *obj);
+ void lookupColorSpace(const char *name, Object *obj);
+ GfxPattern *lookupPattern(char *name, OutputDev *out, GfxState *state);
+ GfxShading *lookupShading(char *name, OutputDev *out, GfxState *state);
+ GBool lookupGState(char *name, Object *obj);
+ GBool lookupGStateNF(char *name, Object *obj);
+
+ GfxResources *getNext() { return next; }
+
+private:
+
+ GfxFontDict *fonts;
+ Object xObjDict;
+ Object colorSpaceDict;
+ Object patternDict;
+ Object shadingDict;
+ Object gStateDict;
+ PopplerObjectCache gStateCache;
+ Object propertiesDict;
+ GfxResources *next;
+};
+
+//------------------------------------------------------------------------
+// Gfx
+//------------------------------------------------------------------------
+
+class Gfx {
+public:
+
+ // Constructor for regular output.
+ Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
+ double hDPI, double vDPI, PDFRectangle *box,
+ PDFRectangle *cropBox, int rotate,
+ GBool (*abortCheckCbkA)(void *data) = NULL,
+ void *abortCheckCbkDataA = NULL, XRef *xrefA = NULL);
+
+ // Constructor for a sub-page object.
+ Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict,
+ PDFRectangle *box, PDFRectangle *cropBox,
+ GBool (*abortCheckCbkA)(void *data) = NULL,
+ void *abortCheckCbkDataA = NULL, XRef *xrefA = NULL);
+#ifdef USE_CMS
+ void initDisplayProfile();
+#endif
+ ~Gfx();
+
+ XRef *getXRef() { return xref; }
+
+ // Interpret a stream or array of streams.
+ void display(Object *obj, GBool topLevel = gTrue);
+
+ // Display an annotation, given its appearance (a Form XObject),
+ // border style, and bounding box (in default user space).
+ void drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
+ double xMin, double yMin, double xMax, double yMax, int rotate);
+
+ // Save graphics state.
+ void saveState();
+
+ // Push a new state guard
+ void pushStateGuard();
+
+ // Restore graphics state.
+ void restoreState();
+
+ // Pop to state guard and pop guard
+ void popStateGuard();
+
+ // Get the current graphics state object.
+ GfxState *getState() { return state; }
+
+ GBool checkTransparencyGroup(Dict *resDict);
+
+ void drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
+ GBool transpGroup = gFalse, GBool softMask = gFalse,
+ GfxColorSpace *blendingColorSpace = NULL,
+ GBool isolated = gFalse, GBool knockout = gFalse,
+ GBool alpha = gFalse, Function *transferFunc = NULL,
+ GfxColor *backdropColor = NULL);
+
+ void pushResources(Dict *resDict);
+ void popResources();
+
+private:
+
+ PDFDoc *doc;
+ XRef *xref; // the xref table for this PDF file
+ Catalog *catalog; // the Catalog for this PDF file
+ OutputDev *out; // output device
+ GBool subPage; // is this a sub-page object?
+ GBool printCommands; // print the drawing commands (for debugging)
+ GBool profileCommands; // profile the drawing commands (for debugging)
+ GBool commandAborted; // did the previous command abort the drawing?
+ GfxResources *res; // resource stack
+ int updateLevel;
+
+ GfxState *state; // current graphics state
+ int stackHeight; // the height of the current graphics stack
+ std::vector<int> stateGuards; // a stack of state limits; to guard against unmatched pops
+ GBool fontChanged; // set if font or text matrix has changed
+ GfxClipType clip; // do a clip?
+ int ignoreUndef; // current BX/EX nesting level
+ double baseMatrix[6]; // default matrix for most recent
+ // page/form/pattern
+ int formDepth;
+ GBool ocState; // true if drawing is enabled, false if
+ // disabled
+
+ MarkedContentStack *mcStack; // current BMC/EMC stack
+
+ Parser *parser; // parser for page content stream(s)
+
+ std::set<int> formsDrawing; // the forms that are being drawn
+
+ GBool // callback to check for an abort
+ (*abortCheckCbk)(void *data);
+ void *abortCheckCbkData;
+
+ static Operator opTab[]; // table of operators
+
+ void go(GBool topLevel);
+ void execOp(Object *cmd, Object args[], int numArgs);
+ Operator *findOp(char *name);
+ GBool checkArg(Object *arg, TchkType type);
+ Goffset getPos();
+
+ int bottomGuard();
+
+ // graphics state operators
+ void opSave(Object args[], int numArgs);
+ void opRestore(Object args[], int numArgs);
+ void opConcat(Object args[], int numArgs);
+ void opSetDash(Object args[], int numArgs);
+ void opSetFlat(Object args[], int numArgs);
+ void opSetLineJoin(Object args[], int numArgs);
+ void opSetLineCap(Object args[], int numArgs);
+ void opSetMiterLimit(Object args[], int numArgs);
+ void opSetLineWidth(Object args[], int numArgs);
+ void opSetExtGState(Object args[], int numArgs);
+ void doSoftMask(Object *str, GBool alpha,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ Function *transferFunc, GfxColor *backdropColor);
+ void opSetRenderingIntent(Object args[], int numArgs);
+
+ // color operators
+ void opSetFillGray(Object args[], int numArgs);
+ void opSetStrokeGray(Object args[], int numArgs);
+ void opSetFillCMYKColor(Object args[], int numArgs);
+ void opSetStrokeCMYKColor(Object args[], int numArgs);
+ void opSetFillRGBColor(Object args[], int numArgs);
+ void opSetStrokeRGBColor(Object args[], int numArgs);
+ void opSetFillColorSpace(Object args[], int numArgs);
+ void opSetStrokeColorSpace(Object args[], int numArgs);
+ void opSetFillColor(Object args[], int numArgs);
+ void opSetStrokeColor(Object args[], int numArgs);
+ void opSetFillColorN(Object args[], int numArgs);
+ void opSetStrokeColorN(Object args[], int numArgs);
+
+ // path segment operators
+ void opMoveTo(Object args[], int numArgs);
+ void opLineTo(Object args[], int numArgs);
+ void opCurveTo(Object args[], int numArgs);
+ void opCurveTo1(Object args[], int numArgs);
+ void opCurveTo2(Object args[], int numArgs);
+ void opRectangle(Object args[], int numArgs);
+ void opClosePath(Object args[], int numArgs);
+
+ // path painting operators
+ void opEndPath(Object args[], int numArgs);
+ void opStroke(Object args[], int numArgs);
+ void opCloseStroke(Object args[], int numArgs);
+ void opFill(Object args[], int numArgs);
+ void opEOFill(Object args[], int numArgs);
+ void opFillStroke(Object args[], int numArgs);
+ void opCloseFillStroke(Object args[], int numArgs);
+ void opEOFillStroke(Object args[], int numArgs);
+ void opCloseEOFillStroke(Object args[], int numArgs);
+ void doPatternFill(GBool eoFill);
+ void doPatternStroke();
+ void doPatternText();
+ void doPatternImageMask(Object *ref, Stream *str, int width, int height,
+ GBool invert, GBool inlineImg);
+ void doTilingPatternFill(GfxTilingPattern *tPat,
+ GBool stroke, GBool eoFill, GBool text);
+ void doShadingPatternFill(GfxShadingPattern *sPat,
+ GBool stroke, GBool eoFill, GBool text);
+ void opShFill(Object args[], int numArgs);
+ void doFunctionShFill(GfxFunctionShading *shading);
+ void doFunctionShFill1(GfxFunctionShading *shading,
+ double x0, double y0,
+ double x1, double y1,
+ GfxColor *colors, int depth);
+ void doAxialShFill(GfxAxialShading *shading);
+ void doRadialShFill(GfxRadialShading *shading);
+ void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading);
+ void gouraudFillTriangle(double x0, double y0, GfxColor *color0,
+ double x1, double y1, GfxColor *color1,
+ double x2, double y2, GfxColor *color2,
+ int nComps, int depth, GfxState::ReusablePathIterator *path);
+ void gouraudFillTriangle(double x0, double y0, double color0,
+ double x1, double y1, double color1,
+ double x2, double y2, double color2,
+ double refineColorThreshold, int depth, GfxGouraudTriangleShading *shading, GfxState::ReusablePathIterator *path);
+ void doPatchMeshShFill(GfxPatchMeshShading *shading);
+ void fillPatch(GfxPatch *patch, int colorComps, int patchColorComps, double refineColorThreshold, int depth, GfxPatchMeshShading *shading);
+ void doEndPath();
+
+ // path clipping operators
+ void opClip(Object args[], int numArgs);
+ void opEOClip(Object args[], int numArgs);
+
+ // text object operators
+ void opBeginText(Object args[], int numArgs);
+ void opEndText(Object args[], int numArgs);
+
+ // text state operators
+ void opSetCharSpacing(Object args[], int numArgs);
+ void opSetFont(Object args[], int numArgs);
+ void opSetTextLeading(Object args[], int numArgs);
+ void opSetTextRender(Object args[], int numArgs);
+ void opSetTextRise(Object args[], int numArgs);
+ void opSetWordSpacing(Object args[], int numArgs);
+ void opSetHorizScaling(Object args[], int numArgs);
+
+ // text positioning operators
+ void opTextMove(Object args[], int numArgs);
+ void opTextMoveSet(Object args[], int numArgs);
+ void opSetTextMatrix(Object args[], int numArgs);
+ void opTextNextLine(Object args[], int numArgs);
+
+ // text string operators
+ void opShowText(Object args[], int numArgs);
+ void opMoveShowText(Object args[], int numArgs);
+ void opMoveSetShowText(Object args[], int numArgs);
+ void opShowSpaceText(Object args[], int numArgs);
+ void doShowText(GooString *s);
+ void doIncCharCount(GooString *s);
+
+ // XObject operators
+ void opXObject(Object args[], int numArgs);
+ void doImage(Object *ref, Stream *str, GBool inlineImg);
+ void doForm(Object *str);
+
+ // in-line image operators
+ void opBeginImage(Object args[], int numArgs);
+ Stream *buildImageStream();
+ void opImageData(Object args[], int numArgs);
+ void opEndImage(Object args[], int numArgs);
+
+ // type 3 font operators
+ void opSetCharWidth(Object args[], int numArgs);
+ void opSetCacheDevice(Object args[], int numArgs);
+
+ // compatibility operators
+ void opBeginIgnoreUndef(Object args[], int numArgs);
+ void opEndIgnoreUndef(Object args[], int numArgs);
+
+ // marked content operators
+ void opBeginMarkedContent(Object args[], int numArgs);
+ void opEndMarkedContent(Object args[], int numArgs);
+ void opMarkPoint(Object args[], int numArgs);
+ GfxState *saveStateStack();
+ void restoreStateStack(GfxState *oldState);
+ GBool contentIsHidden();
+ void pushMarkedContent();
+ void popMarkedContent();
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxFont.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxFont.cc
new file mode 100644
index 00000000000..81f59037f7f
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxFont.cc
@@ -0,0 +1,2620 @@
+//========================================================================
+//
+// GfxFont.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2006, 2008-2010, 2012, 2014, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2007 Ed Catmur <ed@catmur.co.uk>
+// Copyright (C) 2008 Jonathan Kew <jonathan_kew@sil.org>
+// Copyright (C) 2008 Ed Avis <eda@waniasset.com>
+// Copyright (C) 2008, 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2009 Peter Kerzum <kerzum@yandex-team.ru>
+// Copyright (C) 2009, 2010 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2011 Axel Strübing <axel.struebing@freenet.de>
+// Copyright (C) 2011, 2012, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012 Yi Yang <ahyangyi@gmail.com>
+// Copyright (C) 2012 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013-2015 Jason Crain <jason@aquaticape.us>
+// Copyright (C) 2014 Olly Betts <olly@survex.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <limits.h>
+#include <algorithm>
+#include "goo/gmem.h"
+#include "Error.h"
+#include "Object.h"
+#include "Dict.h"
+#include "GlobalParams.h"
+#include "CMap.h"
+#include "CharCodeToUnicode.h"
+#include "FontEncodingTables.h"
+#include "BuiltinFontTables.h"
+#include "UnicodeTypeTable.h"
+#include <fofi/FoFiIdentifier.h>
+#include <fofi/FoFiType1.h>
+#include <fofi/FoFiType1C.h>
+#include <fofi/FoFiTrueType.h>
+#include "GfxFont.h"
+#include "PSOutputDev.h"
+
+//------------------------------------------------------------------------
+
+struct Base14FontMapEntry {
+ const char *altName;
+ const char *base14Name;
+};
+
+static const Base14FontMapEntry base14FontMap[] = {
+ { "Arial", "Helvetica" },
+ { "Arial,Bold", "Helvetica-Bold" },
+ { "Arial,BoldItalic", "Helvetica-BoldOblique" },
+ { "Arial,Italic", "Helvetica-Oblique" },
+ { "Arial-Bold", "Helvetica-Bold" },
+ { "Arial-BoldItalic", "Helvetica-BoldOblique" },
+ { "Arial-BoldItalicMT", "Helvetica-BoldOblique" },
+ { "Arial-BoldMT", "Helvetica-Bold" },
+ { "Arial-Italic", "Helvetica-Oblique" },
+ { "Arial-ItalicMT", "Helvetica-Oblique" },
+ { "ArialMT", "Helvetica" },
+ { "Courier", "Courier" },
+ { "Courier,Bold", "Courier-Bold" },
+ { "Courier,BoldItalic", "Courier-BoldOblique" },
+ { "Courier,Italic", "Courier-Oblique" },
+ { "Courier-Bold", "Courier-Bold" },
+ { "Courier-BoldOblique", "Courier-BoldOblique" },
+ { "Courier-Oblique", "Courier-Oblique" },
+ { "CourierNew", "Courier" },
+ { "CourierNew,Bold", "Courier-Bold" },
+ { "CourierNew,BoldItalic", "Courier-BoldOblique" },
+ { "CourierNew,Italic", "Courier-Oblique" },
+ { "CourierNew-Bold", "Courier-Bold" },
+ { "CourierNew-BoldItalic", "Courier-BoldOblique" },
+ { "CourierNew-Italic", "Courier-Oblique" },
+ { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" },
+ { "CourierNewPS-BoldMT", "Courier-Bold" },
+ { "CourierNewPS-ItalicMT", "Courier-Oblique" },
+ { "CourierNewPSMT", "Courier" },
+ { "Helvetica", "Helvetica" },
+ { "Helvetica,Bold", "Helvetica-Bold" },
+ { "Helvetica,BoldItalic", "Helvetica-BoldOblique" },
+ { "Helvetica,Italic", "Helvetica-Oblique" },
+ { "Helvetica-Bold", "Helvetica-Bold" },
+ { "Helvetica-BoldItalic", "Helvetica-BoldOblique" },
+ { "Helvetica-BoldOblique", "Helvetica-BoldOblique" },
+ { "Helvetica-Italic", "Helvetica-Oblique" },
+ { "Helvetica-Oblique", "Helvetica-Oblique" },
+ { "Symbol", "Symbol" },
+ { "Symbol,Bold", "Symbol" },
+ { "Symbol,BoldItalic", "Symbol" },
+ { "Symbol,Italic", "Symbol" },
+ { "Times-Bold", "Times-Bold" },
+ { "Times-BoldItalic", "Times-BoldItalic" },
+ { "Times-Italic", "Times-Italic" },
+ { "Times-Roman", "Times-Roman" },
+ { "TimesNewRoman", "Times-Roman" },
+ { "TimesNewRoman,Bold", "Times-Bold" },
+ { "TimesNewRoman,BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRoman,Italic", "Times-Italic" },
+ { "TimesNewRoman-Bold", "Times-Bold" },
+ { "TimesNewRoman-BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRoman-Italic", "Times-Italic" },
+ { "TimesNewRomanPS", "Times-Roman" },
+ { "TimesNewRomanPS-Bold", "Times-Bold" },
+ { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
+ { "TimesNewRomanPS-BoldMT", "Times-Bold" },
+ { "TimesNewRomanPS-Italic", "Times-Italic" },
+ { "TimesNewRomanPS-ItalicMT", "Times-Italic" },
+ { "TimesNewRomanPSMT", "Times-Roman" },
+ { "TimesNewRomanPSMT,Bold", "Times-Bold" },
+ { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRomanPSMT,Italic", "Times-Italic" },
+ { "ZapfDingbats", "ZapfDingbats" }
+};
+
+//------------------------------------------------------------------------
+
+// index: {fixed:0, sans-serif:4, serif:8} + bold*2 + italic
+// NB: must be in same order as psSubstFonts in PSOutputDev.cc
+static const char *base14SubstFonts[14] = {
+ "Courier",
+ "Courier-Oblique",
+ "Courier-Bold",
+ "Courier-BoldOblique",
+ "Helvetica",
+ "Helvetica-Oblique",
+ "Helvetica-Bold",
+ "Helvetica-BoldOblique",
+ "Times-Roman",
+ "Times-Italic",
+ "Times-Bold",
+ "Times-BoldItalic",
+ // the last two are never used for substitution
+ "Symbol",
+ "ZapfDingbats"
+};
+
+//------------------------------------------------------------------------
+
+static int parseCharName(char *charName, Unicode *uBuf, int uLen,
+ GBool names, GBool ligatures,
+ GBool numeric, GBool hex, GBool variants);
+
+//------------------------------------------------------------------------
+
+static int readFromStream(void *data) {
+ return ((Stream *)data)->getChar();
+}
+
+//------------------------------------------------------------------------
+// GfxFontLoc
+//------------------------------------------------------------------------
+
+GfxFontLoc::GfxFontLoc() {
+ path = NULL;
+ fontNum = 0;
+ encoding = NULL;
+ substIdx = -1;
+}
+
+GfxFontLoc::~GfxFontLoc() {
+ if (path) {
+ delete path;
+ }
+ if (encoding) {
+ delete encoding;
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxFont
+//------------------------------------------------------------------------
+
+GfxFont *GfxFont::makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict) {
+ GooString *nameA;
+ Ref embFontIDA;
+ GfxFontType typeA;
+ GfxFont *font;
+ Object obj1;
+
+ // get base font name
+ nameA = NULL;
+ fontDict->lookup("BaseFont", &obj1);
+ if (obj1.isName()) {
+ nameA = new GooString(obj1.getName());
+ }
+ obj1.free();
+
+ // get embedded font ID and font type
+ typeA = getFontType(xref, fontDict, &embFontIDA);
+
+ // create the font object
+ font = NULL;
+ if (typeA < fontCIDType0) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA,
+ fontDict);
+ } else {
+ font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA,
+ fontDict);
+ }
+
+ return font;
+}
+
+GfxFont::GfxFont(const char *tagA, Ref idA, GooString *nameA,
+ GfxFontType typeA, Ref embFontIDA) {
+ ok = gFalse;
+ tag = new GooString(tagA);
+ id = idA;
+ name = nameA;
+ type = typeA;
+ embFontID = embFontIDA;
+ embFontName = NULL;
+ family = NULL;
+ stretch = StretchNotDefined;
+ weight = WeightNotDefined;
+ refCnt = 1;
+ encodingName = new GooString("");
+ hasToUnicode = gFalse;
+}
+
+GfxFont::~GfxFont() {
+ delete tag;
+ delete family;
+ if (name) {
+ delete name;
+ }
+ if (embFontName) {
+ delete embFontName;
+ }
+ if (encodingName) {
+ delete encodingName;
+ }
+}
+
+void GfxFont::incRefCnt() {
+ refCnt++;
+}
+
+void GfxFont::decRefCnt() {
+ if (--refCnt == 0)
+ delete this;
+}
+
+// This function extracts three pieces of information:
+// 1. the "expected" font type, i.e., the font type implied by
+// Font.Subtype, DescendantFont.Subtype, and
+// FontDescriptor.FontFile3.Subtype
+// 2. the embedded font object ID
+// 3. the actual font type - determined by examining the embedded font
+// if there is one, otherwise equal to the expected font type
+// If the expected and actual font types don't match, a warning
+// message is printed. The expected font type is not used for
+// anything else.
+GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
+ GfxFontType t, expectedType;
+ FoFiIdentifierType fft;
+ Dict *fontDict2;
+ Object subtype, fontDesc, obj1, obj2, obj3, obj4;
+ GBool isType0, err;
+
+ t = fontUnknownType;
+ embID->num = embID->gen = -1;
+ err = gFalse;
+
+ fontDict->lookup("Subtype", &subtype);
+ expectedType = fontUnknownType;
+ isType0 = gFalse;
+ if (subtype.isName("Type1") || subtype.isName("MMType1")) {
+ expectedType = fontType1;
+ } else if (subtype.isName("Type1C")) {
+ expectedType = fontType1C;
+ } else if (subtype.isName("Type3")) {
+ expectedType = fontType3;
+ } else if (subtype.isName("TrueType")) {
+ expectedType = fontTrueType;
+ } else if (subtype.isName("Type0")) {
+ isType0 = gTrue;
+ } else {
+ error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
+ subtype.isName() ? subtype.getName() : "???");
+ }
+ subtype.free();
+
+ fontDict2 = fontDict;
+ if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == 0) {
+ error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
+ obj2.initNull();
+ } else if (obj1.arrayGet(0, &obj2)->isDict()) {
+ if (!isType0) {
+ error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
+ }
+ fontDict2 = obj2.getDict();
+ fontDict2->lookup("Subtype", &subtype);
+ if (subtype.isName("CIDFontType0")) {
+ if (isType0) {
+ expectedType = fontCIDType0;
+ }
+ } else if (subtype.isName("CIDFontType2")) {
+ if (isType0) {
+ expectedType = fontCIDType2;
+ }
+ }
+ subtype.free();
+ }
+ } else {
+ obj2.initNull();
+ }
+
+ if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) {
+ if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) {
+ *embID = obj3.getRef();
+ if (expectedType != fontType1) {
+ err = gTrue;
+ }
+ }
+ obj3.free();
+ if (embID->num == -1 &&
+ fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) {
+ *embID = obj3.getRef();
+ if (isType0) {
+ expectedType = fontCIDType2;
+ } else if (expectedType != fontTrueType) {
+ err = gTrue;
+ }
+ }
+ obj3.free();
+ if (embID->num == -1 &&
+ fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) {
+ *embID = obj3.getRef();
+ if (obj3.fetch(xref, &obj4)->isStream()) {
+ obj4.streamGetDict()->lookup("Subtype", &subtype);
+ if (subtype.isName("Type1")) {
+ if (expectedType != fontType1) {
+ err = gTrue;
+ expectedType = isType0 ? fontCIDType0 : fontType1;
+ }
+ } else if (subtype.isName("Type1C")) {
+ if (expectedType == fontType1) {
+ expectedType = fontType1C;
+ } else if (expectedType != fontType1C) {
+ err = gTrue;
+ expectedType = isType0 ? fontCIDType0C : fontType1C;
+ }
+ } else if (subtype.isName("TrueType")) {
+ if (expectedType != fontTrueType) {
+ err = gTrue;
+ expectedType = isType0 ? fontCIDType2 : fontTrueType;
+ }
+ } else if (subtype.isName("CIDFontType0C")) {
+ if (expectedType == fontCIDType0) {
+ expectedType = fontCIDType0C;
+ } else {
+ err = gTrue;
+ expectedType = isType0 ? fontCIDType0C : fontType1C;
+ }
+ } else if (subtype.isName("OpenType")) {
+ if (expectedType == fontTrueType) {
+ expectedType = fontTrueTypeOT;
+ } else if (expectedType == fontType1) {
+ expectedType = fontType1COT;
+ } else if (expectedType == fontCIDType0) {
+ expectedType = fontCIDType0COT;
+ } else if (expectedType == fontCIDType2) {
+ expectedType = fontCIDType2OT;
+ } else {
+ err = gTrue;
+ }
+ } else {
+ error(errSyntaxError, -1, "Unknown font type '{0:s}'",
+ subtype.isName() ? subtype.getName() : "???");
+ }
+ subtype.free();
+ }
+ obj4.free();
+ }
+ obj3.free();
+ }
+ fontDesc.free();
+
+ t = fontUnknownType;
+ if (embID->num >= 0) {
+ obj3.initRef(embID->num, embID->gen);
+ obj3.fetch(xref, &obj4);
+ if (obj4.isStream()) {
+ obj4.streamReset();
+ fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream());
+ obj4.streamClose();
+ switch (fft) {
+ case fofiIdType1PFA:
+ case fofiIdType1PFB:
+ t = fontType1;
+ break;
+ case fofiIdCFF8Bit:
+ t = isType0 ? fontCIDType0C : fontType1C;
+ break;
+ case fofiIdCFFCID:
+ t = fontCIDType0C;
+ break;
+ case fofiIdTrueType:
+ case fofiIdTrueTypeCollection:
+ t = isType0 ? fontCIDType2 : fontTrueType;
+ break;
+ case fofiIdOpenTypeCFF8Bit:
+ t = expectedType; // hack: open type always == expected type? s. bug-poppler20605.pdf
+ break;
+ case fofiIdOpenTypeCFFCID:
+ t = fontCIDType0COT;
+ break;
+ default:
+ error(errSyntaxError, -1, "Embedded font file may be invalid");
+ break;
+ }
+ }
+ obj4.free();
+ obj3.free();
+ }
+
+ if (t == fontUnknownType) {
+ t = expectedType;
+ }
+
+ if (t != expectedType) {
+ err = gTrue;
+ }
+
+ if (err) {
+ error(errSyntaxWarning, -1,
+ "Mismatch between font type and embedded font file");
+ }
+
+ obj2.free();
+ obj1.free();
+
+ return t;
+}
+
+void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
+ Object obj1, obj2, obj3, obj4;
+ double t;
+ int i;
+
+ // assume Times-Roman by default (for substitution purposes)
+ flags = fontSerif;
+
+ missingWidth = 0;
+
+ if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
+
+ // get flags
+ if (obj1.dictLookup("Flags", &obj2)->isInt()) {
+ flags = obj2.getInt();
+ }
+ obj2.free();
+
+ // get name
+ obj1.dictLookup("FontName", &obj2);
+ if (obj2.isName()) {
+ embFontName = new GooString(obj2.getName());
+ }
+ obj2.free();
+ if (embFontName == NULL) {
+ // get name with typo
+ obj1.dictLookup("Fontname", &obj2);
+ if (obj2.isName()) {
+ embFontName = new GooString(obj2.getName());
+ error(errSyntaxWarning, -1, "The file uses Fontname instead of FontName please notify the creator that the file is broken");
+ }
+ obj2.free();
+ }
+
+ // get family
+ obj1.dictLookup("FontFamily", &obj2);
+ if (obj2.isString()) family = new GooString(obj2.getString());
+ obj2.free();
+
+ // get stretch
+ obj1.dictLookup("FontStretch", &obj2);
+ if (obj2.isName()) {
+ if (strcmp(obj2.getName(), "UltraCondensed") == 0) stretch = UltraCondensed;
+ else if (strcmp(obj2.getName(), "ExtraCondensed") == 0) stretch = ExtraCondensed;
+ else if (strcmp(obj2.getName(), "Condensed") == 0) stretch = Condensed;
+ else if (strcmp(obj2.getName(), "SemiCondensed") == 0) stretch = SemiCondensed;
+ else if (strcmp(obj2.getName(), "Normal") == 0) stretch = Normal;
+ else if (strcmp(obj2.getName(), "SemiExpanded") == 0) stretch = SemiExpanded;
+ else if (strcmp(obj2.getName(), "Expanded") == 0) stretch = Expanded;
+ else if (strcmp(obj2.getName(), "ExtraExpanded") == 0) stretch = ExtraExpanded;
+ else if (strcmp(obj2.getName(), "UltraExpanded") == 0) stretch = UltraExpanded;
+ else error(errSyntaxWarning, -1, "Invalid Font Stretch");
+ }
+ obj2.free();
+
+ // get weight
+ obj1.dictLookup("FontWeight", &obj2);
+ if (obj2.isNum()) {
+ if (obj2.getNum() == 100) weight = W100;
+ else if (obj2.getNum() == 200) weight = W200;
+ else if (obj2.getNum() == 300) weight = W300;
+ else if (obj2.getNum() == 400) weight = W400;
+ else if (obj2.getNum() == 500) weight = W500;
+ else if (obj2.getNum() == 600) weight = W600;
+ else if (obj2.getNum() == 700) weight = W700;
+ else if (obj2.getNum() == 800) weight = W800;
+ else if (obj2.getNum() == 900) weight = W900;
+ else error(errSyntaxWarning, -1, "Invalid Font Weight");
+ }
+ obj2.free();
+
+ // look for MissingWidth
+ obj1.dictLookup("MissingWidth", &obj2);
+ if (obj2.isNum()) {
+ missingWidth = obj2.getNum();
+ }
+ obj2.free();
+
+ // get Ascent and Descent
+ obj1.dictLookup("Ascent", &obj2);
+ if (obj2.isNum()) {
+ t = 0.001 * obj2.getNum();
+ // some broken font descriptors specify a negative ascent
+ if (t < 0) {
+ t = -t;
+ }
+ // some broken font descriptors set ascent and descent to 0;
+ // others set it to ridiculous values (e.g., 32768)
+ if (t != 0 && t < 3) {
+ ascent = t;
+ }
+ }
+ obj2.free();
+ obj1.dictLookup("Descent", &obj2);
+ if (obj2.isNum()) {
+ t = 0.001 * obj2.getNum();
+ // some broken font descriptors specify a positive descent
+ if (t > 0) {
+ t = -t;
+ }
+ // some broken font descriptors set ascent and descent to 0
+ if (t != 0 && t > -3) {
+ descent = t;
+ }
+ }
+ obj2.free();
+
+ // font FontBBox
+ if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
+ for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ fontBBox[i] = 0.001 * obj3.getNum();
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+
+ }
+ obj1.free();
+}
+
+CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
+ CharCodeToUnicode *ctu) {
+ GooString *buf;
+ Object obj1;
+
+ if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
+ obj1.free();
+ return NULL;
+ }
+ buf = new GooString();
+ obj1.getStream()->fillGooString(buf);
+ obj1.streamClose();
+ obj1.free();
+ if (ctu) {
+ ctu->mergeCMap(buf, nBits);
+ } else {
+ ctu = CharCodeToUnicode::parseCMap(buf, nBits);
+ }
+ hasToUnicode = gTrue;
+ delete buf;
+ return ctu;
+}
+
+GfxFontLoc *GfxFont::locateFont(XRef *xref, PSOutputDev *ps) {
+ GfxFontLoc *fontLoc;
+ SysFontType sysFontType;
+ GooString *path, *base14Name, *substName;
+ PSFontParam16 *psFont16;
+ Object refObj, embFontObj;
+ int substIdx, fontNum;
+ GBool embed;
+
+ if (type == fontType3) {
+ return NULL;
+ }
+
+ //----- embedded font
+ if (embFontID.num >= 0) {
+ embed = gTrue;
+ refObj.initRef(embFontID.num, embFontID.gen);
+ refObj.fetch(xref, &embFontObj);
+ if (!embFontObj.isStream()) {
+ error(errSyntaxError, -1, "Embedded font object is wrong type");
+ embed = gFalse;
+ }
+ embFontObj.free();
+ refObj.free();
+ if (embed) {
+ if (ps) {
+ switch (type) {
+ case fontType1:
+ case fontType1C:
+ case fontType1COT:
+ embed = ps->getEmbedType1();
+ break;
+ case fontTrueType:
+ case fontTrueTypeOT:
+ embed = ps->getEmbedTrueType();
+ break;
+ case fontCIDType0C:
+ case fontCIDType0COT:
+ embed = ps->getEmbedCIDPostScript();
+ break;
+ case fontCIDType2:
+ case fontCIDType2OT:
+ embed = ps->getEmbedCIDTrueType();
+ break;
+ default:
+ break;
+ }
+ }
+ if (embed) {
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocEmbedded;
+ fontLoc->fontType = type;
+ fontLoc->embFontID = embFontID;
+ return fontLoc;
+ }
+ }
+ }
+
+ //----- PS passthrough
+ if (ps && !isCIDFont() && ps->getFontPassthrough()) {
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocResident;
+ fontLoc->fontType = fontType1;
+ fontLoc->path = name->copy();
+ return fontLoc;
+ }
+
+ //----- PS resident Base-14 font
+ if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocResident;
+ fontLoc->fontType = fontType1;
+ fontLoc->path = new GooString(((Gfx8BitFont *)this)->base14->base14Name);
+ return fontLoc;
+ }
+
+ //----- external font file (fontFile, fontDir)
+ if (name && (path = globalParams->findFontFile(name))) {
+ if ((fontLoc = getExternalFont(path, isCIDFont()))) {
+ return fontLoc;
+ }
+ }
+
+ //----- external font file for Base-14 font
+ if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
+ base14Name = new GooString(((Gfx8BitFont *)this)->base14->base14Name);
+ if ((path = globalParams->findBase14FontFile(base14Name, this))) {
+ if ((fontLoc = getExternalFont(path, gFalse))) {
+ delete base14Name;
+ return fontLoc;
+ }
+ }
+ delete base14Name;
+ }
+
+ //----- system font
+ if ((path = globalParams->findSystemFontFile(this, &sysFontType,
+ &fontNum))) {
+ if (isCIDFont()) {
+ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocExternal;
+ fontLoc->fontType = fontCIDType2;
+ fontLoc->path = path;
+ fontLoc->fontNum = fontNum;
+ return fontLoc;
+ }
+ } else {
+ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocExternal;
+ fontLoc->fontType = fontTrueType;
+ fontLoc->path = path;
+ return fontLoc;
+ } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) {
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocExternal;
+ fontLoc->fontType = fontType1;
+ fontLoc->path = path;
+ fontLoc->fontNum = fontNum;
+ return fontLoc;
+ }
+ }
+ delete path;
+ }
+
+ if (!isCIDFont()) {
+
+ //----- 8-bit PS resident font
+ if (name && ps) {
+ if ((path = globalParams->getPSResidentFont(name))) {
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocResident;
+ fontLoc->fontType = fontType1;
+ fontLoc->path = path;
+ return fontLoc;
+ }
+ }
+
+ //----- 8-bit font substitution
+ if (flags & fontFixedWidth) {
+ substIdx = 0;
+ } else if (flags & fontSerif) {
+ substIdx = 8;
+ } else {
+ substIdx = 4;
+ }
+ if (isBold()) {
+ substIdx += 2;
+ }
+ if (isItalic()) {
+ substIdx += 1;
+ }
+ substName = new GooString(base14SubstFonts[substIdx]);
+ if (ps) {
+ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:s}'",
+ base14SubstFonts[substIdx], name ? name->getCString() : "null");
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocResident;
+ fontLoc->fontType = fontType1;
+ fontLoc->path = substName;
+ fontLoc->substIdx = substIdx;
+ return fontLoc;
+ } else {
+ path = globalParams->findFontFile(substName);
+ delete substName;
+ if (path) {
+ if ((fontLoc = getExternalFont(path, gFalse))) {
+ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:s}'",
+ base14SubstFonts[substIdx], name ? name->getCString() : "");
+ name = new GooString(base14SubstFonts[substIdx]);
+ fontLoc->substIdx = substIdx;
+ return fontLoc;
+ }
+ }
+ }
+
+ // failed to find a substitute font
+ return NULL;
+ }
+
+ //----- 16-bit PS resident font
+ if (ps && ((psFont16 = globalParams->getPSResidentFont16(
+ name,
+ ((GfxCIDFont *)this)->getWMode())))) {
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocResident;
+ fontLoc->fontType = fontCIDType0; // this is not used
+ fontLoc->path = psFont16->psFontName->copy();
+ fontLoc->encoding = psFont16->encoding->copy();
+ fontLoc->wMode = psFont16->wMode;
+ return fontLoc;
+ }
+ if (ps && ((psFont16 = globalParams->getPSResidentFontCC(
+ ((GfxCIDFont *)this)->getCollection(),
+ ((GfxCIDFont *)this)->getWMode())))) {
+ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
+ psFont16->psFontName, name);
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocResident;
+ fontLoc->fontType = fontCIDType0; // this is not used
+ fontLoc->path = psFont16->psFontName->copy();
+ fontLoc->encoding = psFont16->encoding->copy();
+ fontLoc->wMode = psFont16->wMode;
+ return fontLoc;
+ }
+
+ //----- CID font substitution
+ if ((path = globalParams->findCCFontFile(
+ ((GfxCIDFont *)this)->getCollection()))) {
+ if ((fontLoc = getExternalFont(path, gTrue))) {
+ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
+ fontLoc->path, name);
+ return fontLoc;
+ }
+ }
+
+ // failed to find a substitute font
+ return NULL;
+}
+
+GfxFontLoc *GfxFont::locateBase14Font(GooString *base14Name) {
+ GooString *path;
+
+ path = globalParams->findFontFile(base14Name);
+ if (!path) {
+ return NULL;
+ }
+ return getExternalFont(path, gFalse);
+}
+
+GfxFontLoc *GfxFont::getExternalFont(GooString *path, GBool cid) {
+ FoFiIdentifierType fft;
+ GfxFontType fontType;
+ GfxFontLoc *fontLoc;
+
+ fft = FoFiIdentifier::identifyFile(path->getCString());
+ switch (fft) {
+ case fofiIdType1PFA:
+ case fofiIdType1PFB:
+ fontType = fontType1;
+ break;
+ case fofiIdCFF8Bit:
+ fontType = fontType1C;
+ break;
+ case fofiIdCFFCID:
+ fontType = fontCIDType0C;
+ break;
+ case fofiIdTrueType:
+ case fofiIdTrueTypeCollection:
+ fontType = cid ? fontCIDType2 : fontTrueType;
+ break;
+ case fofiIdOpenTypeCFF8Bit:
+ fontType = fontType1COT;
+ break;
+ case fofiIdOpenTypeCFFCID:
+ fontType = fontCIDType0COT;
+ break;
+ case fofiIdUnknown:
+ case fofiIdError:
+ default:
+ fontType = fontUnknownType;
+ break;
+ }
+ if (fontType == fontUnknownType ||
+ (cid ? (fontType < fontCIDType0)
+ : (fontType >= fontCIDType0))) {
+ delete path;
+ return NULL;
+ }
+ fontLoc = new GfxFontLoc();
+ fontLoc->locType = gfxFontLocExternal;
+ fontLoc->fontType = fontType;
+ fontLoc->path = path;
+ return fontLoc;
+}
+
+char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
+ char *buf;
+ Object obj1, obj2;
+ Stream *str;
+
+ obj1.initRef(embFontID.num, embFontID.gen);
+ obj1.fetch(xref, &obj2);
+ if (!obj2.isStream()) {
+ error(errSyntaxError, -1, "Embedded font file is not a stream");
+ obj2.free();
+ obj1.free();
+ embFontID.num = -1;
+ *len = 0;
+ return NULL;
+ }
+ str = obj2.getStream();
+
+ buf = (char*)str->toUnsignedChars(len);
+ str->close();
+
+ obj2.free();
+ obj1.free();
+
+ return buf;
+}
+
+
+struct AlternateNameMap {
+ const char *name;
+ const char *alt;
+};
+
+static const AlternateNameMap alternateNameMap[] =
+{
+ { "fi", "f_i" },
+ { "fl", "f_l" },
+ { "ff", "f_f" },
+ { "ffi", "f_f_i" },
+ { "ffl", "f_f_l" },
+ { 0, 0 }
+};
+
+const char *GfxFont::getAlternateName(const char *name) {
+ const AlternateNameMap *map = alternateNameMap;
+ while (map->name) {
+ if (strcmp(name, map->name) == 0) {
+ return map->alt;
+ }
+ map++;
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------
+// Gfx8BitFont
+//------------------------------------------------------------------------
+
+// Parse character names of the form 'Axx', 'xx', 'Ann', 'ABnn', or
+// 'nn', where 'A' and 'B' are any letters, 'xx' is two hex digits,
+// and 'nn' is decimal digits.
+static GBool parseNumericName(char *s, GBool hex, unsigned int *u) {
+ char *endptr;
+
+ // Strip leading alpha characters.
+ if (hex) {
+ int n = 0;
+
+ // Get string length while ignoring junk at end.
+ while (isalnum(s[n]))
+ ++n;
+
+ // Only 2 hex characters with optional leading alpha is allowed.
+ if (n == 3 && isalpha(*s)) {
+ ++s;
+ } else if (n != 2) {
+ return gFalse;
+ }
+ } else {
+ // Strip up to two alpha characters.
+ for (int i = 0; i < 2 && isalpha(*s); ++i)
+ ++s;
+ }
+
+ int v = strtol(s, &endptr, hex ? 16 : 10);
+
+ if (endptr == s)
+ return gFalse;
+
+ // Skip trailing junk characters.
+ while (*endptr != '\0' && !isalnum(*endptr))
+ ++endptr;
+
+ if (*endptr == '\0') {
+ if (u)
+ *u = v;
+ return gTrue;
+ }
+ return gFalse;
+}
+
+// Returns gTrue if the font has character names like xx or Axx which
+// should be parsed for hex or decimal values.
+static GBool testForNumericNames(Dict *fontDict, GBool hex) {
+ Object enc, diff, obj;
+ GBool numeric = gTrue;
+
+ fontDict->lookup("Encoding", &enc);
+ if (!enc.isDict()) {
+ enc.free();
+ return gFalse;
+ }
+
+ enc.dictLookup("Differences", &diff);
+ enc.free();
+ if (!diff.isArray()) {
+ diff.free();
+ return gFalse;
+ }
+
+ for (int i = 0; i < diff.arrayGetLength() && numeric; ++i) {
+ diff.arrayGet(i, &obj);
+ if (obj.isInt()) {
+ // All sequences must start between character codes 0 and 5.
+ if (obj.getInt() > 5)
+ numeric = gFalse;
+ } else if (obj.isName()) {
+ // All character names must sucessfully parse.
+ if (!parseNumericName(obj.getName(), hex, NULL))
+ numeric = gFalse;
+ } else {
+ numeric = gFalse;
+ }
+ obj.free();
+ }
+
+ diff.free();
+ return numeric;
+}
+
+Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
+ GfxFont(tagA, idA, nameA, typeA, embFontIDA) {
+ GooString *name2;
+ BuiltinFont *builtinFont;
+ const char **baseEnc;
+ GBool baseEncFromFontFile;
+ char *buf;
+ int len;
+ FoFiType1 *ffT1;
+ FoFiType1C *ffT1C;
+ int code;
+ char *charName;
+ GBool missing, hex;
+ GBool numeric;
+ Unicode toUnicode[256];
+ CharCodeToUnicode *utu, *ctu2;
+ Unicode uBuf[8];
+ double mul;
+ int firstChar, lastChar;
+ Gushort w;
+ Object obj1, obj2, obj3;
+ int n, i, a, b, m;
+
+ refCnt = 1;
+ ctu = NULL;
+
+ // do font name substitution for various aliases of the Base 14 font
+ // names
+ base14 = NULL;
+ if (name) {
+ name2 = name->copy();
+ i = 0;
+ while (i < name2->getLength()) {
+ if (name2->getChar(i) == ' ') {
+ name2->del(i);
+ } else {
+ ++i;
+ }
+ }
+ a = 0;
+ b = sizeof(base14FontMap) / sizeof(Base14FontMapEntry);
+ // invariant: base14FontMap[a].altName <= name2 < base14FontMap[b].altName
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (name2->cmp(base14FontMap[m].altName) >= 0) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (!name2->cmp(base14FontMap[a].altName)) {
+ base14 = &base14FontMap[a];
+ }
+ delete name2;
+ }
+
+ // is it a built-in font?
+ builtinFont = NULL;
+ if (base14) {
+ for (i = 0; i < nBuiltinFonts; ++i) {
+ if (!strcmp(base14->base14Name, builtinFonts[i].name)) {
+ builtinFont = &builtinFonts[i];
+ break;
+ }
+ }
+ }
+
+ // default ascent/descent values
+ if (builtinFont) {
+ ascent = 0.001 * builtinFont->ascent;
+ descent = 0.001 * builtinFont->descent;
+ fontBBox[0] = 0.001 * builtinFont->bbox[0];
+ fontBBox[1] = 0.001 * builtinFont->bbox[1];
+ fontBBox[2] = 0.001 * builtinFont->bbox[2];
+ fontBBox[3] = 0.001 * builtinFont->bbox[3];
+ } else {
+ ascent = 0.95;
+ descent = -0.35;
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+ }
+
+ // get info from font descriptor
+ readFontDescriptor(xref, fontDict);
+
+ // for non-embedded fonts, don't trust the ascent/descent/bbox
+ // values from the font descriptor
+ if (builtinFont && embFontID.num < 0) {
+ ascent = 0.001 * builtinFont->ascent;
+ descent = 0.001 * builtinFont->descent;
+ fontBBox[0] = 0.001 * builtinFont->bbox[0];
+ fontBBox[1] = 0.001 * builtinFont->bbox[1];
+ fontBBox[2] = 0.001 * builtinFont->bbox[2];
+ fontBBox[3] = 0.001 * builtinFont->bbox[3];
+ }
+
+ // get font matrix
+ fontMat[0] = fontMat[3] = 1;
+ fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
+ if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
+ for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ fontMat[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ // get Type 3 bounding box, font definition, and resources
+ if (type == fontType3) {
+ if (fontDict->lookup("FontBBox", &obj1)->isArray()) {
+ for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ fontBBox[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+ if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) {
+ error(errSyntaxError, -1,
+ "Missing or invalid CharProcs dictionary in Type 3 font");
+ charProcs.free();
+ }
+ if (!fontDict->lookup("Resources", &resources)->isDict()) {
+ resources.free();
+ }
+ }
+
+ //----- build the font encoding -----
+
+ // Encodings start with a base encoding, which can come from
+ // (in order of priority):
+ // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
+ // - MacRoman / MacExpert / WinAnsi / Standard
+ // 2. embedded or external font file
+ // 3. default:
+ // - builtin --> builtin encoding
+ // - TrueType --> WinAnsiEncoding
+ // - others --> StandardEncoding
+ // and then add a list of differences (if any) from
+ // FontDict.Encoding.Differences.
+
+ // check FontDict for base encoding
+ hasEncoding = gFalse;
+ usesMacRomanEnc = gFalse;
+ baseEnc = NULL;
+ baseEncFromFontFile = gFalse;
+ fontDict->lookup("Encoding", &obj1);
+ if (obj1.isDict()) {
+ obj1.dictLookup("BaseEncoding", &obj2);
+ if (obj2.isName("MacRomanEncoding")) {
+ hasEncoding = gTrue;
+ usesMacRomanEnc = gTrue;
+ baseEnc = macRomanEncoding;
+ } else if (obj2.isName("MacExpertEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = macExpertEncoding;
+ } else if (obj2.isName("WinAnsiEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = winAnsiEncoding;
+ }
+ obj2.free();
+ } else if (obj1.isName("MacRomanEncoding")) {
+ hasEncoding = gTrue;
+ usesMacRomanEnc = gTrue;
+ baseEnc = macRomanEncoding;
+ } else if (obj1.isName("MacExpertEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = macExpertEncoding;
+ } else if (obj1.isName("WinAnsiEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = winAnsiEncoding;
+ }
+
+ // check embedded font file for base encoding
+ // (only for Type 1 fonts - trying to get an encoding out of a
+ // TrueType font is a losing proposition)
+ ffT1 = NULL;
+ ffT1C = NULL;
+ buf = NULL;
+ if (type == fontType1 && embFontID.num >= 0) {
+ if ((buf = readEmbFontFile(xref, &len))) {
+ if ((ffT1 = FoFiType1::make(buf, len))) {
+ if (ffT1->getName()) {
+ if (embFontName) {
+ delete embFontName;
+ }
+ embFontName = new GooString(ffT1->getName());
+ }
+ if (!baseEnc) {
+ baseEnc = (const char **)ffT1->getEncoding();
+ baseEncFromFontFile = gTrue;
+ }
+ }
+ gfree(buf);
+ }
+ } else if (type == fontType1C && embFontID.num >= 0) {
+ if ((buf = readEmbFontFile(xref, &len))) {
+ if ((ffT1C = FoFiType1C::make(buf, len))) {
+ if (ffT1C->getName()) {
+ if (embFontName) {
+ delete embFontName;
+ }
+ embFontName = new GooString(ffT1C->getName());
+ }
+ if (!baseEnc) {
+ baseEnc = (const char **)ffT1C->getEncoding();
+ baseEncFromFontFile = gTrue;
+ }
+ }
+ gfree(buf);
+ }
+ }
+
+ // get default base encoding
+ if (!baseEnc) {
+ if (builtinFont && embFontID.num < 0) {
+ baseEnc = builtinFont->defaultBaseEnc;
+ hasEncoding = gTrue;
+ } else if (type == fontTrueType) {
+ baseEnc = winAnsiEncoding;
+ } else {
+ baseEnc = standardEncoding;
+ }
+ }
+
+ if (baseEncFromFontFile) {
+ encodingName->Set("Builtin");
+ } else if (baseEnc == winAnsiEncoding) {
+ encodingName->Set("WinAnsi");
+ } else if (baseEnc == macRomanEncoding) {
+ encodingName->Set("MacRoman");
+ } else if (baseEnc == macExpertEncoding) {
+ encodingName->Set("MacExpert");
+ } else if (baseEnc == symbolEncoding) {
+ encodingName->Set("Symbol");
+ } else if (baseEnc == zapfDingbatsEncoding) {
+ encodingName->Set("ZapfDingbats");
+ } else {
+ encodingName->Set("Standard");
+ }
+
+ // copy the base encoding
+ for (i = 0; i < 256; ++i) {
+ enc[i] = (char *)baseEnc[i];
+ if ((encFree[i] = baseEncFromFontFile) && enc[i]) {
+ enc[i] = copyString(baseEnc[i]);
+ }
+ }
+
+ // some Type 1C font files have empty encodings, which can break the
+ // T1C->T1 conversion (since the 'seac' operator depends on having
+ // the accents in the encoding), so we fill in any gaps from
+ // StandardEncoding
+ if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) {
+ for (i = 0; i < 256; ++i) {
+ if (!enc[i] && standardEncoding[i]) {
+ enc[i] = (char *)standardEncoding[i];
+ encFree[i] = gFalse;
+ }
+ }
+ }
+
+ // merge differences into encoding
+ if (obj1.isDict()) {
+ obj1.dictLookup("Differences", &obj2);
+ if (obj2.isArray()) {
+ encodingName->Set("Custom");
+ hasEncoding = gTrue;
+ code = 0;
+ for (i = 0; i < obj2.arrayGetLength(); ++i) {
+ obj2.arrayGet(i, &obj3);
+ if (obj3.isInt()) {
+ code = obj3.getInt();
+ } else if (obj3.isName()) {
+ if (code >= 0 && code < 256) {
+ if (encFree[code]) {
+ gfree(enc[code]);
+ }
+ enc[code] = copyString(obj3.getName());
+ encFree[code] = gTrue;
+ }
+ ++code;
+ } else {
+ error(errSyntaxError, -1,
+ "Wrong type in font encoding resource differences ({0:s})",
+ obj3.getTypeName());
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ if (ffT1) {
+ delete ffT1;
+ }
+ if (ffT1C) {
+ delete ffT1C;
+ }
+
+ //----- build the mapping to Unicode -----
+
+ // pass 1: use the name-to-Unicode mapping table
+ missing = hex = gFalse;
+ GBool isZapfDingbats = name && name->endsWith("ZapfDingbats");
+ for (code = 0; code < 256; ++code) {
+ if ((charName = enc[code])) {
+ if (isZapfDingbats) {
+ // include ZapfDingbats names
+ toUnicode[code] = globalParams->mapNameToUnicodeAll(charName);
+ } else {
+ toUnicode[code] = globalParams->mapNameToUnicodeText(charName);
+ }
+ if (!toUnicode[code] && strcmp(charName, ".notdef")) {
+ // if it wasn't in the name-to-Unicode table, check for a
+ // name that looks like 'Axx' or 'xx', where 'A' is any letter
+ // and 'xx' is two hex digits
+ if ((strlen(charName) == 3 &&
+ isalpha(charName[0]) &&
+ isxdigit(charName[1]) && isxdigit(charName[2]) &&
+ ((charName[1] >= 'a' && charName[1] <= 'f') ||
+ (charName[1] >= 'A' && charName[1] <= 'F') ||
+ (charName[2] >= 'a' && charName[2] <= 'f') ||
+ (charName[2] >= 'A' && charName[2] <= 'F'))) ||
+ (strlen(charName) == 2 &&
+ isxdigit(charName[0]) && isxdigit(charName[1]) &&
+ // Only check idx 1 to avoid misidentifying a decimal
+ // number like a0
+ ((charName[1] >= 'a' && charName[1] <= 'f') ||
+ (charName[1] >= 'A' && charName[1] <= 'F')))) {
+ hex = gTrue;
+ }
+ missing = gTrue;
+ }
+ } else {
+ toUnicode[code] = 0;
+ }
+ }
+
+ numeric = testForNumericNames(fontDict, hex);
+
+ // construct the char code -> Unicode mapping object
+ ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
+
+ // pass 1a: Expand ligatures in the Alphabetic Presentation Form
+ // block (eg "fi", "ffi") to normal form
+ for (code = 0; code < 256; ++code) {
+ if (unicodeIsAlphabeticPresentationForm(toUnicode[code])) {
+ Unicode *normalized = unicodeNormalizeNFKC(&toUnicode[code], 1, &len, NULL);
+ if (len > 1)
+ ctu->setMapping((CharCode)code, normalized, len);
+ gfree(normalized);
+ }
+ }
+
+ // pass 2: try to fill in the missing chars, looking for ligatures, numeric
+ // references and variants
+ if (missing) {
+ for (code = 0; code < 256; ++code) {
+ if (!toUnicode[code]) {
+ if ((charName = enc[code]) && strcmp(charName, ".notdef")
+ && (n = parseCharName(charName, uBuf, sizeof(uBuf)/sizeof(*uBuf),
+ gFalse, // don't check simple names (pass 1)
+ gTrue, // do check ligatures
+ numeric,
+ hex,
+ gTrue))) { // do check variants
+ ctu->setMapping((CharCode)code, uBuf, n);
+ continue;
+ }
+
+ // if the 'mapUnknownCharNames' flag is set, do a simple pass-through
+ // mapping for unknown character names
+ if (globalParams->getMapUnknownCharNames()) {
+ uBuf[0] = code;
+ ctu->setMapping((CharCode)code, uBuf, 1);
+ }
+ }
+ }
+ }
+
+ // merge in a ToUnicode CMap, if there is one -- this overwrites
+ // existing entries in ctu, i.e., the ToUnicode CMap takes
+ // precedence, but the other encoding info is allowed to fill in any
+ // holes
+ readToUnicodeCMap(fontDict, 16, ctu);
+
+ // look for a Unicode-to-Unicode mapping
+ if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
+ Unicode *uAux;
+ for (i = 0; i < 256; ++i) {
+ toUnicode[i] = 0;
+ }
+ ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode);
+ for (i = 0; i < 256; ++i) {
+ n = ctu->mapToUnicode((CharCode)i, &uAux);
+ if (n >= 1) {
+ n = utu->mapToUnicode((CharCode)uAux[0], &uAux);
+ if (n >= 1) {
+ ctu2->setMapping((CharCode)i, uAux, n);
+ }
+ }
+ }
+ utu->decRefCnt();
+ delete ctu;
+ ctu = ctu2;
+ }
+
+ //----- get the character widths -----
+
+ // initialize all widths
+ for (code = 0; code < 256; ++code) {
+ widths[code] = missingWidth * 0.001;
+ }
+
+ // use widths from font dict, if present
+ fontDict->lookup("FirstChar", &obj1);
+ firstChar = obj1.isInt() ? obj1.getInt() : 0;
+ obj1.free();
+ if (firstChar < 0 || firstChar > 255) {
+ firstChar = 0;
+ }
+ fontDict->lookup("LastChar", &obj1);
+ lastChar = obj1.isInt() ? obj1.getInt() : 255;
+ obj1.free();
+ if (lastChar < 0 || lastChar > 255) {
+ lastChar = 255;
+ }
+ mul = (type == fontType3) ? fontMat[0] : 0.001;
+ fontDict->lookup("Widths", &obj1);
+ if (obj1.isArray()) {
+ flags |= fontFixedWidth;
+ if (obj1.arrayGetLength() < lastChar - firstChar + 1) {
+ lastChar = firstChar + obj1.arrayGetLength() - 1;
+ }
+ for (code = firstChar; code <= lastChar; ++code) {
+ obj1.arrayGet(code - firstChar, &obj2);
+ if (obj2.isNum()) {
+ widths[code] = obj2.getNum() * mul;
+ if (fabs(widths[code] - widths[firstChar]) > 0.00001) {
+ flags &= ~fontFixedWidth;
+ }
+ }
+ obj2.free();
+ }
+
+ // use widths from built-in font
+ } else if (builtinFont) {
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (builtinFont->widths->getWidth("space", &w)) {
+ widths[32] = 0.001 * w;
+ }
+ for (code = 0; code < 256; ++code) {
+ if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
+ widths[code] = 0.001 * w;
+ }
+ }
+
+ // couldn't find widths -- use defaults
+ } else {
+ // this is technically an error -- the Widths entry is required
+ // for all but the Base-14 fonts -- but certain PDF generators
+ // apparently don't include widths for Arial and TimesNewRoman
+ if (isFixedWidth()) {
+ i = 0;
+ } else if (isSerif()) {
+ i = 8;
+ } else {
+ i = 4;
+ }
+ if (isBold()) {
+ i += 2;
+ }
+ if (isItalic()) {
+ i += 1;
+ }
+ builtinFont = builtinFontSubst[i];
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (builtinFont->widths->getWidth("space", &w)) {
+ widths[32] = 0.001 * w;
+ }
+ for (code = 0; code < 256; ++code) {
+ if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
+ widths[code] = 0.001 * w;
+ }
+ }
+ }
+ obj1.free();
+
+ ok = gTrue;
+}
+
+Gfx8BitFont::~Gfx8BitFont() {
+ int i;
+
+ for (i = 0; i < 256; ++i) {
+ if (encFree[i] && enc[i]) {
+ gfree(enc[i]);
+ }
+ }
+ ctu->decRefCnt();
+ if (charProcs.isDict()) {
+ charProcs.free();
+ }
+ if (resources.isDict()) {
+ resources.free();
+ }
+}
+
+// This function is in part a derived work of the Adobe Glyph Mapping
+// Convention: http://www.adobe.com/devnet/opentype/archives/glyph.html
+// Algorithmic comments are excerpted from that document to aid
+// maintainability.
+static int parseCharName(char *charName, Unicode *uBuf, int uLen,
+ GBool names, GBool ligatures,
+ GBool numeric, GBool hex, GBool variants)
+{
+ if (uLen <= 0) {
+ error(errInternal, -1, "Zero-length output buffer (recursion overflow?) in "
+ "parseCharName, component \"{0:s}\"", charName);
+ return 0;
+ }
+ // Step 1: drop all the characters from the glyph name starting with the
+ // first occurrence of a period (U+002E FULL STOP), if any.
+ if (variants) {
+ char *var_part = strchr(charName, '.');
+ if (var_part == charName) {
+ return 0; // .notdef or similar
+ } else if (var_part != NULL) {
+ // parse names of the form 7.oldstyle, P.swash, s.sc, etc.
+ char *main_part = gstrndup(charName, var_part - charName);
+ GBool namesRecurse = gTrue, variantsRecurse = gFalse;
+ int n = parseCharName(main_part, uBuf, uLen, namesRecurse, ligatures,
+ numeric, hex, variantsRecurse);
+ gfree(main_part);
+ return n;
+ }
+ }
+ // Step 2: split the remaining string into a sequence of components, using
+ // underscore (U+005F LOW LINE) as the delimiter.
+ if (ligatures && strchr(charName, '_')) {
+ // parse names of the form A_a (e.g. f_i, T_h, l_quotesingle)
+ char *lig_part, *lig_end, *lig_copy;
+ int n = 0, m;
+ lig_part = lig_copy = copyString(charName);
+ do {
+ if ((lig_end = strchr(lig_part, '_')))
+ *lig_end = '\0';
+ if (lig_part[0] != '\0') {
+ GBool namesRecurse = gTrue, ligaturesRecurse = gFalse;
+ if ((m = parseCharName(lig_part, uBuf + n, uLen - n, namesRecurse,
+ ligaturesRecurse, numeric, hex, variants)))
+ n += m;
+ else
+ error(errSyntaxWarning, -1, "Could not parse ligature component \"{0:s}\" of \"{1:s}\" in "
+ "parseCharName", lig_part, charName);
+ }
+ lig_part = lig_end + 1;
+ } while (lig_end && n < uLen);
+ gfree(lig_copy);
+ return n;
+ }
+ // Step 3: map each component to a character string according to the
+ // procedure below, and concatenate those strings; the result is the
+ // character string to which the glyph name is mapped.
+ // 3.1. if the font is Zapf Dingbats (PostScript FontName ZapfDingbats), and
+ // the component is in the ZapfDingbats list, then map it to the
+ // corresponding character in that list.
+ // 3.2. otherwise, if the component is in the Adobe Glyph List, then map it
+ // to the corresponding character in that list.
+ if (names && (uBuf[0] = globalParams->mapNameToUnicodeText(charName))) {
+ return 1;
+ }
+ if (globalParams->getMapNumericCharNames()) {
+ unsigned int n = strlen(charName);
+ // 3.3. otherwise, if the component is of the form "uni" (U+0075 U+006E
+ // U+0069) followed by a sequence of uppercase hexadecimal digits (0 .. 9,
+ // A .. F, i.e. U+0030 .. U+0039, U+0041 .. U+0046), the length of that
+ // sequence is a multiple of four, and each group of four digits represents
+ // a number in the set {0x0000 .. 0xD7FF, 0xE000 .. 0xFFFF}, then interpret
+ // each such number as a Unicode scalar value and map the component to the
+ // string made of those scalar values. Note that the range and digit length
+ // restrictions mean that the "uni" prefix can be used only with Unicode
+ // values from the Basic Multilingual Plane (BMP).
+ if (n >= 7 && (n % 4) == 3 && !strncmp(charName, "uni", 3)) {
+ int i;
+ unsigned int m;
+ for (i = 0, m = 3; i < uLen && m < n; m += 4) {
+ if (isxdigit(charName[m]) && isxdigit(charName[m + 1]) &&
+ isxdigit(charName[m + 2]) && isxdigit(charName[m + 3])) {
+ unsigned int u;
+ sscanf(charName + m, "%4x", &u);
+ if (u <= 0xD7FF || (0xE000 <= u && u <= 0xFFFF)) {
+ uBuf[i++] = u;
+ }
+ }
+ }
+ return i;
+ }
+ // 3.4. otherwise, if the component is of the form "u" (U+0075) followed by
+ // a sequence of four to six uppercase hexadecimal digits {0 .. 9, A .. F}
+ // (U+0030 .. U+0039, U+0041 .. U+0046), and those digits represent a
+ // number in {0x0000 .. 0xD7FF, 0xE000 .. 0x10FFFF}, then interpret this
+ // number as a Unicode scalar value and map the component to the string
+ // made of this scalar value.
+ if (n >= 5 && n <= 7 && charName[0] == 'u' && isxdigit(charName[1]) &&
+ isxdigit(charName[2]) && isxdigit(charName[3]) && isxdigit(charName[4])
+ && (n <= 5 || isxdigit(charName[5]))
+ && (n <= 6 || isxdigit(charName[6]))) {
+ unsigned int u;
+ sscanf(charName + 1, "%x", &u);
+ if (u <= 0xD7FF || (0xE000 <= u && u <= 0x10FFFF)) {
+ uBuf[0] = u;
+ return 1;
+ }
+ }
+ // Not in Adobe Glyph Mapping convention: look for names like xx
+ // or Axx and parse for hex or decimal values.
+ if (numeric && parseNumericName(charName, hex, uBuf))
+ return 1;
+ }
+ // 3.5. otherwise, map the component to the empty string
+ return 0;
+}
+
+int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code,
+ Unicode **u, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) {
+ CharCode c;
+
+ *code = c = (CharCode)(*s & 0xff);
+ *uLen = ctu->mapToUnicode(c, u);
+ *dx = widths[c];
+ *dy = *ox = *oy = 0;
+ return 1;
+}
+
+CharCodeToUnicode *Gfx8BitFont::getToUnicode() {
+ ctu->incRefCnt();
+ return ctu;
+}
+
+int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
+ int *map;
+ int cmapPlatform, cmapEncoding;
+ int unicodeCmap, macRomanCmap, msSymbolCmap, cmap;
+ GBool useMacRoman, useUnicode;
+ char *charName;
+ Unicode u;
+ int code, i, n;
+
+ map = (int *)gmallocn(256, sizeof(int));
+ for (i = 0; i < 256; ++i) {
+ map[i] = 0;
+ }
+
+ // To match up with the Adobe-defined behaviour, we choose a cmap
+ // like this:
+ // 1. If the PDF font has an encoding:
+ // 1a. If the PDF font specified MacRomanEncoding and the
+ // TrueType font has a Macintosh Roman cmap, use it, and
+ // reverse map the char names through MacRomanEncoding to
+ // get char codes.
+ // 1b. If the PDF font is not symbolic or the PDF font is not
+ // embedded, and the TrueType font has a Microsoft Unicode
+ // cmap or a non-Microsoft Unicode cmap, use it, and use the
+ // Unicode indexes, not the char codes.
+ // 1c. If the PDF font is symbolic and the TrueType font has a
+ // Microsoft Symbol cmap, use it, and use char codes
+ // directly (possibly with an offset of 0xf000).
+ // 1d. If the TrueType font has a Macintosh Roman cmap, use it,
+ // as in case 1a.
+ // 2. If the PDF font does not have an encoding or the PDF font is
+ // symbolic:
+ // 2a. If the TrueType font has a Macintosh Roman cmap, use it,
+ // and use char codes directly (possibly with an offset of
+ // 0xf000).
+ // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
+ // and use char codes directly (possible with an offset of
+ // 0xf000).
+ // 3. If none of these rules apply, use the first cmap and hope for
+ // the best (this shouldn't happen).
+ unicodeCmap = macRomanCmap = msSymbolCmap = -1;
+ for (i = 0; i < ff->getNumCmaps(); ++i) {
+ cmapPlatform = ff->getCmapPlatform(i);
+ cmapEncoding = ff->getCmapEncoding(i);
+ if ((cmapPlatform == 3 && cmapEncoding == 1) ||
+ cmapPlatform == 0) {
+ unicodeCmap = i;
+ } else if (cmapPlatform == 1 && cmapEncoding == 0) {
+ macRomanCmap = i;
+ } else if (cmapPlatform == 3 && cmapEncoding == 0) {
+ msSymbolCmap = i;
+ }
+ }
+ cmap = 0;
+ useMacRoman = gFalse;
+ useUnicode = gFalse;
+ if (hasEncoding || type == fontType1) {
+ if (usesMacRomanEnc && macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ useMacRoman = gTrue;
+ } else if ((!(flags & fontSymbolic) || embFontID.num < 0) &&
+ unicodeCmap >= 0) {
+ cmap = unicodeCmap;
+ useUnicode = gTrue;
+ } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
+ cmap = msSymbolCmap;
+ } else if ((flags & fontSymbolic) && macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ } else if (macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ useMacRoman = gTrue;
+ }
+ } else {
+ if (msSymbolCmap >= 0) {
+ cmap = msSymbolCmap;
+ } else if (macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ }
+ }
+
+ // reverse map the char names through MacRomanEncoding, then map the
+ // char codes through the cmap
+ if (useMacRoman) {
+ for (i = 0; i < 256; ++i) {
+ if ((charName = enc[i])) {
+ if ((code = globalParams->getMacRomanCharCode(charName))) {
+ map[i] = ff->mapCodeToGID(cmap, code);
+ }
+ } else {
+ map[i] = -1;
+ }
+ }
+
+ // map Unicode through the cmap
+ } else if (useUnicode) {
+ Unicode *uAux;
+ for (i = 0; i < 256; ++i) {
+ if (((charName = enc[i]) && (u = globalParams->mapNameToUnicodeAll(charName))))
+ map[i] = ff->mapCodeToGID(cmap, u);
+ else
+ {
+ n = ctu->mapToUnicode((CharCode)i, &uAux);
+ if (n > 0) map[i] = ff->mapCodeToGID(cmap, uAux[0]);
+ else map[i] = -1;
+ }
+ }
+
+ // map the char codes through the cmap, possibly with an offset of
+ // 0xf000
+ } else {
+ for (i = 0; i < 256; ++i) {
+ if (!(map[i] = ff->mapCodeToGID(cmap, i))) {
+ map[i] = ff->mapCodeToGID(cmap, 0xf000 + i);
+ }
+ }
+ }
+
+ // try the TrueType 'post' table to handle any unmapped characters
+ for (i = 0; i < 256; ++i) {
+ if (map[i] <= 0 && (charName = enc[i])) {
+ map[i] = ff->mapNameToGID(charName);
+ }
+ }
+
+ return map;
+}
+
+Dict *Gfx8BitFont::getCharProcs() {
+ return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
+}
+
+Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
+ if (enc[code] && charProcs.isDict()) {
+ charProcs.dictLookup(enc[code], proc);
+ } else {
+ proc->initNull();
+ }
+ return proc;
+}
+
+Dict *Gfx8BitFont::getResources() {
+ return resources.isDict() ? resources.getDict() : (Dict *)NULL;
+}
+
+//------------------------------------------------------------------------
+// GfxCIDFont
+//------------------------------------------------------------------------
+
+struct cmpWidthExcepFunctor {
+ bool operator()(const GfxFontCIDWidthExcep &w1,
+ const GfxFontCIDWidthExcep &w2) {
+ return w1.first < w2.first;
+ }
+};
+
+struct cmpWidthExcepVFunctor {
+ bool operator()(const GfxFontCIDWidthExcepV &w1,
+ const GfxFontCIDWidthExcepV &w2) {
+ return w1.first < w2.first;
+ }
+};
+
+GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
+ GfxFont(tagA, idA, nameA, typeA, embFontIDA)
+{
+ Dict *desFontDict;
+ Object desFontDictObj;
+ Object obj1, obj2, obj3, obj4, obj5, obj6;
+ CharCodeToUnicode *utu;
+ CharCode c;
+ Unicode *uBuf;
+ int c1, c2;
+ int excepsSize, i, j, k, n;
+
+ refCnt = 1;
+ ascent = 0.95;
+ descent = -0.35;
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+ collection = NULL;
+ cMap = NULL;
+ ctu = NULL;
+ ctuUsesCharCode = gTrue;
+ widths.defWidth = 1.0;
+ widths.defHeight = -1.0;
+ widths.defVY = 0.880;
+ widths.exceps = NULL;
+ widths.nExceps = 0;
+ widths.excepsV = NULL;
+ widths.nExcepsV = 0;
+ cidToGID = NULL;
+ cidToGIDLen = 0;
+
+ // get the descendant font
+ if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() ||
+ obj1.arrayGetLength() == 0) {
+ error(errSyntaxError, -1, "Missing or empty DescendantFonts entry in Type 0 font");
+ obj1.free();
+ goto err1;
+ }
+ if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
+ error(errSyntaxError, -1, "Bad descendant font in Type 0 font");
+ goto err3;
+ }
+ obj1.free();
+ desFontDict = desFontDictObj.getDict();
+
+ // get info from font descriptor
+ readFontDescriptor(xref, desFontDict);
+
+ //----- encoding info -----
+
+ // char collection
+ if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
+ error(errSyntaxError, -1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
+ goto err3;
+ }
+ obj1.dictLookup("Registry", &obj2);
+ obj1.dictLookup("Ordering", &obj3);
+ if (!obj2.isString() || !obj3.isString()) {
+ error(errSyntaxError, -1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
+ goto err3;
+ }
+ collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
+ obj3.free();
+ obj2.free();
+ obj1.free();
+
+ // look for a ToUnicode CMap
+ if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
+ ctuUsesCharCode = gFalse;
+
+ // use an identity mapping for the "Adobe-Identity" and
+ // "Adobe-UCS" collections
+ if (!collection->cmp("Adobe-Identity") ||
+ !collection->cmp("Adobe-UCS")) {
+ ctu = CharCodeToUnicode::makeIdentityMapping();
+ } else {
+ // look for a user-supplied .cidToUnicode file
+ if (!(ctu = globalParams->getCIDToUnicode(collection))) {
+ // I'm not completely sure that this is the best thing to do
+ // but it seems to produce better results when the .cidToUnicode
+ // files from the poppler-data package are missing. At least
+ // we know that assuming the Identity mapping is definitely wrong.
+ // -- jrmuizel
+ static const char * knownCollections [] = {
+ "Adobe-CNS1",
+ "Adobe-GB1",
+ "Adobe-Japan1",
+ "Adobe-Japan2",
+ "Adobe-Korea1",
+ };
+ for (size_t i = 0; i < sizeof(knownCollections)/sizeof(knownCollections[0]); i++) {
+ if (collection->cmp(knownCollections[i]) == 0) {
+ error(errSyntaxError, -1, "Missing language pack for '{0:t}' mapping", collection);
+ goto err2;
+ }
+ }
+ error(errSyntaxError, -1, "Unknown character collection '{0:t}'",
+ collection);
+ // fall-through, assuming the Identity mapping -- this appears
+ // to match Adobe's behavior
+ }
+ }
+ }
+
+ // look for a Unicode-to-Unicode mapping
+ if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
+ if (ctu) {
+ for (c = 0; c < ctu->getLength(); ++c) {
+ n = ctu->mapToUnicode(c, &uBuf);
+ if (n >= 1) {
+ n = utu->mapToUnicode((CharCode)uBuf[0], &uBuf);
+ if (n >= 1) {
+ ctu->setMapping(c, uBuf, n);
+ }
+ }
+ }
+ utu->decRefCnt();
+ } else {
+ ctu = utu;
+ }
+ }
+
+ // encoding (i.e., CMap)
+ if (fontDict->lookup("Encoding", &obj1)->isNull()) {
+ error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font");
+ goto err2;
+ }
+ if (!(cMap = CMap::parse(NULL, collection, &obj1))) {
+ goto err2;
+ }
+ obj1.free();
+ if (cMap->getCMapName()) {
+ encodingName->Set(cMap->getCMapName()->getCString());
+ } else {
+ encodingName->Set("Custom");
+ }
+
+ // CIDToGIDMap (for embedded TrueType fonts)
+ if (type == fontCIDType2 || type == fontCIDType2OT) {
+ desFontDict->lookup("CIDToGIDMap", &obj1);
+ if (obj1.isStream()) {
+ cidToGIDLen = 0;
+ i = 64;
+ cidToGID = (int *)gmallocn(i, sizeof(int));
+ obj1.streamReset();
+ while ((c1 = obj1.streamGetChar()) != EOF &&
+ (c2 = obj1.streamGetChar()) != EOF) {
+ if (cidToGIDLen == i) {
+ i *= 2;
+ cidToGID = (int *)greallocn(cidToGID, i, sizeof(int));
+ }
+ cidToGID[cidToGIDLen++] = (c1 << 8) + c2;
+ }
+ } else if (!obj1.isName("Identity") && !obj1.isNull()) {
+ error(errSyntaxError, -1, "Invalid CIDToGIDMap entry in CID font");
+ }
+ obj1.free();
+ }
+
+ //----- character metrics -----
+
+ // default char width
+ if (desFontDict->lookup("DW", &obj1)->isInt()) {
+ widths.defWidth = obj1.getInt() * 0.001;
+ }
+ obj1.free();
+
+ // char width exceptions
+ if (desFontDict->lookup("W", &obj1)->isArray()) {
+ excepsSize = 0;
+ i = 0;
+ while (i + 1 < obj1.arrayGetLength()) {
+ obj1.arrayGet(i, &obj2);
+ obj1.arrayGet(i + 1, &obj3);
+ if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
+ if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
+ if (widths.nExceps == excepsSize) {
+ excepsSize += 16;
+ widths.exceps = (GfxFontCIDWidthExcep *)
+ greallocn(widths.exceps,
+ excepsSize, sizeof(GfxFontCIDWidthExcep));
+ }
+ widths.exceps[widths.nExceps].first = obj2.getInt();
+ widths.exceps[widths.nExceps].last = obj3.getInt();
+ widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
+ ++widths.nExceps;
+ } else {
+ error(errSyntaxError, -1, "Bad widths array in Type 0 font");
+ }
+ obj4.free();
+ i += 3;
+ } else if (obj2.isInt() && obj3.isArray()) {
+ if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
+ excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
+ widths.exceps = (GfxFontCIDWidthExcep *)
+ greallocn(widths.exceps,
+ excepsSize, sizeof(GfxFontCIDWidthExcep));
+ }
+ j = obj2.getInt();
+ for (k = 0; k < obj3.arrayGetLength(); ++k) {
+ if (obj3.arrayGet(k, &obj4)->isNum()) {
+ widths.exceps[widths.nExceps].first = j;
+ widths.exceps[widths.nExceps].last = j;
+ widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
+ ++j;
+ ++widths.nExceps;
+ } else {
+ error(errSyntaxError, -1, "Bad widths array in Type 0 font");
+ }
+ obj4.free();
+ }
+ i += 2;
+ } else {
+ error(errSyntaxError, -1, "Bad widths array in Type 0 font");
+ ++i;
+ }
+ obj3.free();
+ obj2.free();
+ }
+ std::sort(widths.exceps, widths.exceps + widths.nExceps,
+ cmpWidthExcepFunctor());
+ }
+ obj1.free();
+
+ // default metrics for vertical font
+ if (desFontDict->lookup("DW2", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ if (obj1.arrayGet(0, &obj2)->isNum()) {
+ widths.defVY = obj2.getNum() * 0.001;
+ }
+ obj2.free();
+ if (obj1.arrayGet(1, &obj2)->isNum()) {
+ widths.defHeight = obj2.getNum() * 0.001;
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ // char metric exceptions for vertical font
+ if (desFontDict->lookup("W2", &obj1)->isArray()) {
+ excepsSize = 0;
+ i = 0;
+ while (i + 1 < obj1.arrayGetLength()) {
+ obj1.arrayGet(i, &obj2);
+ obj1.arrayGet(i+ 1, &obj3);
+ if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
+ if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
+ obj1.arrayGet(i + 3, &obj5)->isNum() &&
+ obj1.arrayGet(i + 4, &obj6)->isNum()) {
+ if (widths.nExcepsV == excepsSize) {
+ excepsSize += 16;
+ widths.excepsV = (GfxFontCIDWidthExcepV *)
+ greallocn(widths.excepsV,
+ excepsSize, sizeof(GfxFontCIDWidthExcepV));
+ }
+ widths.excepsV[widths.nExcepsV].first = obj2.getInt();
+ widths.excepsV[widths.nExcepsV].last = obj3.getInt();
+ widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
+ widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
+ widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
+ ++widths.nExcepsV;
+ } else {
+ error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
+ }
+ obj6.free();
+ obj5.free();
+ obj4.free();
+ i += 5;
+ } else if (obj2.isInt() && obj3.isArray()) {
+ if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
+ excepsSize =
+ (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
+ widths.excepsV = (GfxFontCIDWidthExcepV *)
+ greallocn(widths.excepsV,
+ excepsSize, sizeof(GfxFontCIDWidthExcepV));
+ }
+ j = obj2.getInt();
+ for (k = 0; k < obj3.arrayGetLength(); k += 3) {
+ if (obj3.arrayGet(k, &obj4)->isNum() &&
+ obj3.arrayGet(k+1, &obj5)->isNum() &&
+ obj3.arrayGet(k+2, &obj6)->isNum()) {
+ widths.excepsV[widths.nExcepsV].first = j;
+ widths.excepsV[widths.nExcepsV].last = j;
+ widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
+ widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
+ widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
+ ++j;
+ ++widths.nExcepsV;
+ } else {
+ error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
+ }
+ obj6.free();
+ obj5.free();
+ obj4.free();
+ }
+ i += 2;
+ } else {
+ error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
+ ++i;
+ }
+ obj3.free();
+ obj2.free();
+ }
+ std::sort(widths.excepsV, widths.excepsV + widths.nExcepsV,
+ cmpWidthExcepVFunctor());
+ }
+ obj1.free();
+
+ desFontDictObj.free();
+ ok = gTrue;
+ return;
+
+ err3:
+ obj3.free();
+ obj2.free();
+ err2:
+ obj1.free();
+ desFontDictObj.free();
+ err1:;
+}
+
+GfxCIDFont::~GfxCIDFont() {
+ if (collection) {
+ delete collection;
+ }
+ if (cMap) {
+ cMap->decRefCnt();
+ }
+ if (ctu) {
+ ctu->decRefCnt();
+ }
+ gfree(widths.exceps);
+ gfree(widths.excepsV);
+ if (cidToGID) {
+ gfree(cidToGID);
+ }
+}
+
+int GfxCIDFont::getNextChar(char *s, int len, CharCode *code,
+ Unicode **u, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) {
+ CID cid;
+ CharCode c;
+ double w, h, vx, vy;
+ int n, a, b, m;
+
+ if (!cMap) {
+ *code = 0;
+ *uLen = 0;
+ *dx = *dy = 0;
+ return 1;
+ }
+
+ *code = (CharCode)(cid = cMap->getCID(s, len, &c, &n));
+ if (ctu) {
+ if (hasToUnicode) {
+ int i = 0, c = 0;
+ while (i < n) {
+ c = (c << 8 ) + (s[i] & 0xff);
+ ++i;
+ }
+ *uLen = ctu->mapToUnicode(c, u);
+ } else {
+ *uLen = ctu->mapToUnicode(cid, u);
+ }
+ } else {
+ *uLen = 0;
+ }
+
+ // horizontal
+ if (cMap->getWMode() == 0) {
+ w = getWidth(cid);
+ h = vx = vy = 0;
+
+ // vertical
+ } else {
+ w = 0;
+ h = widths.defHeight;
+ vx = getWidth(cid) / 2;
+ vy = widths.defVY;
+ if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) {
+ a = 0;
+ b = widths.nExcepsV;
+ // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths.excepsV[m].last <= cid) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (cid <= widths.excepsV[a].last) {
+ h = widths.excepsV[a].height;
+ vx = widths.excepsV[a].vx;
+ vy = widths.excepsV[a].vy;
+ }
+ }
+ }
+
+ *dx = w;
+ *dy = h;
+ *ox = vx;
+ *oy = vy;
+
+ return n;
+}
+
+int GfxCIDFont::getWMode() {
+ return cMap ? cMap->getWMode() : 0;
+}
+
+CharCodeToUnicode *GfxCIDFont::getToUnicode() {
+ if (ctu) {
+ ctu->incRefCnt();
+ }
+ return ctu;
+}
+
+GooString *GfxCIDFont::getCollection() {
+ return cMap ? cMap->getCollection() : (GooString *)NULL;
+}
+
+int GfxCIDFont::mapCodeToGID(FoFiTrueType *ff, int cmapi,
+ Unicode unicode, GBool wmode) {
+ Gushort gid = ff->mapCodeToGID(cmapi,unicode);
+ if (wmode) {
+ Gushort vgid = ff->mapToVertGID(gid);
+ if (vgid != 0) gid = vgid;
+ }
+ return gid;
+}
+
+int *GfxCIDFont::getCodeToGIDMap(FoFiTrueType *ff, int *mapsizep) {
+#define N_UCS_CANDIDATES 2
+ /* space characters */
+ static const unsigned long spaces[] = {
+ 0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007,
+ 0x2008,0x2009,0x200A,0x00A0,0x200B,0x2060,0x3000,0xFEFF,
+ 0
+ };
+ static const char *adobe_cns1_cmaps[] = {
+ "UniCNS-UTF32-V",
+ "UniCNS-UCS2-V",
+ "UniCNS-UTF32-H",
+ "UniCNS-UCS2-H",
+ 0
+ };
+ static const char *adobe_gb1_cmaps[] = {
+ "UniGB-UTF32-V",
+ "UniGB-UCS2-V",
+ "UniGB-UTF32-H",
+ "UniGB-UCS2-H",
+ 0
+ };
+ static const char *adobe_japan1_cmaps[] = {
+ "UniJIS-UTF32-V",
+ "UniJIS-UCS2-V",
+ "UniJIS-UTF32-H",
+ "UniJIS-UCS2-H",
+ 0
+ };
+ static const char *adobe_japan2_cmaps[] = {
+ "UniHojo-UTF32-V",
+ "UniHojo-UCS2-V",
+ "UniHojo-UTF32-H",
+ "UniHojo-UCS2-H",
+ 0
+ };
+ static const char *adobe_korea1_cmaps[] = {
+ "UniKS-UTF32-V",
+ "UniKS-UCS2-V",
+ "UniKS-UTF32-H",
+ "UniKS-UCS2-H",
+ 0
+ };
+ static struct CMapListEntry {
+ const char *collection;
+ const char *scriptTag;
+ const char *languageTag;
+ const char *toUnicodeMap;
+ const char **CMaps;
+ } CMapList[] = {
+ {
+ "Adobe-CNS1",
+ "hani", "CHN ",
+ "Adobe-CNS1-UCS2",
+ adobe_cns1_cmaps,
+ },
+ {
+ "Adobe-GB1",
+ "hani", "CHN ",
+ "Adobe-GB1-UCS2",
+ adobe_gb1_cmaps,
+ },
+ {
+ "Adobe-Japan1",
+ "kana", "JAN ",
+ "Adobe-Japan1-UCS2",
+ adobe_japan1_cmaps,
+ },
+ {
+ "Adobe-Japan2",
+ "kana", "JAN ",
+ "Adobe-Japan2-UCS2",
+ adobe_japan2_cmaps,
+ },
+ {
+ "Adobe-Korea1",
+ "hang", "KOR ",
+ "Adobe-Korea1-UCS2",
+ adobe_korea1_cmaps,
+ },
+ {0, 0, 0, 0}
+ };
+ Unicode *humap = 0;
+ Unicode *vumap = 0;
+ Unicode *tumap = 0;
+ int *codeToGID = 0;
+ unsigned long n;
+ int i;
+ unsigned long code;
+ int wmode;
+ const char **cmapName;
+ CMap *cMap;
+ CMapListEntry *lp;
+ int cmap;
+ int cmapPlatform, cmapEncoding;
+ Ref embID;
+
+ *mapsizep = 0;
+ if (!ctu) return NULL;
+ if (getCollection()->cmp("Adobe-Identity") == 0) return NULL;
+ if (getEmbeddedFontID(&embID)) {
+ /* if this font is embedded font,
+ * CIDToGIDMap should be embedded in PDF file
+ * and already set. So return it.
+ */
+ *mapsizep = getCIDToGIDLen();
+ return getCIDToGID();
+ }
+
+ /* we use only unicode cmap */
+ cmap = -1;
+ for (i = 0; i < ff->getNumCmaps(); ++i) {
+ cmapPlatform = ff->getCmapPlatform(i);
+ cmapEncoding = ff->getCmapEncoding(i);
+ if (cmapPlatform == 3 && cmapEncoding == 10) {
+ /* UCS-4 */
+ cmap = i;
+ /* use UCS-4 cmap */
+ break;
+ } else if (cmapPlatform == 3 && cmapEncoding == 1) {
+ /* Unicode */
+ cmap = i;
+ } else if (cmapPlatform == 0 && cmap < 0) {
+ cmap = i;
+ }
+ }
+ if (cmap < 0)
+ return NULL;
+
+ wmode = getWMode();
+ for (lp = CMapList;lp->collection != 0;lp++) {
+ if (strcmp(lp->collection,getCollection()->getCString()) == 0) {
+ break;
+ }
+ }
+ n = 65536;
+ tumap = new Unicode[n];
+ humap = new Unicode[n*N_UCS_CANDIDATES];
+ memset(humap,0,sizeof(Unicode)*n*N_UCS_CANDIDATES);
+ if (lp->collection != 0) {
+ CharCodeToUnicode *tctu;
+ GooString tname(lp->toUnicodeMap);
+
+ if ((tctu = CharCodeToUnicode::parseCMapFromFile(&tname,16)) != 0) {
+ CharCode cid;
+ for (cid = 0;cid < n ;cid++) {
+ int len;
+ Unicode *ucodes;
+
+ len = tctu->mapToUnicode(cid,&ucodes);
+ if (len == 1) {
+ tumap[cid] = ucodes[0];
+ } else {
+ /* if not single character, ignore it */
+ tumap[cid] = 0;
+ }
+ }
+ delete tctu;
+ }
+ vumap = new Unicode[n];
+ memset(vumap,0,sizeof(Unicode)*n);
+ for (cmapName = lp->CMaps;*cmapName != 0;cmapName++) {
+ GooString cname(*cmapName);
+
+ if ((cMap = globalParams->getCMap(getCollection(),&cname))
+ != 0) {
+ if (cMap->getWMode()) {
+ cMap->setReverseMap(vumap,n,1);
+ } else {
+ cMap->setReverseMap(humap,n,N_UCS_CANDIDATES);
+ }
+ cMap->decRefCnt();
+ }
+ }
+ ff->setupGSUB(lp->scriptTag, lp->languageTag);
+ } else {
+ error(errSyntaxError, -1, "Unknown character collection {0:t}\n",
+ getCollection());
+ if ((ctu = getToUnicode()) != 0) {
+ CharCode cid;
+ for (cid = 0;cid < n ;cid++) {
+ Unicode *ucode;
+
+ if (ctu->mapToUnicode(cid, &ucode))
+ humap[cid*N_UCS_CANDIDATES] = ucode[0];
+ else
+ humap[cid*N_UCS_CANDIDATES] = 0;
+ for (i = 1;i < N_UCS_CANDIDATES;i++) {
+ humap[cid*N_UCS_CANDIDATES+i] = 0;
+ }
+ }
+ ctu->decRefCnt();
+ }
+ }
+ // map CID -> Unicode -> GID
+ codeToGID = (int *)gmallocn(n, sizeof(int));
+ for (code = 0; code < n; ++code) {
+ Unicode unicode;
+ unsigned long gid;
+
+ unicode = 0;
+ gid = 0;
+ if (humap != 0) {
+ for (i = 0;i < N_UCS_CANDIDATES
+ && gid == 0 && (unicode = humap[code*N_UCS_CANDIDATES+i]) != 0;i++) {
+ gid = mapCodeToGID(ff,cmap,unicode,gFalse);
+ }
+ }
+ if (gid == 0 && vumap != 0) {
+ unicode = vumap[code];
+ if (unicode != 0) {
+ gid = mapCodeToGID(ff,cmap,unicode,gTrue);
+ if (gid == 0 && tumap != 0) {
+ if ((unicode = tumap[code]) != 0) {
+ gid = mapCodeToGID(ff,cmap,unicode,gTrue);
+ }
+ }
+ }
+ }
+ if (gid == 0 && tumap != 0) {
+ if ((unicode = tumap[code]) != 0) {
+ gid = mapCodeToGID(ff,cmap,unicode,gFalse);
+ }
+ }
+ if (gid == 0) {
+ /* special handling space characters */
+ const unsigned long *p;
+
+ if (humap != 0) unicode = humap[code];
+ if (unicode != 0) {
+ /* check if code is space character , so map code to 0x0020 */
+ for (p = spaces;*p != 0;p++) {
+ if (*p == unicode) {
+ unicode = 0x20;
+ gid = mapCodeToGID(ff,cmap,unicode,wmode);
+ break;
+ }
+ }
+ }
+ }
+ codeToGID[code] = gid;
+ }
+ *mapsizep = n;
+ if (humap != 0) delete[] humap;
+ if (tumap != 0) delete[] tumap;
+ if (vumap != 0) delete[] vumap;
+ return codeToGID;
+}
+
+double GfxCIDFont::getWidth(CID cid) {
+ double w;
+ int a, b, m;
+
+ w = widths.defWidth;
+ if (widths.nExceps > 0 && cid >= widths.exceps[0].first) {
+ a = 0;
+ b = widths.nExceps;
+ // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths.exceps[m].first <= cid) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (cid <= widths.exceps[a].last) {
+ w = widths.exceps[a].width;
+ }
+ }
+ return w;
+}
+
+double GfxCIDFont::getWidth (char* s, int len) {
+ int nUsed;
+ CharCode c;
+
+ CID cid = cMap->getCID(s, len, &c, &nUsed);
+ return getWidth(cid);
+}
+
+//------------------------------------------------------------------------
+// GfxFontDict
+//------------------------------------------------------------------------
+
+GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
+ int i;
+ Object obj1, obj2;
+ Ref r;
+
+ numFonts = fontDict->getLength();
+ fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *));
+ for (i = 0; i < numFonts; ++i) {
+ fontDict->getValNF(i, &obj1);
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ if (obj1.isRef()) {
+ r = obj1.getRef();
+ } else {
+ // no indirect reference for this font, so invent a unique one
+ // (legal generation numbers are five digits, so any 6-digit
+ // number would be safe)
+ r.num = i;
+ if (fontDictRef) {
+ r.gen = 100000 + fontDictRef->num;
+ } else {
+ r.gen = 999999;
+ }
+ }
+ fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i),
+ r, obj2.getDict());
+ if (fonts[i] && !fonts[i]->isOk()) {
+ // XXX: it may be meaningful to distinguish between
+ // NULL and !isOk() so that when we do lookups
+ // we can tell the difference between a missing font
+ // and a font that is just !isOk()
+ fonts[i]->decRefCnt();
+ fonts[i] = NULL;
+ }
+ } else {
+ error(errSyntaxError, -1, "font resource is not a dictionary");
+ fonts[i] = NULL;
+ }
+ obj1.free();
+ obj2.free();
+ }
+}
+
+GfxFontDict::~GfxFontDict() {
+ int i;
+
+ for (i = 0; i < numFonts; ++i) {
+ if (fonts[i]) {
+ fonts[i]->decRefCnt();
+ }
+ }
+ gfree(fonts);
+}
+
+GfxFont *GfxFontDict::lookup(char *tag) {
+ int i;
+
+ for (i = 0; i < numFonts; ++i) {
+ if (fonts[i] && fonts[i]->matches(tag)) {
+ return fonts[i];
+ }
+ }
+ return NULL;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxFont.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxFont.h
new file mode 100644
index 00000000000..febb902922d
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxFont.h
@@ -0,0 +1,444 @@
+//========================================================================
+//
+// GfxFont.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2008, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2011 Axel Strübing <axel.struebing@freenet.de>
+// Copyright (C) 2011, 2012, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2015 Jason Crain <jason@aquaticape.us>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef GFXFONT_H
+#define GFXFONT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "goo/GooString.h"
+#include "Object.h"
+#include "CharTypes.h"
+
+class Dict;
+class CMap;
+class CharCodeToUnicode;
+class FoFiTrueType;
+class PSOutputDev;
+struct GfxFontCIDWidths;
+struct Base14FontMapEntry;
+
+//------------------------------------------------------------------------
+// GfxFontType
+//------------------------------------------------------------------------
+
+enum GfxFontType {
+ //----- Gfx8BitFont
+ fontUnknownType,
+ fontType1,
+ fontType1C,
+ fontType1COT,
+ fontType3,
+ fontTrueType,
+ fontTrueTypeOT,
+ //----- GfxCIDFont
+ fontCIDType0,
+ fontCIDType0C,
+ fontCIDType0COT,
+ fontCIDType2,
+ fontCIDType2OT
+};
+
+//------------------------------------------------------------------------
+// GfxFontCIDWidths
+//------------------------------------------------------------------------
+
+struct GfxFontCIDWidthExcep {
+ CID first; // this record applies to
+ CID last; // CIDs <first>..<last>
+ double width; // char width
+};
+
+struct GfxFontCIDWidthExcepV {
+ CID first; // this record applies to
+ CID last; // CIDs <first>..<last>
+ double height; // char height
+ double vx, vy; // origin position
+};
+
+struct GfxFontCIDWidths {
+ double defWidth; // default char width
+ double defHeight; // default char height
+ double defVY; // default origin position
+ GfxFontCIDWidthExcep *exceps; // exceptions
+ int nExceps; // number of valid entries in exceps
+ GfxFontCIDWidthExcepV * // exceptions for vertical font
+ excepsV;
+ int nExcepsV; // number of valid entries in excepsV
+};
+
+//------------------------------------------------------------------------
+// GfxFontLoc
+//------------------------------------------------------------------------
+
+enum GfxFontLocType {
+ gfxFontLocEmbedded, // font embedded in PDF file
+ gfxFontLocExternal, // external font file
+ gfxFontLocResident // font resident in PS printer
+};
+
+class GfxFontLoc {
+public:
+
+ GfxFontLoc();
+ ~GfxFontLoc();
+
+ GfxFontLocType locType;
+ GfxFontType fontType;
+ Ref embFontID; // embedded stream obj ID
+ // (if locType == gfxFontLocEmbedded)
+ GooString *path; // font file path
+ // (if locType == gfxFontLocExternal)
+ // PS font name
+ // (if locType == gfxFontLocResident)
+ int fontNum; // for TrueType collections
+ // (if locType == gfxFontLocExternal)
+ GooString *encoding; // PS font encoding, only for 16-bit fonts
+ // (if locType == gfxFontLocResident)
+ int wMode; // writing mode, only for 16-bit fonts
+ // (if locType == gfxFontLocResident)
+ int substIdx; // substitute font index
+ // (if locType == gfxFontLocExternal,
+ // and a Base-14 substitution was made)
+};
+
+//------------------------------------------------------------------------
+// GfxFont
+//------------------------------------------------------------------------
+
+#define fontFixedWidth (1 << 0)
+#define fontSerif (1 << 1)
+#define fontSymbolic (1 << 2)
+#define fontItalic (1 << 6)
+#define fontBold (1 << 18)
+
+class GfxFont {
+public:
+
+ enum Stretch {
+ StretchNotDefined,
+ UltraCondensed,
+ ExtraCondensed,
+ Condensed,
+ SemiCondensed,
+ Normal,
+ SemiExpanded,
+ Expanded,
+ ExtraExpanded,
+ UltraExpanded };
+
+ enum Weight {
+ WeightNotDefined,
+ W100,
+ W200,
+ W300,
+ W400, // Normal
+ W500,
+ W600,
+ W700, // Bold
+ W800,
+ W900 };
+
+ // Build a GfxFont object.
+ static GfxFont *makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict);
+
+ GfxFont(const char *tagA, Ref idA, GooString *nameA,
+ GfxFontType typeA, Ref embFontIDA);
+
+ GBool isOk() { return ok; }
+
+ void incRefCnt();
+ void decRefCnt();
+
+ // Get font tag.
+ GooString *getTag() { return tag; }
+
+ // Get font dictionary ID.
+ Ref *getID() { return &id; }
+
+ // Does this font match the tag?
+ GBool matches(char *tagA) { return !tag->cmp(tagA); }
+
+ // Get font family name.
+ GooString *getFamily() { return family; }
+
+ // Get font stretch.
+ Stretch getStretch() { return stretch; }
+
+ // Get font weight.
+ Weight getWeight() { return weight; }
+
+ // Get the original font name (ignornig any munging that might have
+ // been done to map to a canonical Base-14 font name).
+ GooString *getName() { return name; }
+
+ // Get font type.
+ GfxFontType getType() { return type; }
+ virtual GBool isCIDFont() { return gFalse; }
+
+ // Get embedded font ID, i.e., a ref for the font file stream.
+ // Returns false if there is no embedded font.
+ GBool getEmbeddedFontID(Ref *embID)
+ { *embID = embFontID; return embFontID.num >= 0; }
+
+ // Get the PostScript font name for the embedded font. Returns
+ // NULL if there is no embedded font.
+ GooString *getEmbeddedFontName() { return embFontName; }
+
+ // Get font descriptor flags.
+ int getFlags() { return flags; }
+ GBool isFixedWidth() { return flags & fontFixedWidth; }
+ GBool isSerif() { return flags & fontSerif; }
+ GBool isSymbolic() { return flags & fontSymbolic; }
+ GBool isItalic() { return flags & fontItalic; }
+ GBool isBold() { return flags & fontBold; }
+
+ // Return the Unicode map.
+ virtual CharCodeToUnicode *getToUnicode() = 0;
+
+ // Return the font matrix.
+ double *getFontMatrix() { return fontMat; }
+
+ // Return the font bounding box.
+ double *getFontBBox() { return fontBBox; }
+
+ // Return the ascent and descent values.
+ double getAscent() { return ascent; }
+ double getDescent() { return descent; }
+
+ // Return the writing mode (0=horizontal, 1=vertical).
+ virtual int getWMode() { return 0; }
+
+ // Locate the font file for this font. If <ps> is not null, includes PS
+ // printer-resident fonts. Returns NULL on failure.
+ GfxFontLoc *locateFont(XRef *xref, PSOutputDev *ps);
+
+ // Locate a Base-14 font file for a specified font name.
+ static GfxFontLoc *locateBase14Font(GooString *base14Name);
+
+ // Read an external or embedded font file into a buffer.
+ char *readEmbFontFile(XRef *xref, int *len);
+
+ // Get the next char from a string <s> of <len> bytes, returning the
+ // char <code>, its Unicode mapping <u>, its displacement vector
+ // (<dx>, <dy>), and its origin offset vector (<ox>, <oy>). <uSize>
+ // is the number of entries available in <u>, and <uLen> is set to
+ // the number actually used. Returns the number of bytes used by
+ // the char code.
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode **u, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) = 0;
+
+ // Does this font have a toUnicode map?
+ GBool hasToUnicodeCMap() { return hasToUnicode; }
+
+ // Return the name of the encoding
+ GooString *getEncodingName() { return encodingName; }
+
+ // Return AGLFN names of ligatures in the Standard and Expert encodings
+ // for use with fonts that are not compatible with the Standard 14 fonts.
+ // http://sourceforge.net/adobe/aglfn/wiki/AGL%20Specification/
+ static const char *getAlternateName(const char *name);
+
+protected:
+
+ virtual ~GfxFont();
+
+ static GfxFontType getFontType(XRef *xref, Dict *fontDict, Ref *embID);
+ void readFontDescriptor(XRef *xref, Dict *fontDict);
+ CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits,
+ CharCodeToUnicode *ctu);
+ static GfxFontLoc *getExternalFont(GooString *path, GBool cid);
+
+ GooString *tag; // PDF font tag
+ Ref id; // reference (used as unique ID)
+ GooString *name; // font name
+ GooString *family; // font family
+ Stretch stretch; // font stretch
+ Weight weight; // font weight
+ GfxFontType type; // type of font
+ int flags; // font descriptor flags
+ GooString *embFontName; // name of embedded font
+ Ref embFontID; // ref to embedded font file stream
+ double fontMat[6]; // font matrix (Type 3 only)
+ double fontBBox[4]; // font bounding box (Type 3 only)
+ double missingWidth; // "default" width
+ double ascent; // max height above baseline
+ double descent; // max depth below baseline
+ int refCnt;
+ GBool ok;
+ GBool hasToUnicode;
+ GooString *encodingName;
+};
+
+//------------------------------------------------------------------------
+// Gfx8BitFont
+//------------------------------------------------------------------------
+
+class Gfx8BitFont: public GfxFont {
+public:
+
+ Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict);
+
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode **u, int *uLen,
+ double *dx, double *dy, double *ox, double *oy);
+
+ // Return the encoding.
+ char **getEncoding() { return enc; }
+
+ // Return the Unicode map.
+ CharCodeToUnicode *getToUnicode();
+
+ // Return the character name associated with <code>.
+ char *getCharName(int code) { return enc[code]; }
+
+ // Returns true if the PDF font specified an encoding.
+ GBool getHasEncoding() { return hasEncoding; }
+
+ // Returns true if the PDF font specified MacRomanEncoding.
+ GBool getUsesMacRomanEnc() { return usesMacRomanEnc; }
+
+ // Get width of a character.
+ double getWidth(Guchar c) { return widths[c]; }
+
+ // Return a char code-to-GID mapping for the provided font file.
+ // (This is only useful for TrueType fonts.)
+ int *getCodeToGIDMap(FoFiTrueType *ff);
+
+ // Return the Type 3 CharProc dictionary, or NULL if none.
+ Dict *getCharProcs();
+
+ // Return the Type 3 CharProc for the character associated with <code>.
+ Object *getCharProc(int code, Object *proc);
+
+ // Return the Type 3 Resources dictionary, or NULL if none.
+ Dict *getResources();
+
+private:
+ virtual ~Gfx8BitFont();
+
+ const Base14FontMapEntry *base14; // for Base-14 fonts only; NULL otherwise
+ char *enc[256]; // char code --> char name
+ char encFree[256]; // boolean for each char name: if set,
+ // the string is malloc'ed
+ CharCodeToUnicode *ctu; // char code --> Unicode
+ GBool hasEncoding;
+ GBool usesMacRomanEnc;
+ double widths[256]; // character widths
+ Object charProcs; // Type 3 CharProcs dictionary
+ Object resources; // Type 3 Resources dictionary
+
+ friend class GfxFont;
+};
+
+//------------------------------------------------------------------------
+// GfxCIDFont
+//------------------------------------------------------------------------
+
+class GfxCIDFont: public GfxFont {
+public:
+
+ GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict);
+
+ virtual GBool isCIDFont() { return gTrue; }
+
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode **u, int *uLen,
+ double *dx, double *dy, double *ox, double *oy);
+
+ // Return the writing mode (0=horizontal, 1=vertical).
+ virtual int getWMode();
+
+ // Return the Unicode map.
+ CharCodeToUnicode *getToUnicode();
+
+ // Get the collection name (<registry>-<ordering>).
+ GooString *getCollection();
+
+ // Return the CID-to-GID mapping table. These should only be called
+ // if type is fontCIDType2.
+ int *getCIDToGID() { return cidToGID; }
+ int getCIDToGIDLen() { return cidToGIDLen; }
+
+ int *getCodeToGIDMap(FoFiTrueType *ff, int *length);
+
+ double getWidth(char* s, int len);
+
+private:
+ virtual ~GfxCIDFont();
+
+ int mapCodeToGID(FoFiTrueType *ff, int cmapi,
+ Unicode unicode, GBool wmode);
+ double getWidth(CID cid); // Get width of a character.
+
+ GooString *collection; // collection name
+ CMap *cMap; // char code --> CID
+ CharCodeToUnicode *ctu; // CID --> Unicode
+ GBool ctuUsesCharCode; // true: ctu maps char code to Unicode;
+ // false: ctu maps CID to Unicode
+ GfxFontCIDWidths widths; // character widths
+ int *cidToGID; // CID --> GID mapping (for embedded
+ // TrueType fonts)
+ int cidToGIDLen;
+};
+
+//------------------------------------------------------------------------
+// GfxFontDict
+//------------------------------------------------------------------------
+
+class GfxFontDict {
+public:
+
+ // Build the font dictionary, given the PDF font dictionary.
+ GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict);
+
+ // Destructor.
+ ~GfxFontDict();
+
+ // Get the specified font.
+ GfxFont *lookup(char *tag);
+
+ // Iterative access.
+ int getNumFonts() { return numFonts; }
+ GfxFont *getFont(int i) { return fonts[i]; }
+
+private:
+
+ GfxFont **fonts; // list of fonts
+ int numFonts; // number of fonts
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState.cc
new file mode 100644
index 00000000000..cacccad3097
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState.cc
@@ -0,0 +1,7273 @@
+//========================================================================
+//
+// GfxState.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2006, 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2006-2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009, 2012 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2009, 2011-2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2009 Christian Persch <chpe@gnome.org>
+// Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
+// Copyright (C) 2012 William Bader <williambader@hotmail.com>
+// Copyright (C) 2013 Lu Wang <coolwanglu@gmail.com>
+// Copyright (C) 2013 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <algorithm>
+#include <stddef.h>
+#include <math.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "Error.h"
+#include "Object.h"
+#include "Array.h"
+#include "Page.h"
+#include "Gfx.h"
+#include "GfxState.h"
+#include "GfxState_helpers.h"
+#include "GfxFont.h"
+#include "GlobalParams.h"
+#include "PopplerCache.h"
+#include "OutputDev.h"
+#include "splash/SplashTypes.h"
+
+//------------------------------------------------------------------------
+
+// Max depth of nested color spaces. This is used to catch infinite
+// loops in the color space object structure.
+#define colorSpaceRecursionLimit 8
+
+//------------------------------------------------------------------------
+
+GBool Matrix::invertTo(Matrix *other) const
+{
+ double det;
+
+ det = 1 / determinant();
+ other->m[0] = m[3] * det;
+ other->m[1] = -m[1] * det;
+ other->m[2] = -m[2] * det;
+ other->m[3] = m[0] * det;
+ other->m[4] = (m[2] * m[5] - m[3] * m[4]) * det;
+ other->m[5] = (m[1] * m[4] - m[0] * m[5]) * det;
+
+ return gTrue;
+}
+
+void Matrix::transform(double x, double y, double *tx, double *ty) const
+{
+ double temp_x, temp_y;
+
+ temp_x = m[0] * x + m[2] * y + m[4];
+ temp_y = m[1] * x + m[3] * y + m[5];
+
+ *tx = temp_x;
+ *ty = temp_y;
+}
+
+// Matrix norm, taken from _cairo_matrix_transformed_circle_major_axis
+double Matrix::norm() const
+{
+ double f, g, h, i, j;
+
+ i = m[0]*m[0] + m[1]*m[1];
+ j = m[2]*m[2] + m[3]*m[3];
+
+ f = 0.5 * (i + j);
+ g = 0.5 * (i - j);
+ h = m[0]*m[2] + m[1]*m[3];
+
+ return sqrt (f + hypot (g, h));
+}
+
+//------------------------------------------------------------------------
+
+struct GfxBlendModeInfo {
+ const char *name;
+ GfxBlendMode mode;
+};
+
+static const GfxBlendModeInfo gfxBlendModeNames[] = {
+ { "Normal", gfxBlendNormal },
+ { "Compatible", gfxBlendNormal },
+ { "Multiply", gfxBlendMultiply },
+ { "Screen", gfxBlendScreen },
+ { "Overlay", gfxBlendOverlay },
+ { "Darken", gfxBlendDarken },
+ { "Lighten", gfxBlendLighten },
+ { "ColorDodge", gfxBlendColorDodge },
+ { "ColorBurn", gfxBlendColorBurn },
+ { "HardLight", gfxBlendHardLight },
+ { "SoftLight", gfxBlendSoftLight },
+ { "Difference", gfxBlendDifference },
+ { "Exclusion", gfxBlendExclusion },
+ { "Hue", gfxBlendHue },
+ { "Saturation", gfxBlendSaturation },
+ { "Color", gfxBlendColor },
+ { "Luminosity", gfxBlendLuminosity }
+};
+
+#define nGfxBlendModeNames \
+ ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo))))
+
+//------------------------------------------------------------------------
+//
+// NB: This must match the GfxColorSpaceMode enum defined in
+// GfxState.h
+static const char *gfxColorSpaceModeNames[] = {
+ "DeviceGray",
+ "CalGray",
+ "DeviceRGB",
+ "CalRGB",
+ "DeviceCMYK",
+ "Lab",
+ "ICCBased",
+ "Indexed",
+ "Separation",
+ "DeviceN",
+ "Pattern"
+};
+
+#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
+
+#ifdef USE_CMS
+
+static const std::map<unsigned int, unsigned int>::size_type CMSCACHE_LIMIT = 2048;
+
+#ifdef USE_LCMS1
+#include <lcms.h>
+#define cmsColorSpaceSignature icColorSpaceSignature
+#define cmsSetLogErrorHandler cmsSetErrorHandler
+#define cmsSigXYZData icSigXYZData
+#define cmsSigLuvData icSigLuvData
+#define cmsSigLabData icSigLabData
+#define cmsSigYCbCrData icSigYCbCrData
+#define cmsSigYxyData icSigYxyData
+#define cmsSigRgbData icSigRgbData
+#define cmsSigHsvData icSigHsvData
+#define cmsSigHlsData icSigHlsData
+#define cmsSigCmyData icSigCmyData
+#define cmsSig3colorData icSig3colorData
+#define cmsSigGrayData icSigGrayData
+#define cmsSigCmykData icSigCmykData
+#define cmsSig4colorData icSig4colorData
+#define cmsSig2colorData icSig2colorData
+#define cmsSig5colorData icSig5colorData
+#define cmsSig6colorData icSig6colorData
+#define cmsSig7colorData icSig7colorData
+#define cmsSig8colorData icSig8colorData
+#define cmsSig9colorData icSig9colorData
+#define cmsSig10colorData icSig10colorData
+#define cmsSig11colorData icSig11colorData
+#define cmsSig12colorData icSig12colorData
+#define cmsSig13colorData icSig13colorData
+#define cmsSig14colorData icSig14colorData
+#define cmsSig15colorData icSig15colorData
+#define LCMS_FLAGS 0
+#else
+#include <lcms2.h>
+#define LCMS_FLAGS cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION
+#endif
+
+#define COLOR_PROFILE_DIR "/ColorProfiles/"
+#define GLOBAL_COLOR_PROFILE_DIR POPPLER_DATADIR COLOR_PROFILE_DIR
+
+void GfxColorTransform::doTransform(void *in, void *out, unsigned int size) {
+ cmsDoTransform(transform, in, out, size);
+}
+
+// transformA should be a cmsHTRANSFORM
+GfxColorTransform::GfxColorTransform(void *transformA, int cmsIntentA, unsigned int inputPixelTypeA, unsigned int transformPixelTypeA) {
+ transform = transformA;
+ refCount = 1;
+ cmsIntent = cmsIntentA;
+ inputPixelType = inputPixelTypeA;
+ transformPixelType = transformPixelTypeA;
+}
+
+GfxColorTransform::~GfxColorTransform() {
+ cmsDeleteTransform(transform);
+}
+
+void GfxColorTransform::ref() {
+ refCount++;
+}
+
+unsigned int GfxColorTransform::unref() {
+ return --refCount;
+}
+
+static cmsHPROFILE RGBProfile = NULL;
+static GooString *displayProfileName = NULL; // display profile file Name
+static cmsHPROFILE displayProfile = NULL; // display profile
+static unsigned int displayPixelType = 0;
+static GfxColorTransform *XYZ2DisplayTransform = NULL;
+
+// convert color space signature to cmsColor type
+static unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs);
+static unsigned int getCMSNChannels(cmsColorSpaceSignature cs);
+static cmsHPROFILE loadColorProfile(const char *fileName);
+
+void GfxColorSpace::setDisplayProfile(void *displayProfileA) {
+ displayProfile = displayProfileA;
+ if (displayProfile != NULL) {
+ cmsHTRANSFORM transform;
+ unsigned int nChannels;
+
+ displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile));
+ nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile));
+ // create transform from XYZ
+ cmsHPROFILE XYZProfile = cmsCreateXYZProfile();
+ if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
+ displayProfile,
+ COLORSPACE_SH(displayPixelType) |
+ CHANNELS_SH(nChannels) | BYTES_SH(1),
+ INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == 0) {
+ error(errSyntaxWarning, -1, "Can't create Lab transform");
+ } else {
+ XYZ2DisplayTransform = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
+ }
+ cmsCloseProfile(XYZProfile);
+ }
+}
+
+void GfxColorSpace::setDisplayProfileName(GooString *name) {
+ displayProfileName = name->copy();
+}
+
+cmsHPROFILE GfxColorSpace::getRGBProfile() {
+ return RGBProfile;
+}
+
+cmsHPROFILE GfxColorSpace::getDisplayProfile() {
+ return displayProfile;
+}
+
+#endif
+
+//------------------------------------------------------------------------
+// GfxColorSpace
+//------------------------------------------------------------------------
+
+GfxColorSpace::GfxColorSpace() {
+ overprintMask = 0x0f;
+ mapping = NULL;
+}
+
+GfxColorSpace::~GfxColorSpace() {
+}
+
+GfxColorSpace *GfxColorSpace::parse(GfxResources *res, Object *csObj, OutputDev *out, GfxState *state, int recursion) {
+ GfxColorSpace *cs;
+ Object obj1;
+
+ if (recursion > colorSpaceRecursionLimit) {
+ error(errSyntaxError, -1, "Loop detected in color space objects");
+ return NULL;
+ }
+
+ cs = NULL;
+ if (csObj->isName()) {
+ if (csObj->isName("DeviceGray") || csObj->isName("G")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultGray", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceGrayColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceGrayColorSpace();
+ }
+ } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultRGB", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceRGBColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceRGBColorSpace();
+ }
+ } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultCMYK", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceCMYKColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceCMYKColorSpace();
+ }
+ } else if (csObj->isName("Pattern")) {
+ cs = new GfxPatternColorSpace(NULL);
+ } else {
+ error(errSyntaxWarning, -1, "Bad color space '{0:s}'", csObj->getName());
+ }
+ } else if (csObj->isArray() && csObj->arrayGetLength() > 0) {
+ csObj->arrayGet(0, &obj1);
+ if (obj1.isName("DeviceGray") || obj1.isName("G")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultGray", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceGrayColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceGrayColorSpace();
+ }
+ } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultRGB", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceRGBColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceRGBColorSpace();
+ }
+ } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultCMYK", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceCMYKColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceCMYKColorSpace();
+ }
+ } else if (obj1.isName("CalGray")) {
+ cs = GfxCalGrayColorSpace::parse(csObj->getArray(), state);
+ } else if (obj1.isName("CalRGB")) {
+ cs = GfxCalRGBColorSpace::parse(csObj->getArray(), state);
+ } else if (obj1.isName("Lab")) {
+ cs = GfxLabColorSpace::parse(csObj->getArray(), state);
+ } else if (obj1.isName("ICCBased")) {
+ cs = GfxICCBasedColorSpace::parse(csObj->getArray(), out, state, recursion);
+ } else if (obj1.isName("Indexed") || obj1.isName("I")) {
+ cs = GfxIndexedColorSpace::parse(res, csObj->getArray(), out, state, recursion);
+ } else if (obj1.isName("Separation")) {
+ cs = GfxSeparationColorSpace::parse(res, csObj->getArray(), out, state, recursion);
+ } else if (obj1.isName("DeviceN")) {
+ cs = GfxDeviceNColorSpace::parse(res, csObj->getArray(), out, state, recursion);
+ } else if (obj1.isName("Pattern")) {
+ cs = GfxPatternColorSpace::parse(res, csObj->getArray(), out, state, recursion);
+ } else {
+ error(errSyntaxWarning, -1, "Bad color space");
+ }
+ obj1.free();
+ } else if (csObj->isDict()) {
+ csObj->dictLookup("ColorSpace", &obj1);
+ if (obj1.isName("DeviceGray")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultGray", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceGrayColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceGrayColorSpace();
+ }
+ } else if (obj1.isName("DeviceRGB")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultRGB", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceRGBColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceRGBColorSpace();
+ }
+ } else if (obj1.isName("DeviceCMYK")) {
+ if (res != NULL) {
+ Object objCS;
+ res->lookupColorSpace("DefaultCMYK", &objCS);
+ if (objCS.isNull()) {
+ cs = new GfxDeviceCMYKColorSpace();
+ } else {
+ cs = GfxColorSpace::parse(NULL, &objCS, out, state);
+ }
+ objCS.free();
+ } else {
+ cs = new GfxDeviceCMYKColorSpace();
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Bad color space dict'");
+ }
+ obj1.free();
+ } else {
+ error(errSyntaxWarning, -1, "Bad color space - expected name or array or dict");
+ }
+ return cs;
+}
+
+void GfxColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+ return;
+}
+
+void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel) {
+ int i;
+
+ for (i = 0; i < getNComps(); ++i) {
+ decodeLow[i] = 0;
+ decodeRange[i] = 1;
+ }
+}
+
+int GfxColorSpace::getNumColorSpaceModes() {
+ return nGfxColorSpaceModes;
+}
+
+const char *GfxColorSpace::getColorSpaceModeName(int idx) {
+ return gfxColorSpaceModeNames[idx];
+}
+
+#ifdef USE_CMS
+cmsHPROFILE loadColorProfile(const char *fileName)
+{
+ cmsHPROFILE hp = NULL;
+ FILE *fp;
+
+ if (fileName[0] == '/') {
+ // full path
+ // check if open the file
+ if ((fp = fopen(fileName,"r")) != NULL) {
+ fclose(fp);
+ hp = cmsOpenProfileFromFile(fileName,"r");
+ }
+ return hp;
+ }
+ // try to load from global directory
+ GooString *path = new GooString(GLOBAL_COLOR_PROFILE_DIR);
+ path->append(fileName);
+ // check if open the file
+ if ((fp = fopen(path->getCString(),"r")) != NULL) {
+ fclose(fp);
+ hp = cmsOpenProfileFromFile(path->getCString(),"r");
+ }
+ delete path;
+ return hp;
+}
+
+#ifdef USE_LCMS1
+static int CMSError(int ecode, const char *msg)
+{
+ error(errSyntaxWarning, -1, "{0:s}", msg);
+ return 1;
+}
+#else
+static void CMSError(cmsContext /*contextId*/, cmsUInt32Number /*ecode*/, const char *text)
+{
+ error(errSyntaxWarning, -1, "{0:s}", text);
+}
+#endif
+
+int GfxColorSpace::setupColorProfiles()
+{
+ static GBool initialized = gFalse;
+ cmsHTRANSFORM transform;
+ unsigned int nChannels;
+
+ // do only once
+ if (initialized) return 0;
+ initialized = gTrue;
+
+ // set error handlor
+ cmsSetLogErrorHandler(CMSError);
+
+ if (displayProfile == NULL) {
+ // load display profile if it was not already loaded.
+ if (displayProfileName == NULL) {
+ displayProfile = loadColorProfile("display.icc");
+ } else if (displayProfileName->getLength() > 0) {
+ displayProfile = loadColorProfile(displayProfileName->getCString());
+ }
+ }
+ // load RGB profile
+ RGBProfile = loadColorProfile("RGB.icc");
+ if (RGBProfile == NULL) {
+ /* use built in sRGB profile */
+ RGBProfile = cmsCreate_sRGBProfile();
+ }
+ // create transforms
+ if (displayProfile != NULL) {
+ displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile));
+ nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile));
+ // create transform from XYZ
+ cmsHPROFILE XYZProfile = cmsCreateXYZProfile();
+ if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
+ displayProfile,
+ COLORSPACE_SH(displayPixelType) |
+ CHANNELS_SH(nChannels) | BYTES_SH(1),
+ INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == 0) {
+ error(errSyntaxWarning, -1, "Can't create Lab transform");
+ } else {
+ XYZ2DisplayTransform = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
+ }
+ cmsCloseProfile(XYZProfile);
+ }
+ return 0;
+}
+
+unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs)
+{
+ switch (cs) {
+ case cmsSigXYZData:
+ return PT_XYZ;
+ break;
+ case cmsSigLabData:
+ return PT_Lab;
+ break;
+ case cmsSigLuvData:
+ return PT_YUV;
+ break;
+ case cmsSigYCbCrData:
+ return PT_YCbCr;
+ break;
+ case cmsSigYxyData:
+ return PT_Yxy;
+ break;
+ case cmsSigRgbData:
+ return PT_RGB;
+ break;
+ case cmsSigGrayData:
+ return PT_GRAY;
+ break;
+ case cmsSigHsvData:
+ return PT_HSV;
+ break;
+ case cmsSigHlsData:
+ return PT_HLS;
+ break;
+ case cmsSigCmykData:
+ return PT_CMYK;
+ break;
+ case cmsSigCmyData:
+ return PT_CMY;
+ break;
+ case cmsSig2colorData:
+ case cmsSig3colorData:
+ case cmsSig4colorData:
+ case cmsSig5colorData:
+ case cmsSig6colorData:
+ case cmsSig7colorData:
+ case cmsSig8colorData:
+ case cmsSig9colorData:
+ case cmsSig10colorData:
+ case cmsSig11colorData:
+ case cmsSig12colorData:
+ case cmsSig13colorData:
+ case cmsSig14colorData:
+ case cmsSig15colorData:
+ default:
+ break;
+ }
+ return PT_RGB;
+}
+
+unsigned int getCMSNChannels(cmsColorSpaceSignature cs)
+{
+ switch (cs) {
+ case cmsSigXYZData:
+ case cmsSigLuvData:
+ case cmsSigLabData:
+ case cmsSigYCbCrData:
+ case cmsSigYxyData:
+ case cmsSigRgbData:
+ case cmsSigHsvData:
+ case cmsSigHlsData:
+ case cmsSigCmyData:
+ case cmsSig3colorData:
+ return 3;
+ break;
+ case cmsSigGrayData:
+ return 1;
+ break;
+ case cmsSigCmykData:
+ case cmsSig4colorData:
+ return 4;
+ break;
+ case cmsSig2colorData:
+ return 2;
+ break;
+ case cmsSig5colorData:
+ return 5;
+ break;
+ case cmsSig6colorData:
+ return 6;
+ break;
+ case cmsSig7colorData:
+ return 7;
+ break;
+ case cmsSig8colorData:
+ return 8;
+ break;
+ case cmsSig9colorData:
+ return 9;
+ break;
+ case cmsSig10colorData:
+ return 10;
+ break;
+ case cmsSig11colorData:
+ return 11;
+ break;
+ case cmsSig12colorData:
+ return 12;
+ break;
+ case cmsSig13colorData:
+ return 13;
+ break;
+ case cmsSig14colorData:
+ return 14;
+ break;
+ case cmsSig15colorData:
+ return 15;
+ default:
+ break;
+ }
+ return 3;
+}
+#endif
+
+//------------------------------------------------------------------------
+// GfxDeviceGrayColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
+}
+
+GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
+ return new GfxDeviceGrayColorSpace();
+}
+
+void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01(color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getGrayLine(Guchar *in, Guchar *out, int length) {
+ memcpy (out, in, length);
+}
+
+void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getRGBLine(Guchar *in, unsigned int *out,
+ int length) {
+ int i;
+
+ for (i = 0; i < length; i++)
+ out[i] = (in[i] << 16) | (in[i] << 8) | (in[i] << 0);
+}
+
+void GfxDeviceGrayColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) {
+ for (int i = 0; i < length; i++) {
+ *out++ = in[i];
+ *out++ = in[i];
+ *out++ = in[i];
+ }
+}
+
+void GfxDeviceGrayColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) {
+ for (int i = 0; i < length; i++) {
+ *out++ = in[i];
+ *out++ = in[i];
+ *out++ = in[i];
+ *out++ = 255;
+ }
+}
+
+void GfxDeviceGrayColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) {
+ for (int i = 0; i < length; i++) {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = in[i];
+ }
+}
+
+void GfxDeviceGrayColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) {
+ for (int i = 0; i < length; i++) {
+ for (int j = 0; j < SPOT_NCOMPS+4; j++)
+ out[j] = 0;
+ out[4] = in[i];
+ out += (SPOT_NCOMPS+4);
+ }
+}
+
+void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = cmyk->m = cmyk->y = 0;
+ cmyk->k = clip01(gfxColorComp1 - color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ deviceN->c[3] = clip01(gfxColorComp1 - color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxCalGrayColorSpace
+//------------------------------------------------------------------------
+
+GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ gamma = 1;
+}
+
+GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
+#ifdef USE_CMS
+ if (transform != NULL) {
+ if (transform->unref() == 0) delete transform;
+ }
+#endif
+}
+
+GfxColorSpace *GfxCalGrayColorSpace::copy() {
+ GfxCalGrayColorSpace *cs;
+
+ cs = new GfxCalGrayColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->gamma = gamma;
+#ifdef USE_CMS
+ cs->transform = transform;
+ if (transform != NULL) transform->ref();
+#endif
+ return cs;
+}
+
+// This is the inverse of MatrixLMN in Example 4.10 from the PostScript
+// Language Reference, Third Edition.
+static const double xyzrgb[3][3] = {
+ { 3.240449, -1.537136, -0.498531 },
+ { -0.969265, 1.876011, 0.041556 },
+ { 0.055643, -0.204026, 1.057229 }
+};
+
+GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, GfxState *state) {
+ GfxCalGrayColorSpace *cs;
+ Object obj1, obj2, obj3;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(errSyntaxWarning, -1, "Bad CalGray color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxCalGrayColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ if (likely(obj3.isNum()))
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ if (likely(obj3.isNum()))
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ if (likely(obj3.isNum()))
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ if (likely(obj3.isNum()))
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ if (likely(obj3.isNum()))
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ if (likely(obj3.isNum()))
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
+ cs->gamma = obj2.getNum();
+ }
+ obj2.free();
+ obj1.free();
+
+ cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
+ xyzrgb[0][1] * cs->whiteY +
+ xyzrgb[0][2] * cs->whiteZ);
+ cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
+ xyzrgb[1][1] * cs->whiteY +
+ xyzrgb[1][2] * cs->whiteZ);
+ cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
+ xyzrgb[2][1] * cs->whiteY +
+ xyzrgb[2][2] * cs->whiteZ);
+#ifdef USE_CMS
+ cs->transform = (state != NULL) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform;
+ if (cs->transform != NULL) cs->transform->ref();
+#endif
+ return cs;
+}
+
+// convert CalGray to media XYZ color space
+// (not multiply by the white point)
+void GfxCalGrayColorSpace::getXYZ(GfxColor *color,
+ double *pX, double *pY, double *pZ) {
+ const double A = colToDbl(color->c[0]);
+ const double xyzColor = pow(A,gamma);
+ *pX = xyzColor;
+ *pY = xyzColor;
+ *pZ = xyzColor;
+}
+
+void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxRGB rgb;
+
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_GRAY) {
+ Guchar out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+ double X, Y, Z;
+
+ getXYZ(color,&X,&Y,&Z);
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ transform->doTransform(in,out,1);
+ *gray = byteToCol(out[0]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ *gray = clip01((GfxColorComp)(0.299 * rgb.r +
+ 0.587 * rgb.g +
+ 0.114 * rgb.b + 0.5));
+}
+
+void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double X, Y, Z;
+ double r, g, b;
+
+ getXYZ(color,&X,&Y,&Z);
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_RGB) {
+ Guchar out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ transform->doTransform(in,out,1);
+ rgb->r = byteToCol(out[0]);
+ rgb->g = byteToCol(out[1]);
+ rgb->b = byteToCol(out[2]);
+ return;
+ }
+#endif
+ X *= whiteX;
+ Y *= whiteY;
+ Z *= whiteZ;
+ // convert XYZ to RGB, including gamut mapping and gamma correction
+ r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
+ g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
+ b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
+ rgb->r = dblToCol(sqrt(clip01(r * kr)));
+ rgb->g = dblToCol(sqrt(clip01(g * kg)));
+ rgb->b = dblToCol(sqrt(clip01(b * kb)));
+}
+
+void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxRGB rgb;
+ GfxColorComp c, m, y, k;
+
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) {
+ double in[gfxColorMaxComps];
+ Guchar out[gfxColorMaxComps];
+ double X, Y, Z;
+
+ getXYZ(color,&X,&Y,&Z);
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+
+ transform->doTransform(in,out,1);
+ cmyk->c = byteToCol(out[0]);
+ cmyk->m = byteToCol(out[1]);
+ cmyk->y = byteToCol(out[2]);
+ cmyk->k = byteToCol(out[3]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+void GfxCalGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
+void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceRGBColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
+}
+
+GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
+ return new GfxDeviceRGBColorSpace();
+}
+
+void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01((GfxColorComp)(0.3 * color->c[0] +
+ 0.59 * color->c[1] +
+ 0.11 * color->c[2] + 0.5));
+}
+
+void GfxDeviceRGBColorSpace::getGrayLine(Guchar *in, Guchar *out, int length) {
+ int i;
+
+ for (i = 0; i < length; i++) {
+ out[i] =
+ (in[i * 3 + 0] * 19595 +
+ in[i * 3 + 1] * 38469 +
+ in[i * 3 + 2] * 7472) / 65536;
+ }
+}
+
+void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = clip01(color->c[0]);
+ rgb->g = clip01(color->c[1]);
+ rgb->b = clip01(color->c[2]);
+}
+
+void GfxDeviceRGBColorSpace::getRGBLine(Guchar *in, unsigned int *out,
+ int length) {
+ Guchar *p;
+ int i;
+
+ for (i = 0, p = in; i < length; i++, p += 3)
+ out[i] = (p[0] << 16) | (p[1] << 8) | (p[2] << 0);
+}
+
+void GfxDeviceRGBColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) {
+ for (int i = 0; i < length; i++) {
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ }
+}
+
+void GfxDeviceRGBColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) {
+ for (int i = 0; i < length; i++) {
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = 255;
+ }
+}
+
+void GfxDeviceRGBColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) {
+ GfxColorComp c, m, y, k;
+
+ for (int i = 0; i < length; i++) {
+ c = byteToCol(255 - *in++);
+ m = byteToCol(255 - *in++);
+ y = byteToCol(255 - *in++);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ *out++ = colToByte(c - k);
+ *out++ = colToByte(m - k);
+ *out++ = colToByte(y - k);
+ *out++ = colToByte(k);
+ }
+}
+
+void GfxDeviceRGBColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) {
+ GfxColorComp c, m, y, k;
+
+ for (int i = 0; i < length; i++) {
+ for (int j = 0; j < SPOT_NCOMPS+4; j++)
+ out[j] = 0;
+ c = byteToCol(255 - *in++);
+ m = byteToCol(255 - *in++);
+ y = byteToCol(255 - *in++);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ out[0] = colToByte(c - k);
+ out[1] = colToByte(m - k);
+ out[2] = colToByte(y - k);
+ out[3] = colToByte(k);
+ out += (SPOT_NCOMPS+4);
+ }
+}
+
+void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxColorComp c, m, y, k;
+
+ c = clip01(gfxColorComp1 - color->c[0]);
+ m = clip01(gfxColorComp1 - color->c[1]);
+ y = clip01(gfxColorComp1 - color->c[2]);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+void GfxDeviceRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
+void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+ color->c[1] = 0;
+ color->c[2] = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxCalRGBColorSpace
+//------------------------------------------------------------------------
+
+GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ gammaR = gammaG = gammaB = 1;
+ mat[0] = 1; mat[1] = 0; mat[2] = 0;
+ mat[3] = 0; mat[4] = 1; mat[5] = 0;
+ mat[6] = 0; mat[7] = 0; mat[8] = 1;
+}
+
+GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
+#ifdef USE_CMS
+ if (transform != NULL) {
+ if (transform->unref() == 0) delete transform;
+ }
+#endif
+}
+
+GfxColorSpace *GfxCalRGBColorSpace::copy() {
+ GfxCalRGBColorSpace *cs;
+ int i;
+
+ cs = new GfxCalRGBColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->gammaR = gammaR;
+ cs->gammaG = gammaG;
+ cs->gammaB = gammaB;
+ for (i = 0; i < 9; ++i) {
+ cs->mat[i] = mat[i];
+ }
+#ifdef USE_CMS
+ cs->transform = transform;
+ if (transform != NULL) transform->ref();
+#endif
+ return cs;
+}
+
+GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, GfxState *state) {
+ GfxCalRGBColorSpace *cs;
+ Object obj1, obj2, obj3;
+ int i;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(errSyntaxWarning, -1, "Bad CalRGB color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxCalRGBColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ if (likely(obj3.isNum()))
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ if (likely(obj3.isNum()))
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ if (likely(obj3.isNum()))
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ if (likely(obj3.isNum()))
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ if (likely(obj3.isNum()))
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ if (likely(obj3.isNum()))
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ if (likely(obj3.isNum()))
+ cs->gammaR = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ if (likely(obj3.isNum()))
+ cs->gammaG = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ if (likely(obj3.isNum()))
+ cs->gammaB = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 9) {
+ for (i = 0; i < 9; ++i) {
+ obj2.arrayGet(i, &obj3);
+ if (likely(obj3.isNum()))
+ cs->mat[i] = obj3.getNum();
+ obj3.free();
+ }
+ }
+ obj2.free();
+ obj1.free();
+
+ cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
+ xyzrgb[0][1] * cs->whiteY +
+ xyzrgb[0][2] * cs->whiteZ);
+ cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
+ xyzrgb[1][1] * cs->whiteY +
+ xyzrgb[1][2] * cs->whiteZ);
+ cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
+ xyzrgb[2][1] * cs->whiteY +
+ xyzrgb[2][2] * cs->whiteZ);
+
+#ifdef USE_CMS
+ cs->transform = (state != NULL) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform;
+ if (cs->transform != NULL) cs->transform->ref();
+#endif
+ return cs;
+}
+
+// convert CalRGB to XYZ color space
+void GfxCalRGBColorSpace::getXYZ(GfxColor *color,
+ double *pX, double *pY, double *pZ) {
+ double A, B, C;
+
+ A = pow(colToDbl(color->c[0]), gammaR);
+ B = pow(colToDbl(color->c[1]), gammaG);
+ C = pow(colToDbl(color->c[2]), gammaB);
+ *pX = mat[0] * A + mat[3] * B + mat[6] * C;
+ *pY = mat[1] * A + mat[4] * B + mat[7] * C;
+ *pZ = mat[2] * A + mat[5] * B + mat[8] * C;
+}
+
+void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxRGB rgb;
+
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_GRAY) {
+ Guchar out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+ double X, Y, Z;
+
+ getXYZ(color,&X,&Y,&Z);
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ transform->doTransform(in,out,1);
+ *gray = byteToCol(out[0]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ *gray = clip01((GfxColorComp)(0.299 * rgb.r +
+ 0.587 * rgb.g +
+ 0.114 * rgb.b + 0.5));
+}
+
+void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double X, Y, Z;
+ double r, g, b;
+
+ getXYZ(color,&X,&Y,&Z);
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_RGB) {
+ Guchar out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+
+ in[0] = clip01(X/whiteX);
+ in[1] = clip01(Y/whiteY);
+ in[2] = clip01(Z/whiteZ);
+ transform->doTransform(in,out,1);
+ rgb->r = byteToCol(out[0]);
+ rgb->g = byteToCol(out[1]);
+ rgb->b = byteToCol(out[2]);
+ return;
+ }
+#endif
+ // convert XYZ to RGB, including gamut mapping and gamma correction
+ r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
+ g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
+ b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
+ rgb->r = dblToCol(sqrt(clip01(r)));
+ rgb->g = dblToCol(sqrt(clip01(g)));
+ rgb->b = dblToCol(sqrt(clip01(b)));
+}
+
+void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxRGB rgb;
+ GfxColorComp c, m, y, k;
+
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) {
+ double in[gfxColorMaxComps];
+ Guchar out[gfxColorMaxComps];
+ double X, Y, Z;
+
+ getXYZ(color,&X,&Y,&Z);
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ transform->doTransform(in,out,1);
+ cmyk->c = byteToCol(out[0]);
+ cmyk->m = byteToCol(out[1]);
+ cmyk->y = byteToCol(out[2]);
+ cmyk->k = byteToCol(out[3]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+void GfxCalRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
+void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+ color->c[1] = 0;
+ color->c[2] = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceCMYKColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
+}
+
+GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
+ return new GfxDeviceCMYKColorSpace();
+}
+
+void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3]
+ - 0.3 * color->c[0]
+ - 0.59 * color->c[1]
+ - 0.11 * color->c[2] + 0.5));
+}
+
+void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+ c = colToDbl(color->c[0]);
+ m = colToDbl(color->c[1]);
+ y = colToDbl(color->c[2]);
+ k = colToDbl(color->c[3]);
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+ rgb->r = clip01(dblToCol(r));
+ rgb->g = clip01(dblToCol(g));
+ rgb->b = clip01(dblToCol(b));
+}
+
+static inline void GfxDeviceCMYKColorSpacegetRGBLineHelper(Guchar *&in, double &r, double &g, double &b)
+{
+ double c, m, y, k, c1, m1, y1, k1;
+
+ c = byteToDbl(*in++);
+ m = byteToDbl(*in++);
+ y = byteToDbl(*in++);
+ k = byteToDbl(*in++);
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+}
+
+void GfxDeviceCMYKColorSpace::getRGBLine(Guchar *in, unsigned int *out, int length)
+{
+ double r, g, b;
+ for (int i = 0; i < length; i++) {
+ GfxDeviceCMYKColorSpacegetRGBLineHelper(in, r, g, b);
+ *out++ = (dblToByte(clip01(r)) << 16) | (dblToByte(clip01(g)) << 8) | dblToByte(clip01(b));
+ }
+}
+
+void GfxDeviceCMYKColorSpace::getRGBLine(Guchar *in, Guchar *out, int length)
+{
+ double r, g, b;
+
+ for (int i = 0; i < length; i++) {
+ GfxDeviceCMYKColorSpacegetRGBLineHelper(in, r, g, b);
+ *out++ = dblToByte(clip01(r));
+ *out++ = dblToByte(clip01(g));
+ *out++ = dblToByte(clip01(b));
+ }
+}
+
+void GfxDeviceCMYKColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length)
+{
+ double r, g, b;
+
+ for (int i = 0; i < length; i++) {
+ GfxDeviceCMYKColorSpacegetRGBLineHelper(in, r, g, b);
+ *out++ = dblToByte(clip01(r));
+ *out++ = dblToByte(clip01(g));
+ *out++ = dblToByte(clip01(b));
+ *out++ = 255;
+ }
+}
+
+void GfxDeviceCMYKColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length)
+{
+ for (int i = 0; i < length; i++) {
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ }
+}
+
+void GfxDeviceCMYKColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length)
+{
+ for (int i = 0; i < length; i++) {
+ for (int j = 0; j < SPOT_NCOMPS+4; j++)
+ out[j] = 0;
+ out[0] = *in++;
+ out[1] = *in++;
+ out[2] = *in++;
+ out[3] = *in++;
+ out += (SPOT_NCOMPS+4);
+ }
+}
+
+void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = clip01(color->c[0]);
+ cmyk->m = clip01(color->c[1]);
+ cmyk->y = clip01(color->c[2]);
+ cmyk->k = clip01(color->c[3]);
+}
+
+void GfxDeviceCMYKColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ deviceN->c[0] = clip01(color->c[0]);
+ deviceN->c[1] = clip01(color->c[1]);
+ deviceN->c[2] = clip01(color->c[2]);
+ deviceN->c[3] = 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
+//------------------------------------------------------------------------
+
+GfxLabColorSpace::GfxLabColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ aMin = bMin = -100;
+ aMax = bMax = 100;
+}
+
+GfxLabColorSpace::~GfxLabColorSpace() {
+#ifdef USE_CMS
+ if (transform != NULL) {
+ if (transform->unref() == 0) delete transform;
+ }
+#endif
+}
+
+GfxColorSpace *GfxLabColorSpace::copy() {
+ GfxLabColorSpace *cs;
+
+ cs = new GfxLabColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->aMin = aMin;
+ cs->aMax = aMax;
+ cs->bMin = bMin;
+ cs->bMax = bMax;
+ cs->kr = kr;
+ cs->kg = kg;
+ cs->kb = kb;
+#ifdef USE_CMS
+ cs->transform = transform;
+ if (transform != NULL) transform->ref();
+#endif
+ return cs;
+}
+
+GfxColorSpace *GfxLabColorSpace::parse(Array *arr, GfxState *state) {
+ GfxLabColorSpace *cs;
+ Object obj1, obj2, obj3;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(errSyntaxWarning, -1, "Bad Lab color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxLabColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Range", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 4) {
+ obj2.arrayGet(0, &obj3);
+ cs->aMin = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->aMax = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->bMin = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(3, &obj3);
+ cs->bMax = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ obj1.free();
+
+ cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
+ xyzrgb[0][1] * cs->whiteY +
+ xyzrgb[0][2] * cs->whiteZ);
+ cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
+ xyzrgb[1][1] * cs->whiteY +
+ xyzrgb[1][2] * cs->whiteZ);
+ cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
+ xyzrgb[2][1] * cs->whiteY +
+ xyzrgb[2][2] * cs->whiteZ);
+
+#ifdef USE_CMS
+ cs->transform = (state != NULL) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform;
+ if (cs->transform != NULL) cs->transform->ref();
+#endif
+ return cs;
+}
+
+void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxRGB rgb;
+
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_GRAY) {
+ Guchar out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+
+ getXYZ(color, &in[0], &in[1], &in[2]);
+ transform->doTransform(in,out,1);
+ *gray = byteToCol(out[0]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ *gray = clip01((GfxColorComp)(0.299 * rgb.r +
+ 0.587 * rgb.g +
+ 0.114 * rgb.b + 0.5));
+}
+
+// convert L*a*b* to media XYZ color space
+// (not multiply by the white point)
+void GfxLabColorSpace::getXYZ(GfxColor *color,
+ double *pX, double *pY, double *pZ) {
+ double X, Y, Z;
+ double t1, t2;
+
+ t1 = (colToDbl(color->c[0]) + 16) / 116;
+ t2 = t1 + colToDbl(color->c[1]) / 500;
+ if (t2 >= (6.0 / 29.0)) {
+ X = t2 * t2 * t2;
+ } else {
+ X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
+ }
+ if (t1 >= (6.0 / 29.0)) {
+ Y = t1 * t1 * t1;
+ } else {
+ Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
+ }
+ t2 = t1 - colToDbl(color->c[2]) / 200;
+ if (t2 >= (6.0 / 29.0)) {
+ Z = t2 * t2 * t2;
+ } else {
+ Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
+ }
+ *pX = X;
+ *pY = Y;
+ *pZ = Z;
+}
+
+void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double X, Y, Z;
+ double r, g, b;
+
+ getXYZ(color, &X, &Y, &Z);
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_RGB) {
+ Guchar out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ transform->doTransform(in,out,1);
+ rgb->r = byteToCol(out[0]);
+ rgb->g = byteToCol(out[1]);
+ rgb->b = byteToCol(out[2]);
+ return;
+ } else if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) {
+ Guchar out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ transform->doTransform(in,out,1);
+ c = byteToDbl(out[0]);
+ m = byteToDbl(out[1]);
+ y = byteToDbl(out[2]);
+ k = byteToDbl(out[3]);
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+ rgb->r = clip01(dblToCol(r));
+ rgb->g = clip01(dblToCol(g));
+ rgb->b = clip01(dblToCol(b));
+ return;
+ }
+#endif
+ X *= whiteX;
+ Y *= whiteY;
+ Z *= whiteZ;
+ // convert XYZ to RGB, including gamut mapping and gamma correction
+ r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
+ g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
+ b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
+ rgb->r = dblToCol(sqrt(clip01(r * kr)));
+ rgb->g = dblToCol(sqrt(clip01(g * kg)));
+ rgb->b = dblToCol(sqrt(clip01(b * kb)));
+}
+
+void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxRGB rgb;
+ GfxColorComp c, m, y, k;
+
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) {
+ double in[gfxColorMaxComps];
+ Guchar out[gfxColorMaxComps];
+
+ getXYZ(color, &in[0], &in[1], &in[2]);
+ transform->doTransform(in,out,1);
+ cmyk->c = byteToCol(out[0]);
+ cmyk->m = byteToCol(out[1]);
+ cmyk->y = byteToCol(out[2]);
+ cmyk->k = byteToCol(out[3]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+void GfxLabColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
+void GfxLabColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+ if (aMin > 0) {
+ color->c[1] = dblToCol(aMin);
+ } else if (aMax < 0) {
+ color->c[1] = dblToCol(aMax);
+ } else {
+ color->c[1] = 0;
+ }
+ if (bMin > 0) {
+ color->c[2] = dblToCol(bMin);
+ } else if (bMax < 0) {
+ color->c[2] = dblToCol(bMax);
+ } else {
+ color->c[2] = 0;
+ }
+}
+
+void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel) {
+ decodeLow[0] = 0;
+ decodeRange[0] = 100;
+ decodeLow[1] = aMin;
+ decodeRange[1] = aMax - aMin;
+ decodeLow[2] = bMin;
+ decodeRange[2] = bMax - bMin;
+}
+
+//------------------------------------------------------------------------
+// GfxICCBasedColorSpace
+//------------------------------------------------------------------------
+
+class GfxICCBasedColorSpaceKey : public PopplerCacheKey
+{
+ public:
+ GfxICCBasedColorSpaceKey(int numA, int genA) : num(numA), gen(genA)
+ {
+ }
+
+ bool operator==(const PopplerCacheKey &key) const
+ {
+ const GfxICCBasedColorSpaceKey *k = static_cast<const GfxICCBasedColorSpaceKey*>(&key);
+ return k->num == num && k->gen == gen;
+ }
+
+ int num, gen;
+};
+
+class GfxICCBasedColorSpaceItem : public PopplerCacheItem
+{
+ public:
+ GfxICCBasedColorSpaceItem(GfxICCBasedColorSpace *csA)
+ {
+ cs = static_cast<GfxICCBasedColorSpace*>(csA->copy());
+ }
+
+ ~GfxICCBasedColorSpaceItem()
+ {
+ delete cs;
+ }
+
+ GfxICCBasedColorSpace *cs;
+};
+
+GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA) {
+ nComps = nCompsA;
+ alt = altA;
+ iccProfileStream = *iccProfileStreamA;
+ rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
+ rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
+#ifdef USE_CMS
+ transform = NULL;
+ lineTransform = NULL;
+#endif
+}
+
+GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
+ delete alt;
+#ifdef USE_CMS
+ if (transform != NULL) {
+ if (transform->unref() == 0) delete transform;
+ }
+ if (lineTransform != NULL) {
+ if (lineTransform->unref() == 0) delete lineTransform;
+ }
+#endif
+}
+
+GfxColorSpace *GfxICCBasedColorSpace::copy() {
+ GfxICCBasedColorSpace *cs;
+ int i;
+
+ cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
+ for (i = 0; i < 4; ++i) {
+ cs->rangeMin[i] = rangeMin[i];
+ cs->rangeMax[i] = rangeMax[i];
+ }
+#ifdef USE_CMS
+ cs->transform = transform;
+ if (transform != NULL) transform->ref();
+ cs->lineTransform = lineTransform;
+ if (lineTransform != NULL) lineTransform->ref();
+#endif
+ return cs;
+}
+
+GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState *state, int recursion) {
+ GfxICCBasedColorSpace *cs;
+ Ref iccProfileStreamA;
+ int nCompsA;
+ GfxColorSpace *altA;
+ Dict *dict;
+ Object obj1, obj2, obj3;
+ int i;
+
+ if (arr->getLength() < 2) {
+ error(errSyntaxError, -1, "Bad ICCBased color space");
+ return NULL;
+ }
+ arr->getNF(1, &obj1);
+ if (obj1.isRef()) {
+ iccProfileStreamA = obj1.getRef();
+ } else {
+ iccProfileStreamA.num = 0;
+ iccProfileStreamA.gen = 0;
+ }
+ obj1.free();
+#ifdef USE_CMS
+ // check cache
+ if (out && iccProfileStreamA.num > 0) {
+ GfxICCBasedColorSpaceKey k(iccProfileStreamA.num, iccProfileStreamA.gen);
+ GfxICCBasedColorSpaceItem *item = static_cast<GfxICCBasedColorSpaceItem *>(out->getIccColorSpaceCache()->lookup(k));
+ if (item != NULL)
+ {
+ cs = static_cast<GfxICCBasedColorSpace*>(item->cs->copy());
+ int transformIntent = cs->getIntent();
+ int cmsIntent = INTENT_RELATIVE_COLORIMETRIC;
+ if (state != NULL) {
+ const char *intent = state->getRenderingIntent();
+ if (intent != NULL) {
+ if (strcmp(intent, "AbsoluteColorimetric") == 0) {
+ cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC;
+ } else if (strcmp(intent, "Saturation") == 0) {
+ cmsIntent = INTENT_SATURATION;
+ } else if (strcmp(intent, "Perceptual") == 0) {
+ cmsIntent = INTENT_PERCEPTUAL;
+ }
+ }
+ }
+ if (transformIntent == cmsIntent) {
+ return cs;
+ }
+ delete cs;
+ }
+ }
+#endif
+ arr->get(1, &obj1);
+ if (!obj1.isStream()) {
+ error(errSyntaxWarning, -1, "Bad ICCBased color space (stream)");
+ obj1.free();
+ return NULL;
+ }
+ dict = obj1.streamGetDict();
+ if (!dict->lookup("N", &obj2)->isInt()) {
+ error(errSyntaxWarning, -1, "Bad ICCBased color space (N)");
+ obj2.free();
+ obj1.free();
+ return NULL;
+ }
+ nCompsA = obj2.getInt();
+ obj2.free();
+ if (nCompsA > 4) {
+ error(errSyntaxError, -1,
+ "ICCBased color space with too many ({0:d} > 4) components",
+ nCompsA);
+ nCompsA = 4;
+ }
+ if (dict->lookup("Alternate", &obj2)->isNull() ||
+ !(altA = GfxColorSpace::parse(NULL, &obj2, out, state, recursion + 1))) {
+ switch (nCompsA) {
+ case 1:
+ altA = new GfxDeviceGrayColorSpace();
+ break;
+ case 3:
+ altA = new GfxDeviceRGBColorSpace();
+ break;
+ case 4:
+ altA = new GfxDeviceCMYKColorSpace();
+ break;
+ default:
+ error(errSyntaxWarning, -1, "Bad ICCBased color space - invalid N");
+ obj2.free();
+ obj1.free();
+ return NULL;
+ }
+ }
+ obj2.free();
+ cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
+ if (dict->lookup("Range", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 2 * nCompsA) {
+ Object obj4;
+ for (i = 0; i < nCompsA; ++i) {
+ obj2.arrayGet(2*i, &obj3);
+ obj2.arrayGet(2*i+1, &obj4);
+ if (obj3.isNum() && obj4.isNum()) {
+ cs->rangeMin[i] = obj3.getNum();
+ cs->rangeMax[i] = obj4.getNum();
+ }
+ obj3.free();
+ obj4.free();
+ }
+ }
+ obj2.free();
+ obj1.free();
+
+#ifdef USE_CMS
+ arr->get(1, &obj1);
+ dict = obj1.streamGetDict();
+ Guchar *profBuf;
+ Stream *iccStream = obj1.getStream();
+ int length = 0;
+
+ profBuf = iccStream->toUnsignedChars(&length, 65536, 65536);
+ cmsHPROFILE hp = cmsOpenProfileFromMem(profBuf,length);
+ gfree(profBuf);
+ if (hp == 0) {
+ error(errSyntaxWarning, -1, "read ICCBased color space profile error");
+ } else {
+ cmsHPROFILE dhp = (state != NULL && state->getDisplayProfile() != NULL) ? state->getDisplayProfile() : displayProfile;
+ if (dhp == NULL) dhp = RGBProfile;
+ unsigned int cst = getCMSColorSpaceType(cmsGetColorSpace(hp));
+ unsigned int dNChannels = getCMSNChannels(cmsGetColorSpace(dhp));
+ unsigned int dcst = getCMSColorSpaceType(cmsGetColorSpace(dhp));
+ cmsHTRANSFORM transform;
+
+ int cmsIntent = INTENT_RELATIVE_COLORIMETRIC;
+ if (state != NULL) {
+ const char *intent = state->getRenderingIntent();
+ if (intent != NULL) {
+ if (strcmp(intent, "AbsoluteColorimetric") == 0) {
+ cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC;
+ } else if (strcmp(intent, "Saturation") == 0) {
+ cmsIntent = INTENT_SATURATION;
+ } else if (strcmp(intent, "Perceptual") == 0) {
+ cmsIntent = INTENT_PERCEPTUAL;
+ }
+ }
+ }
+ if ((transform = cmsCreateTransform(hp,
+ COLORSPACE_SH(cst) |CHANNELS_SH(nCompsA) | BYTES_SH(1),
+ dhp,
+ COLORSPACE_SH(dcst) |
+ CHANNELS_SH(dNChannels) | BYTES_SH(1),
+ cmsIntent, LCMS_FLAGS)) == 0) {
+ error(errSyntaxWarning, -1, "Can't create transform");
+ cs->transform = NULL;
+ } else {
+ cs->transform = new GfxColorTransform(transform, cmsIntent, cst, dcst);
+ }
+ if (dcst == PT_RGB || dcst == PT_CMYK) {
+ // create line transform only when the display is RGB type color space
+ if ((transform = cmsCreateTransform(hp,
+ CHANNELS_SH(nCompsA) | BYTES_SH(1),dhp,
+ (dcst == PT_RGB) ? TYPE_RGB_8 : TYPE_CMYK_8, cmsIntent, LCMS_FLAGS)) == 0) {
+ error(errSyntaxWarning, -1, "Can't create transform");
+ cs->lineTransform = NULL;
+ } else {
+ cs->lineTransform = new GfxColorTransform(transform, cmsIntent, cst, dcst);
+ }
+ }
+ cmsCloseProfile(hp);
+ }
+ obj1.free();
+ // put this colorSpace into cache
+ if (out && iccProfileStreamA.num > 0) {
+ GfxICCBasedColorSpaceKey *k = new GfxICCBasedColorSpaceKey(iccProfileStreamA.num, iccProfileStreamA.gen);
+ GfxICCBasedColorSpaceItem *item = new GfxICCBasedColorSpaceItem(cs);
+ out->getIccColorSpaceCache()->put(k, item);
+ }
+#endif
+ return cs;
+}
+
+void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+#ifdef USE_CMS
+ if (transform != 0 && transform->getTransformPixelType() == PT_GRAY) {
+ Guchar in[gfxColorMaxComps];
+ Guchar out[gfxColorMaxComps];
+
+ if (nComps == 3 && transform->getInputPixelType() == PT_Lab) {
+ in[0] = colToByte(dblToCol(colToDbl(color->c[0]) / 100.0));
+ in[1] = colToByte(dblToCol((colToDbl(color->c[1]) + 128.0) / 255.0));
+ in[2] = colToByte(dblToCol((colToDbl(color->c[2]) + 128.0) / 255.0));
+ } else {
+ for (int i = 0;i < nComps;i++) {
+ in[i] = colToByte(color->c[i]);
+ }
+ }
+ if (nComps <= 4) {
+ unsigned int key = 0;
+ for (int j = 0; j < nComps; j++) {
+ key = (key << 8) + in[j];
+ }
+ std::map<unsigned int, unsigned int>::iterator it = cmsCache.find(key);
+ if (it != cmsCache.end()) {
+ unsigned int value = it->second;
+ *gray = byteToCol(value & 0xff);
+ return;
+ }
+ }
+ transform->doTransform(in,out,1);
+ *gray = byteToCol(out[0]);
+ if (nComps <= 4 && cmsCache.size() <= CMSCACHE_LIMIT) {
+ unsigned int key = 0;
+ for (int j = 0; j < nComps; j++) {
+ key = (key << 8) + in[j];
+ }
+ unsigned int value = out[0];
+ cmsCache.insert(std::pair<unsigned int, unsigned int>(key, value));
+ }
+ } else {
+ GfxRGB rgb;
+ getRGB(color,&rgb);
+ *gray = clip01((GfxColorComp)(0.3 * rgb.r +
+ 0.59 * rgb.g +
+ 0.11 * rgb.b + 0.5));
+ }
+#else
+ alt->getGray(color, gray);
+#endif
+}
+
+void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+#ifdef USE_CMS
+ if (transform != 0 && transform->getTransformPixelType() == PT_RGB) {
+ Guchar in[gfxColorMaxComps];
+ Guchar out[gfxColorMaxComps];
+
+ if (nComps == 3 && transform->getInputPixelType() == PT_Lab) {
+ in[0] = colToByte(dblToCol(colToDbl(color->c[0]) / 100.0));
+ in[1] = colToByte(dblToCol((colToDbl(color->c[1]) + 128.0) / 255.0));
+ in[2] = colToByte(dblToCol((colToDbl(color->c[2]) + 128.0) / 255.0));
+ } else {
+ for (int i = 0;i < nComps;i++) {
+ in[i] = colToByte(color->c[i]);
+ }
+ }
+ if (nComps <= 4) {
+ unsigned int key = 0;
+ for (int j = 0; j < nComps; j++) {
+ key = (key << 8) + in[j];
+ }
+ std::map<unsigned int, unsigned int>::iterator it = cmsCache.find(key);
+ if (it != cmsCache.end()) {
+ unsigned int value = it->second;
+ rgb->r = byteToCol(value >> 16);
+ rgb->g = byteToCol((value >> 8) & 0xff);
+ rgb->b = byteToCol(value & 0xff);
+ return;
+ }
+ }
+ transform->doTransform(in,out,1);
+ rgb->r = byteToCol(out[0]);
+ rgb->g = byteToCol(out[1]);
+ rgb->b = byteToCol(out[2]);
+ if (nComps <= 4 && cmsCache.size() <= CMSCACHE_LIMIT) {
+ unsigned int key = 0;
+ for (int j = 0; j < nComps; j++) {
+ key = (key << 8) + in[j];
+ }
+ unsigned int value = (out[0] << 16) + (out[1] << 8) + out[2];
+ cmsCache.insert(std::pair<unsigned int, unsigned int>(key, value));
+ }
+ } else if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) {
+ Guchar in[gfxColorMaxComps];
+ Guchar out[gfxColorMaxComps];
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+ if (nComps == 3 && transform->getInputPixelType() == PT_Lab) {
+ in[0] = colToByte(dblToCol(colToDbl(color->c[0]) / 100.0));
+ in[1] = colToByte(dblToCol((colToDbl(color->c[1]) + 128.0) / 255.0));
+ in[2] = colToByte(dblToCol((colToDbl(color->c[2]) + 128.0) / 255.0));
+ } else {
+ for (int i = 0;i < nComps;i++) {
+ in[i] = colToByte(color->c[i]);
+ }
+ }
+ if (nComps <= 4) {
+ unsigned int key = 0;
+ for (int j = 0; j < nComps; j++) {
+ key = (key << 8) + in[j];
+ }
+ std::map<unsigned int, unsigned int>::iterator it = cmsCache.find(key);
+ if (it != cmsCache.end()) {
+ unsigned int value = it->second;
+ rgb->r = byteToCol(value >> 16);
+ rgb->g = byteToCol((value >> 8) & 0xff);
+ rgb->b = byteToCol(value & 0xff);
+ return;
+ }
+ }
+ transform->doTransform(in,out,1);
+ c = byteToDbl(out[0]);
+ m = byteToDbl(out[1]);
+ y = byteToDbl(out[2]);
+ k = byteToDbl(out[3]);
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+ rgb->r = clip01(dblToCol(r));
+ rgb->g = clip01(dblToCol(g));
+ rgb->b = clip01(dblToCol(b));
+ if (nComps <= 4 && cmsCache.size() <= CMSCACHE_LIMIT) {
+ unsigned int key = 0;
+ for (int j = 0; j < nComps; j++) {
+ key = (key << 8) + in[j];
+ }
+ unsigned int value = (dblToByte(r) << 16) + (dblToByte(g) << 8) + dblToByte(b);
+ cmsCache.insert(std::pair<unsigned int, unsigned int>(key, value));
+ }
+ } else {
+ alt->getRGB(color, rgb);
+ }
+#else
+ alt->getRGB(color, rgb);
+#endif
+}
+
+void GfxICCBasedColorSpace::getRGBLine(Guchar *in, unsigned int *out,
+ int length) {
+#ifdef USE_CMS
+ if (lineTransform != 0 && lineTransform->getTransformPixelType() == PT_RGB) {
+ Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar));
+ lineTransform->doTransform(in, tmp, length);
+ for (int i = 0; i < length; ++i) {
+ Guchar *current = tmp + (i * 3);
+ out[i] = (current[0] << 16) | (current[1] << 8) | current[2];
+ }
+ gfree(tmp);
+ } else {
+ alt->getRGBLine(in, out, length);
+ }
+#else
+ alt->getRGBLine(in, out, length);
+#endif
+}
+
+void GfxICCBasedColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) {
+#ifdef USE_CMS
+ if (lineTransform != 0 && lineTransform->getTransformPixelType() == PT_RGB) {
+ Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar));
+ lineTransform->doTransform(in, tmp, length);
+ Guchar *current = tmp;
+ for (int i = 0; i < length; ++i) {
+ *out++ = *current++;
+ *out++ = *current++;
+ *out++ = *current++;
+ }
+ gfree(tmp);
+ } else if (lineTransform != NULL && lineTransform->getTransformPixelType() == PT_CMYK) {
+ Guchar* tmp = (Guchar *)gmallocn(4 * length, sizeof(Guchar));
+ lineTransform->doTransform(in, tmp, length);
+ Guchar *current = tmp;
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+ for (int i = 0; i < length; ++i) {
+ c = byteToDbl(*current++);
+ m = byteToDbl(*current++);
+ y = byteToDbl(*current++);
+ k = byteToDbl(*current++);
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+ *out++ = dblToByte(r);
+ *out++ = dblToByte(g);
+ *out++ = dblToByte(b);
+ }
+ gfree(tmp);
+ } else {
+ alt->getRGBLine(in, out, length);
+ }
+#else
+ alt->getRGBLine(in, out, length);
+#endif
+}
+
+void GfxICCBasedColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) {
+#ifdef USE_CMS
+ if (lineTransform != 0 && lineTransform->getTransformPixelType() == PT_RGB) {
+ Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar));
+ lineTransform->doTransform(in, tmp, length);
+ Guchar *current = tmp;
+ for (int i = 0; i < length; ++i) {
+ *out++ = *current++;
+ *out++ = *current++;
+ *out++ = *current++;
+ *out++ = 255;
+ }
+ gfree(tmp);
+ } else {
+ alt->getRGBXLine(in, out, length);
+ }
+#else
+ alt->getRGBXLine(in, out, length);
+#endif
+}
+
+void GfxICCBasedColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) {
+#ifdef USE_CMS
+ if (lineTransform != NULL && lineTransform->getTransformPixelType() == PT_CMYK) {
+ transform->doTransform(in,out,length);
+ } else if (lineTransform != NULL && nComps != 4) {
+ GfxColorComp c, m, y, k;
+ Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar));
+ getRGBLine(in, tmp, length);
+ Guchar *p = tmp;
+ for (int i = 0; i < length; i++) {
+ c = byteToCol(255 - *p++);
+ m = byteToCol(255 - *p++);
+ y = byteToCol(255 - *p++);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ *out++ = colToByte(c - k);
+ *out++ = colToByte(m - k);
+ *out++ = colToByte(y - k);
+ *out++ = colToByte(k);
+ }
+ gfree(tmp);
+ } else {
+ alt->getCMYKLine(in, out, length);
+ }
+#else
+ alt->getCMYKLine(in, out, length);
+#endif
+}
+
+void GfxICCBasedColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) {
+#ifdef USE_CMS
+ if (lineTransform != NULL && lineTransform->getTransformPixelType() == PT_CMYK) {
+ Guchar* tmp = (Guchar *)gmallocn(4 * length, sizeof(Guchar));
+ transform->doTransform(in,tmp,length);
+ Guchar *p = tmp;
+ for (int i = 0; i < length; i++) {
+ for (int j = 0; j < 4; j++)
+ *out++ = *p++;
+ for (int j = 4; j < SPOT_NCOMPS+4; j++)
+ *out++ = 0;
+ }
+ gfree(tmp);
+ } else if (lineTransform != NULL && nComps != 4) {
+ GfxColorComp c, m, y, k;
+ Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar));
+ getRGBLine(in, tmp, length);
+ Guchar *p = tmp;
+ for (int i = 0; i < length; i++) {
+ for (int j = 0; j < SPOT_NCOMPS+4; j++)
+ out[j] = 0;
+ c = byteToCol(255 - *p++);
+ m = byteToCol(255 - *p++);
+ y = byteToCol(255 - *p++);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ out[0] = colToByte(c - k);
+ out[1] = colToByte(m - k);
+ out[2] = colToByte(y - k);
+ out[3] = colToByte(k);
+ out += (SPOT_NCOMPS+4);
+ }
+ gfree(tmp);
+ } else {
+ alt->getDeviceNLine(in, out, length);
+ }
+#else
+ alt->getDeviceNLine(in, out, length);
+#endif
+}
+
+void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+#ifdef USE_CMS
+ if (transform != NULL && transform->getTransformPixelType() == PT_CMYK) {
+ Guchar in[gfxColorMaxComps];
+ Guchar out[gfxColorMaxComps];
+
+ if (nComps == 3 && transform->getInputPixelType() == PT_Lab) {
+ in[0] = colToByte(dblToCol(colToDbl(color->c[0]) / 100.0));
+ in[1] = colToByte(dblToCol((colToDbl(color->c[1]) + 128.0) / 255.0));
+ in[2] = colToByte(dblToCol((colToDbl(color->c[2]) + 128.0) / 255.0));
+ } else {
+ for (int i = 0;i < nComps;i++) {
+ in[i] = colToByte(color->c[i]);
+ }
+ }
+ if (nComps <= 4) {
+ unsigned int key = 0;
+ for (int j = 0; j < nComps; j++) {
+ key = (key << 8) + in[j];
+ }
+ std::map<unsigned int, unsigned int>::iterator it = cmsCache.find(key);
+ if (it != cmsCache.end()) {
+ unsigned int value = it->second;
+ cmyk->c = byteToCol(value >> 24);
+ cmyk->m = byteToCol((value >> 16) & 0xff);
+ cmyk->y = byteToCol((value >> 8) & 0xff);
+ cmyk->k = byteToCol(value & 0xff);
+ return;
+ }
+ }
+ transform->doTransform(in,out,1);
+ cmyk->c = byteToCol(out[0]);
+ cmyk->m = byteToCol(out[1]);
+ cmyk->y = byteToCol(out[2]);
+ cmyk->k = byteToCol(out[3]);
+ if (nComps <= 4 && cmsCache.size() <= CMSCACHE_LIMIT) {
+ unsigned int key = 0;
+ for (int j = 0; j < nComps; j++) {
+ key = (key << 8) + in[j];
+ }
+ unsigned int value = (out[0] << 24) + (out[1] << 16) + (out[2] << 8) + out[3];
+ cmsCache.insert(std::pair<unsigned int, unsigned int>(key, value));
+ }
+ } else if (nComps != 4 && transform != NULL && transform->getTransformPixelType() == PT_RGB) {
+ GfxRGB rgb;
+ GfxColorComp c, m, y, k;
+
+ getRGB(color,&rgb);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+ } else {
+ alt->getCMYK(color, cmyk);
+ }
+#else
+ alt->getCMYK(color, cmyk);
+#endif
+}
+
+GBool GfxICCBasedColorSpace::useGetRGBLine() {
+#ifdef USE_CMS
+ return lineTransform != NULL || alt->useGetRGBLine();
+#else
+ return alt->useGetRGBLine();
+#endif
+}
+
+GBool GfxICCBasedColorSpace::useGetCMYKLine() {
+#ifdef USE_CMS
+ return lineTransform != NULL || alt->useGetCMYKLine();
+#else
+ return alt->useGetCMYKLine();
+#endif
+}
+
+GBool GfxICCBasedColorSpace::useGetDeviceNLine() {
+#ifdef USE_CMS
+ return lineTransform != NULL || alt->useGetDeviceNLine();
+#else
+ return alt->useGetDeviceNLine();
+#endif
+}
+
+void GfxICCBasedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
+void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) {
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ if (rangeMin[i] > 0) {
+ color->c[i] = dblToCol(rangeMin[i]);
+ } else if (rangeMax[i] < 0) {
+ color->c[i] = dblToCol(rangeMax[i]);
+ } else {
+ color->c[i] = 0;
+ }
+ }
+}
+
+void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
+ double *decodeRange,
+ int maxImgPixel) {
+ alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
+
+#if 0
+ // this is nominally correct, but some PDF files don't set the
+ // correct ranges in the ICCBased dict
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ decodeLow[i] = rangeMin[i];
+ decodeRange[i] = rangeMax[i] - rangeMin[i];
+ }
+#endif
+}
+
+//------------------------------------------------------------------------
+// GfxIndexedColorSpace
+//------------------------------------------------------------------------
+
+GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
+ int indexHighA) {
+ base = baseA;
+ indexHigh = indexHighA;
+ lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
+ sizeof(Guchar));
+ overprintMask = base->getOverprintMask();
+}
+
+GfxIndexedColorSpace::~GfxIndexedColorSpace() {
+ delete base;
+ gfree(lookup);
+}
+
+GfxColorSpace *GfxIndexedColorSpace::copy() {
+ GfxIndexedColorSpace *cs;
+
+ cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
+ memcpy(cs->lookup, lookup,
+ (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
+ return cs;
+}
+
+GfxColorSpace *GfxIndexedColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) {
+ GfxIndexedColorSpace *cs;
+ GfxColorSpace *baseA;
+ int indexHighA;
+ Object obj1;
+ char *s;
+ int n, i, j;
+
+ if (arr->getLength() != 4) {
+ error(errSyntaxWarning, -1, "Bad Indexed color space");
+ goto err1;
+ }
+ arr->get(1, &obj1);
+ if (!(baseA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
+ error(errSyntaxWarning, -1, "Bad Indexed color space (base color space)");
+ goto err2;
+ }
+ obj1.free();
+ if (!arr->get(2, &obj1)->isInt()) {
+ error(errSyntaxWarning, -1, "Bad Indexed color space (hival)");
+ delete baseA;
+ goto err2;
+ }
+ indexHighA = obj1.getInt();
+ if (indexHighA < 0 || indexHighA > 255) {
+ // the PDF spec requires indexHigh to be in [0,255] -- allowing
+ // values larger than 255 creates a security hole: if nComps *
+ // indexHigh is greater than 2^31, the loop below may overwrite
+ // past the end of the array
+ int previousValue = indexHighA;
+ if (indexHighA < 0) indexHighA = 0;
+ else indexHighA = 255;
+ error(errSyntaxWarning, -1, "Bad Indexed color space (invalid indexHigh value, was {0:d} using {1:d} to try to recover)", previousValue, indexHighA);
+ }
+ obj1.free();
+ cs = new GfxIndexedColorSpace(baseA, indexHighA);
+ arr->get(3, &obj1);
+ n = baseA->getNComps();
+ if (obj1.isStream()) {
+ obj1.streamReset();
+ for (i = 0; i <= indexHighA; ++i) {
+ const int readChars = obj1.streamGetChars(n, &cs->lookup[i*n]);
+ for (j = readChars; j < n; ++j) {
+ error(errSyntaxWarning, -1, "Bad Indexed color space (lookup table stream too short) padding with zeroes");
+ cs->lookup[i*n + j] = 0;
+ }
+ }
+ obj1.streamClose();
+ } else if (obj1.isString()) {
+ if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
+ error(errSyntaxWarning, -1, "Bad Indexed color space (lookup table string too short)");
+ goto err3;
+ }
+ s = obj1.getString()->getCString();
+ for (i = 0; i <= indexHighA; ++i) {
+ for (j = 0; j < n; ++j) {
+ cs->lookup[i*n + j] = (Guchar)*s++;
+ }
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Bad Indexed color space (lookup table)");
+ goto err3;
+ }
+ obj1.free();
+ return cs;
+
+ err3:
+ delete cs;
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
+ GfxColor *baseColor) {
+ Guchar *p;
+ double low[gfxColorMaxComps], range[gfxColorMaxComps];
+ int n, i;
+
+ n = base->getNComps();
+ base->getDefaultRanges(low, range, indexHigh);
+ const int idx = (int)(colToDbl(color->c[0]) + 0.5) * n;
+ if (likely((idx + n < (indexHigh + 1) * base->getNComps()) && idx >= 0)) {
+ p = &lookup[idx];
+ for (i = 0; i < n; ++i) {
+ baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ baseColor->c[i] = 0;
+ }
+ }
+ return baseColor;
+}
+
+void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxColor color2;
+
+ base->getGray(mapColorToBase(color, &color2), gray);
+}
+
+void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ GfxColor color2;
+
+ base->getRGB(mapColorToBase(color, &color2), rgb);
+}
+
+void GfxIndexedColorSpace::getRGBLine(Guchar *in, unsigned int *out, int length) {
+ Guchar *line;
+ int i, j, n;
+
+ n = base->getNComps();
+ line = (Guchar *) gmallocn (length, n);
+ for (i = 0; i < length; i++)
+ for (j = 0; j < n; j++)
+ line[i * n + j] = lookup[in[i] * n + j];
+
+ base->getRGBLine(line, out, length);
+
+ gfree (line);
+}
+
+void GfxIndexedColorSpace::getRGBLine(Guchar *in, Guchar *out, int length)
+{
+ Guchar *line;
+ int i, j, n;
+
+ n = base->getNComps();
+ line = (Guchar *) gmallocn (length, n);
+ for (i = 0; i < length; i++)
+ for (j = 0; j < n; j++)
+ line[i * n + j] = lookup[in[i] * n + j];
+
+ base->getRGBLine(line, out, length);
+
+ gfree (line);
+}
+
+void GfxIndexedColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length)
+{
+ Guchar *line;
+ int i, j, n;
+
+ n = base->getNComps();
+ line = (Guchar *) gmallocn (length, n);
+ for (i = 0; i < length; i++)
+ for (j = 0; j < n; j++)
+ line[i * n + j] = lookup[in[i] * n + j];
+
+ base->getRGBXLine(line, out, length);
+
+ gfree (line);
+}
+
+void GfxIndexedColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) {
+ Guchar *line;
+ int i, j, n;
+
+ n = base->getNComps();
+ line = (Guchar *) gmallocn (length, n);
+ for (i = 0; i < length; i++)
+ for (j = 0; j < n; j++)
+ line[i * n + j] = lookup[in[i] * n + j];
+
+ base->getCMYKLine(line, out, length);
+
+ gfree (line);
+}
+
+void GfxIndexedColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) {
+ Guchar *line;
+ int i, j, n;
+
+ n = base->getNComps();
+ line = (Guchar *) gmallocn (length, n);
+ for (i = 0; i < length; i++)
+ for (j = 0; j < n; j++)
+ line[i * n + j] = lookup[in[i] * n + j];
+
+ base->getDeviceNLine(line, out, length);
+
+ gfree (line);
+}
+
+void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxColor color2;
+
+ base->getCMYK(mapColorToBase(color, &color2), cmyk);
+}
+
+void GfxIndexedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxColor color2;
+
+ base->getDeviceN(mapColorToBase(color, &color2), deviceN);
+}
+
+void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+}
+
+void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
+ double *decodeRange,
+ int maxImgPixel) {
+ decodeLow[0] = 0;
+ decodeRange[0] = maxImgPixel;
+}
+
+//------------------------------------------------------------------------
+// GfxSeparationColorSpace
+//------------------------------------------------------------------------
+
+GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ name = nameA;
+ alt = altA;
+ func = funcA;
+ nonMarking = !name->cmp("None");
+ if (!name->cmp("Cyan")) {
+ overprintMask = 0x01;
+ } else if (!name->cmp("Magenta")) {
+ overprintMask = 0x02;
+ } else if (!name->cmp("Yellow")) {
+ overprintMask = 0x04;
+ } else if (!name->cmp("Black")) {
+ overprintMask = 0x08;
+ } else if (!name->cmp("All")) {
+ overprintMask = 0xffffffff;
+ }
+}
+
+GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA,
+ GfxColorSpace *altA,
+ Function *funcA,
+ GBool nonMarkingA,
+ Guint overprintMaskA,
+ int *mappingA) {
+ name = nameA;
+ alt = altA;
+ func = funcA;
+ nonMarking = nonMarkingA;
+ overprintMask = overprintMaskA;
+ mapping = mappingA;
+}
+
+GfxSeparationColorSpace::~GfxSeparationColorSpace() {
+ delete name;
+ delete alt;
+ delete func;
+ if (mapping != NULL)
+ gfree(mapping);
+}
+
+GfxColorSpace *GfxSeparationColorSpace::copy() {
+ int *mappingA = NULL;
+ if (mapping != NULL) {
+ mappingA = (int *) gmalloc(sizeof(int));
+ *mappingA = *mapping;
+ }
+ return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(),
+ nonMarking, overprintMask, mappingA);
+}
+
+//~ handle the 'All' and 'None' colorants
+GfxColorSpace *GfxSeparationColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) {
+ GfxSeparationColorSpace *cs;
+ GooString *nameA;
+ GfxColorSpace *altA;
+ Function *funcA;
+ Object obj1;
+
+ if (arr->getLength() != 4) {
+ error(errSyntaxWarning, -1, "Bad Separation color space");
+ goto err1;
+ }
+ if (!arr->get(1, &obj1)->isName()) {
+ error(errSyntaxWarning, -1, "Bad Separation color space (name)");
+ goto err2;
+ }
+ nameA = new GooString(obj1.getName());
+ obj1.free();
+ arr->get(2, &obj1);
+ if (!(altA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
+ error(errSyntaxWarning, -1, "Bad Separation color space (alternate color space)");
+ goto err3;
+ }
+ obj1.free();
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
+ goto err4;
+ }
+ if (funcA->getInputSize() != 1) {
+ error(errSyntaxWarning, -1, "Bad SeparationColorSpace function");
+ goto err5;
+ }
+ obj1.free();
+ cs = new GfxSeparationColorSpace(nameA, altA, funcA);
+ return cs;
+
+ err5:
+ delete funcA;
+ err4:
+ delete altA;
+ err3:
+ delete nameA;
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ double x;
+ double c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getGray(&color2, gray);
+}
+
+void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double x;
+ double c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getRGB(&color2, rgb);
+}
+
+void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ double x;
+ double c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getCMYK(&color2, cmyk);
+}
+
+void GfxSeparationColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ if (mapping == NULL || mapping[0] == -1) {
+ GfxCMYK cmyk;
+
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+ } else {
+ deviceN->c[mapping[0]] = color->c[0];
+ }
+}
+
+void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = gfxColorComp1;
+}
+
+void GfxSeparationColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+ if (nonMarking)
+ return;
+ mapping = (int *)gmalloc(sizeof(int));
+ switch (overprintMask) {
+ case 0x01:
+ *mapping = 0;
+ break;
+ case 0x02:
+ *mapping = 1;
+ break;
+ case 0x04:
+ *mapping = 2;
+ break;
+ case 0x08:
+ *mapping = 3;
+ break;
+ default:
+ Guint newOverprintMask = 0x10;
+ for (int i = 0; i < separationList->getLength(); i++) {
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+ if (!sepCS->getName()->cmp(name)) {
+ if (sepCS->getFunc()->hasDifferentResultSet(func)) {
+ error(errSyntaxWarning, -1,
+ "Different functions found for '{0:t}', convert immediately", name);
+ gfree(mapping);
+ mapping = NULL;
+ return;
+ }
+ *mapping = i+4;
+ overprintMask = newOverprintMask;
+ return;
+ }
+ newOverprintMask <<=1;
+ }
+ if (separationList->getLength() == maxSepComps) {
+ error(errSyntaxWarning, -1,
+ "Too many ({0:d}) spots, convert '{1:t}' immediately", maxSepComps, name);
+ gfree(mapping);
+ mapping = NULL;
+ return;
+ }
+ *mapping = separationList->getLength() + 4;
+ separationList->append(copy());
+ overprintMask = newOverprintMask;
+ break;
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceNColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GooString **namesA,
+ GfxColorSpace *altA,
+ Function *funcA,
+ GooList *sepsCSA) {
+ int i;
+
+ nComps = nCompsA;
+ alt = altA;
+ func = funcA;
+ sepsCS = sepsCSA;
+ nonMarking = gTrue;
+ overprintMask = 0;
+ mapping = NULL;
+ for (i = 0; i < nComps; ++i) {
+ names[i] = namesA[i];
+ if (names[i]->cmp("None")) {
+ nonMarking = gFalse;
+ }
+ if (!names[i]->cmp("Cyan")) {
+ overprintMask |= 0x01;
+ } else if (!names[i]->cmp("Magenta")) {
+ overprintMask |= 0x02;
+ } else if (!names[i]->cmp("Yellow")) {
+ overprintMask |= 0x04;
+ } else if (!names[i]->cmp("Black")) {
+ overprintMask |= 0x08;
+ } else if (!names[i]->cmp("All")) {
+ overprintMask = 0xffffffff;
+ } else {
+ overprintMask = 0x0f;
+ }
+ }
+}
+
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GooString **namesA,
+ GfxColorSpace *altA,
+ Function *funcA,
+ GooList *sepsCSA,
+ int *mappingA,
+ GBool nonMarkingA,
+ Guint overprintMaskA) {
+ int i;
+
+ nComps = nCompsA;
+ alt = altA;
+ func = funcA;
+ sepsCS = sepsCSA;
+ mapping = mappingA;
+ nonMarking = nonMarkingA;
+ overprintMask = overprintMaskA;
+ for (i = 0; i < nComps; ++i) {
+ names[i] = namesA[i]->copy();
+ }
+}
+
+GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ delete names[i];
+ }
+ delete alt;
+ delete func;
+ deleteGooList(sepsCS, GfxSeparationColorSpace);
+ if (mapping != NULL)
+ gfree(mapping);
+}
+
+GfxColorSpace *GfxDeviceNColorSpace::copy() {
+ int i;
+ int *mappingA = NULL;
+
+ GooList *sepsCSA = new GooList(sepsCS->getLength());
+ for (i = 0; i < sepsCS->getLength(); i++) {
+ GfxSeparationColorSpace *scs = (GfxSeparationColorSpace *) sepsCS->get(i);
+ if (likely(scs != NULL)) {
+ sepsCSA->append(scs->copy());
+ }
+ }
+ if (mapping != NULL) {
+ mappingA = (int *)gmalloc(sizeof(int) * nComps);
+ for (i = 0; i < nComps; i++)
+ mappingA[i] = mapping[i];
+ }
+ return new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(),
+ sepsCSA, mappingA, nonMarking, overprintMask);
+}
+
+//~ handle the 'None' colorant
+GfxColorSpace *GfxDeviceNColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) {
+ GfxDeviceNColorSpace *cs;
+ int nCompsA;
+ GooString *namesA[gfxColorMaxComps];
+ GfxColorSpace *altA;
+ Function *funcA;
+ Object obj1, obj2;
+ int i;
+ GooList *separationList = new GooList();
+
+ if (arr->getLength() != 4 && arr->getLength() != 5) {
+ error(errSyntaxWarning, -1, "Bad DeviceN color space");
+ goto err1;
+ }
+ if (!arr->get(1, &obj1)->isArray()) {
+ error(errSyntaxWarning, -1, "Bad DeviceN color space (names)");
+ goto err2;
+ }
+ nCompsA = obj1.arrayGetLength();
+ if (nCompsA > gfxColorMaxComps) {
+ error(errSyntaxWarning, -1, "DeviceN color space with too many ({0:d} > {1:d}) components",
+ nCompsA, gfxColorMaxComps);
+ nCompsA = gfxColorMaxComps;
+ }
+ for (i = 0; i < nCompsA; ++i) {
+ if (!obj1.arrayGet(i, &obj2)->isName()) {
+ error(errSyntaxWarning, -1, "Bad DeviceN color space (names)");
+ obj2.free();
+ goto err2;
+ }
+ namesA[i] = new GooString(obj2.getName());
+ obj2.free();
+ }
+ obj1.free();
+ arr->get(2, &obj1);
+ if (!(altA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
+ error(errSyntaxWarning, -1, "Bad DeviceN color space (alternate color space)");
+ goto err3;
+ }
+ obj1.free();
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
+ goto err4;
+ }
+ obj1.free();
+ if (arr->getLength() == 5) {
+ if (!arr->get(4, &obj1)->isDict()) {
+ error(errSyntaxWarning, -1, "Bad DeviceN color space (attributes)");
+ goto err4;
+ }
+ Dict *attribs = obj1.getDict();
+ attribs->lookup("Colorants", &obj2);
+ if (obj2.isDict()) {
+ Dict *colorants = obj2.getDict();
+ for (i = 0; i < colorants->getLength(); i++) {
+ Object obj3;
+ colorants->getVal(i, &obj3);
+ if (obj3.isArray()) {
+ separationList->append(GfxSeparationColorSpace::parse(res, obj3.getArray(), out, state, recursion));
+ } else {
+ obj3.free();
+ obj2.free();
+ error(errSyntaxWarning, -1, "Bad DeviceN color space (colorant value entry is not an Array)");
+ goto err4;
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ obj1.free();
+ }
+ cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, separationList);
+ return cs;
+
+ err4:
+ delete altA;
+ err3:
+ for (i = 0; i < nCompsA; ++i) {
+ delete namesA[i];
+ }
+ err2:
+ obj1.free();
+ err1:
+ delete separationList;
+ return NULL;
+}
+
+void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getGray(&color2, gray);
+}
+
+void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getRGB(&color2, rgb);
+}
+
+void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getCMYK(&color2, cmyk);
+}
+
+void GfxDeviceNColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ if (mapping == NULL) {
+ GfxCMYK cmyk;
+
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+ } else {
+ for (int j = 0; j < nComps; j++)
+ if (mapping[j] != -1)
+ deviceN->c[mapping[j]] = color->c[j];
+ }
+}
+
+void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) {
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ color->c[i] = gfxColorComp1;
+ }
+}
+
+void GfxDeviceNColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+ if (nonMarking) // None
+ return;
+ mapping = (int *)gmalloc(sizeof(int) * nComps);
+ Guint newOverprintMask = 0;
+ for (int i = 0; i < nComps; i++) {
+ if (!names[i]->cmp("None")) {
+ mapping[i] = -1;
+ } else if (!names[i]->cmp("Cyan")) {
+ newOverprintMask |= 0x01;
+ mapping[i] = 0;
+ } else if (!names[i]->cmp("Magenta")) {
+ newOverprintMask |= 0x02;
+ mapping[i] = 1;
+ } else if (!names[i]->cmp("Yellow")) {
+ newOverprintMask |= 0x04;
+ mapping[i] = 2;
+ } else if (!names[i]->cmp("Black")) {
+ newOverprintMask |= 0x08;
+ mapping[i] = 3;
+ } else {
+ Guint startOverprintMask = 0x10;
+ GBool found = gFalse;
+ Function *sepFunc = NULL;
+ if (nComps == 1)
+ sepFunc = func;
+ else {
+ for (int k = 0; k < sepsCS->getLength(); k++) {
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k);
+ if (!sepCS->getName()->cmp(names[i])) {
+ sepFunc = sepCS->getFunc();
+ break;
+ }
+ }
+ }
+ for (int j = 0; j < separationList->getLength(); j++) {
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(j);
+ if (!sepCS->getName()->cmp(names[i])) {
+ if (sepFunc != NULL && sepCS->getFunc()->hasDifferentResultSet(sepFunc)) {
+ error(errSyntaxWarning, -1,
+ "Different functions found for '{0:t}', convert immediately", names[i]);
+ gfree(mapping);
+ mapping = NULL;
+ overprintMask = 0xffffffff;
+ return;
+ }
+ mapping[i] = j+4;
+ newOverprintMask |= startOverprintMask;
+ found = gTrue;
+ break;
+ }
+ startOverprintMask <<=1;
+ }
+ if (!found) {
+ if (separationList->getLength() == maxSepComps) {
+ error(errSyntaxWarning, -1,
+ "Too many ({0:d}) spots, convert '{1:t}' immediately", maxSepComps, names[i]);
+ gfree(mapping);
+ mapping = NULL;
+ overprintMask = 0xffffffff;
+ return;
+ }
+ mapping[i] = separationList->getLength() + 4;
+ newOverprintMask |= startOverprintMask;
+ if (nComps == 1)
+ separationList->append(new GfxSeparationColorSpace(names[i]->copy(),alt->copy(), func->copy()));
+ else {
+ for (int k = 0; k < sepsCS->getLength(); k++) {
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k);
+ if (!sepCS->getName()->cmp(names[i])) {
+ found = gTrue;
+ separationList->append(sepCS->copy());
+ break;
+ }
+ }
+ if(!found) {
+ error(errSyntaxWarning, -1, "DeviceN has no suitable colorant");
+ gfree(mapping);
+ mapping = NULL;
+ overprintMask = 0xffffffff;
+ return;
+ }
+ }
+ }
+ }
+ }
+ overprintMask = newOverprintMask;
+}
+
+//------------------------------------------------------------------------
+// GfxPatternColorSpace
+//------------------------------------------------------------------------
+
+GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
+ under = underA;
+}
+
+GfxPatternColorSpace::~GfxPatternColorSpace() {
+ if (under) {
+ delete under;
+ }
+}
+
+GfxColorSpace *GfxPatternColorSpace::copy() {
+ return new GfxPatternColorSpace(under ? under->copy() :
+ (GfxColorSpace *)NULL);
+}
+
+GfxColorSpace *GfxPatternColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) {
+ GfxPatternColorSpace *cs;
+ GfxColorSpace *underA;
+ Object obj1;
+
+ if (arr->getLength() != 1 && arr->getLength() != 2) {
+ error(errSyntaxWarning, -1, "Bad Pattern color space");
+ return NULL;
+ }
+ underA = NULL;
+ if (arr->getLength() == 2) {
+ arr->get(1, &obj1);
+ if (!(underA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
+ error(errSyntaxWarning, -1, "Bad Pattern color space (underlying color space)");
+ obj1.free();
+ return NULL;
+ }
+ obj1.free();
+ }
+ cs = new GfxPatternColorSpace(underA);
+ return cs;
+}
+
+void GfxPatternColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = 0;
+}
+
+void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = rgb->g = rgb->b = 0;
+}
+
+void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = cmyk->m = cmyk->y = 0;
+ cmyk->k = 1;
+}
+
+void GfxPatternColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ deviceN->c[3] = 1;
+}
+
+void GfxPatternColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0]=0;
+}
+
+//------------------------------------------------------------------------
+// Pattern
+//------------------------------------------------------------------------
+
+GfxPattern::GfxPattern(int typeA) {
+ type = typeA;
+}
+
+GfxPattern::~GfxPattern() {
+}
+
+GfxPattern *GfxPattern::parse(GfxResources *res, Object *obj, OutputDev *out, GfxState *state) {
+ GfxPattern *pattern;
+ Object obj1;
+
+ if (obj->isDict()) {
+ obj->dictLookup("PatternType", &obj1);
+ } else if (obj->isStream()) {
+ obj->streamGetDict()->lookup("PatternType", &obj1);
+ } else {
+ return NULL;
+ }
+ pattern = NULL;
+ if (obj1.isInt() && obj1.getInt() == 1) {
+ pattern = GfxTilingPattern::parse(obj);
+ } else if (obj1.isInt() && obj1.getInt() == 2) {
+ pattern = GfxShadingPattern::parse(res, obj, out, state);
+ }
+ obj1.free();
+ return pattern;
+}
+
+//------------------------------------------------------------------------
+// GfxTilingPattern
+//------------------------------------------------------------------------
+
+GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
+ GfxTilingPattern *pat;
+ Dict *dict;
+ int paintTypeA, tilingTypeA;
+ double bboxA[4], matrixA[6];
+ double xStepA, yStepA;
+ Object resDictA;
+ Object obj1, obj2;
+ int i;
+
+ if (!patObj->isStream()) {
+ return NULL;
+ }
+ dict = patObj->streamGetDict();
+
+ if (dict->lookup("PaintType", &obj1)->isInt()) {
+ paintTypeA = obj1.getInt();
+ } else {
+ paintTypeA = 1;
+ error(errSyntaxWarning, -1, "Invalid or missing PaintType in pattern");
+ }
+ obj1.free();
+ if (dict->lookup("TilingType", &obj1)->isInt()) {
+ tilingTypeA = obj1.getInt();
+ } else {
+ tilingTypeA = 1;
+ error(errSyntaxWarning, -1, "Invalid or missing TilingType in pattern");
+ }
+ obj1.free();
+ bboxA[0] = bboxA[1] = 0;
+ bboxA[2] = bboxA[3] = 1;
+ if (dict->lookup("BBox", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ for (i = 0; i < 4; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ bboxA[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Invalid or missing BBox in pattern");
+ }
+ obj1.free();
+ if (dict->lookup("XStep", &obj1)->isNum()) {
+ xStepA = obj1.getNum();
+ } else {
+ xStepA = 1;
+ error(errSyntaxWarning, -1, "Invalid or missing XStep in pattern");
+ }
+ obj1.free();
+ if (dict->lookup("YStep", &obj1)->isNum()) {
+ yStepA = obj1.getNum();
+ } else {
+ yStepA = 1;
+ error(errSyntaxWarning, -1, "Invalid or missing YStep in pattern");
+ }
+ obj1.free();
+ if (!dict->lookup("Resources", &resDictA)->isDict()) {
+ resDictA.free();
+ resDictA.initNull();
+ error(errSyntaxWarning, -1, "Invalid or missing Resources in pattern");
+ }
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ for (i = 0; i < 6; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ matrixA[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
+ &resDictA, matrixA, patObj);
+ resDictA.free();
+ return pat;
+}
+
+GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
+ double *bboxA, double xStepA, double yStepA,
+ Object *resDictA, double *matrixA,
+ Object *contentStreamA):
+ GfxPattern(1)
+{
+ int i;
+
+ paintType = paintTypeA;
+ tilingType = tilingTypeA;
+ for (i = 0; i < 4; ++i) {
+ bbox[i] = bboxA[i];
+ }
+ xStep = xStepA;
+ yStep = yStepA;
+ resDictA->copy(&resDict);
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+ contentStreamA->copy(&contentStream);
+}
+
+GfxTilingPattern::~GfxTilingPattern() {
+ resDict.free();
+ contentStream.free();
+}
+
+GfxPattern *GfxTilingPattern::copy() {
+ return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
+ &resDict, matrix, &contentStream);
+}
+
+//------------------------------------------------------------------------
+// GfxShadingPattern
+//------------------------------------------------------------------------
+
+GfxShadingPattern *GfxShadingPattern::parse(GfxResources *res, Object *patObj, OutputDev *out, GfxState *state) {
+ Dict *dict;
+ GfxShading *shadingA;
+ double matrixA[6];
+ Object obj1, obj2;
+ int i;
+
+ if (!patObj->isDict()) {
+ return NULL;
+ }
+ dict = patObj->getDict();
+
+ dict->lookup("Shading", &obj1);
+ shadingA = GfxShading::parse(res, &obj1, out, state);
+ obj1.free();
+ if (!shadingA) {
+ return NULL;
+ }
+
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ for (i = 0; i < 6; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ matrixA[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ return new GfxShadingPattern(shadingA, matrixA);
+}
+
+GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
+ GfxPattern(2)
+{
+ int i;
+
+ shading = shadingA;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+}
+
+GfxShadingPattern::~GfxShadingPattern() {
+ delete shading;
+}
+
+GfxPattern *GfxShadingPattern::copy() {
+ return new GfxShadingPattern(shading->copy(), matrix);
+}
+
+//------------------------------------------------------------------------
+// GfxShading
+//------------------------------------------------------------------------
+
+GfxShading::GfxShading(int typeA) {
+ type = typeA;
+ colorSpace = NULL;
+}
+
+GfxShading::GfxShading(GfxShading *shading) {
+ int i;
+
+ type = shading->type;
+ colorSpace = shading->colorSpace->copy();
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ background.c[i] = shading->background.c[i];
+ }
+ hasBackground = shading->hasBackground;
+ xMin = shading->xMin;
+ yMin = shading->yMin;
+ xMax = shading->xMax;
+ yMax = shading->yMax;
+ hasBBox = shading->hasBBox;
+}
+
+GfxShading::~GfxShading() {
+ if (colorSpace) {
+ delete colorSpace;
+ }
+}
+
+GfxShading *GfxShading::parse(GfxResources *res, Object *obj, OutputDev *out, GfxState *state) {
+ GfxShading *shading;
+ Dict *dict;
+ int typeA;
+ Object obj1;
+
+ if (obj->isDict()) {
+ dict = obj->getDict();
+ } else if (obj->isStream()) {
+ dict = obj->streamGetDict();
+ } else {
+ return NULL;
+ }
+
+ if (!dict->lookup("ShadingType", &obj1)->isInt()) {
+ error(errSyntaxWarning, -1, "Invalid ShadingType in shading dictionary");
+ obj1.free();
+ return NULL;
+ }
+ typeA = obj1.getInt();
+ obj1.free();
+
+ switch (typeA) {
+ case 1:
+ shading = GfxFunctionShading::parse(res, dict, out, state);
+ break;
+ case 2:
+ shading = GfxAxialShading::parse(res, dict, out, state);
+ break;
+ case 3:
+ shading = GfxRadialShading::parse(res, dict, out, state);
+ break;
+ case 4:
+ if (obj->isStream()) {
+ shading = GfxGouraudTriangleShading::parse(res, 4, dict, obj->getStream(), out, state);
+ } else {
+ error(errSyntaxWarning, -1, "Invalid Type 4 shading object");
+ goto err1;
+ }
+ break;
+ case 5:
+ if (obj->isStream()) {
+ shading = GfxGouraudTriangleShading::parse(res, 5, dict, obj->getStream(), out, state);
+ } else {
+ error(errSyntaxWarning, -1, "Invalid Type 5 shading object");
+ goto err1;
+ }
+ break;
+ case 6:
+ if (obj->isStream()) {
+ shading = GfxPatchMeshShading::parse(res, 6, dict, obj->getStream(), out, state);
+ } else {
+ error(errSyntaxWarning, -1, "Invalid Type 6 shading object");
+ goto err1;
+ }
+ break;
+ case 7:
+ if (obj->isStream()) {
+ shading = GfxPatchMeshShading::parse(res, 7, dict, obj->getStream(), out, state);
+ } else {
+ error(errSyntaxWarning, -1, "Invalid Type 7 shading object");
+ goto err1;
+ }
+ break;
+ default:
+ error(errSyntaxWarning, -1, "Unimplemented shading type {0:d}", typeA);
+ goto err1;
+ }
+
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GBool GfxShading::init(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) {
+ Object obj1, obj2;
+ int i;
+
+ dict->lookup("ColorSpace", &obj1);
+ if (!(colorSpace = GfxColorSpace::parse(res, &obj1, out, state))) {
+ error(errSyntaxWarning, -1, "Bad color space in shading dictionary");
+ obj1.free();
+ return gFalse;
+ }
+ obj1.free();
+
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ background.c[i] = 0;
+ }
+ hasBackground = gFalse;
+ if (dict->lookup("Background", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == colorSpace->getNComps()) {
+ hasBackground = gTrue;
+ for (i = 0; i < colorSpace->getNComps(); ++i) {
+ background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
+ obj2.free();
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Bad Background in shading dictionary");
+ }
+ }
+ obj1.free();
+
+ xMin = yMin = xMax = yMax = 0;
+ hasBBox = gFalse;
+ if (dict->lookup("BBox", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == 4) {
+ Object obj3, obj4, obj5;
+ obj1.arrayGet(0, &obj2);
+ obj1.arrayGet(1, &obj3);
+ obj1.arrayGet(2, &obj4);
+ obj1.arrayGet(3, &obj5);
+ if (obj2.isNum() && obj3.isNum() && obj4.isNum() && obj5.isNum())
+ {
+ hasBBox = gTrue;
+ xMin = obj2.getNum();
+ yMin = obj3.getNum();
+ xMax = obj4.getNum();
+ yMax = obj5.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad BBox in shading dictionary (Values not numbers)");
+ }
+ obj2.free();
+ obj3.free();
+ obj4.free();
+ obj5.free();
+ } else {
+ error(errSyntaxWarning, -1, "Bad BBox in shading dictionary");
+ }
+ }
+ obj1.free();
+
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// GfxFunctionShading
+//------------------------------------------------------------------------
+
+GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double *matrixA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(1)
+{
+ int i;
+
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = shading->matrix[i];
+ }
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxFunctionShading::~GfxFunctionShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxFunctionShading *GfxFunctionShading::parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) {
+ GfxFunctionShading *shading;
+ double x0A, y0A, x1A, y1A;
+ double matrixA[6];
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = 0;
+ x1A = y1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
+ obj2.free();
+ matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps || nFuncsA <= 0) {
+ error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ goto err2;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ goto err1;
+ }
+ }
+ obj1.free();
+
+ shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
+ funcsA, nFuncsA);
+ if (!shading->init(res, dict, out, state)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err2:
+ obj2.free();
+ err1:
+ obj1.free();
+ return NULL;
+}
+
+GfxShading *GfxFunctionShading::copy() {
+ return new GfxFunctionShading(this);
+}
+
+void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
+ double in[2], out[gfxColorMaxComps];
+ int i;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ out[i] = 0;
+ }
+ in[0] = x;
+ in[1] = y;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(in, &out[i]);
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color->c[i] = dblToCol(out[i]);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxUnivariateShading
+//------------------------------------------------------------------------
+
+GfxUnivariateShading::GfxUnivariateShading(int typeA,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A):
+ GfxShading(typeA)
+{
+ int i;
+
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+ extend0 = extend0A;
+ extend1 = extend1A;
+
+ cacheSize = 0;
+ lastMatch = 0;
+ cacheBounds = NULL;
+ cacheCoeff = NULL;
+ cacheValues = NULL;
+}
+
+GfxUnivariateShading::GfxUnivariateShading(GfxUnivariateShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ t0 = shading->t0;
+ t1 = shading->t1;
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+ extend0 = shading->extend0;
+ extend1 = shading->extend1;
+
+ cacheSize = 0;
+ lastMatch = 0;
+ cacheBounds = NULL;
+ cacheCoeff = NULL;
+ cacheValues = NULL;
+}
+
+GfxUnivariateShading::~GfxUnivariateShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+
+ gfree (cacheBounds);
+}
+
+void GfxUnivariateShading::getColor(double t, GfxColor *color) {
+ double out[gfxColorMaxComps];
+ int i, nComps;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ nComps = nFuncs * funcs[0]->getOutputSize();
+
+ if (cacheSize > 0) {
+ double x, ix, *l, *u, *upper;
+
+ if (cacheBounds[lastMatch - 1] >= t) {
+ upper = std::lower_bound (cacheBounds, cacheBounds + lastMatch - 1, t);
+ lastMatch = upper - cacheBounds;
+ lastMatch = std::min<int>(std::max<int>(1, lastMatch), cacheSize - 1);
+ } else if (cacheBounds[lastMatch] < t) {
+ upper = std::lower_bound (cacheBounds + lastMatch + 1, cacheBounds + cacheSize, t);
+ lastMatch = upper - cacheBounds;
+ lastMatch = std::min<int>(std::max<int>(1, lastMatch), cacheSize - 1);
+ }
+
+ x = (t - cacheBounds[lastMatch-1]) * cacheCoeff[lastMatch];
+ ix = 1.0 - x;
+ u = cacheValues + lastMatch * nComps;
+ l = u - nComps;
+
+ for (i = 0; i < nComps; ++i) {
+ out[i] = ix * l[i] + x * u[i];
+ }
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ out[i] = 0;
+ }
+ for (i = 0; i < nFuncs; ++i) {
+ if (funcs[i]->getInputSize() != 1) {
+ error(errSyntaxWarning, -1, "Invalid shading function (input != 1)");
+ break;
+ }
+ funcs[i]->transform(&t, &out[i]);
+ }
+ }
+
+ for (i = 0; i < nComps; ++i) {
+ color->c[i] = dblToCol(out[i]);
+ }
+}
+
+void GfxUnivariateShading::setupCache(const Matrix *ctm,
+ double xMin, double yMin,
+ double xMax, double yMax) {
+ double sMin, sMax, tMin, tMax, upperBound;
+ int i, j, nComps, maxSize;
+
+ gfree (cacheBounds);
+ cacheBounds = NULL;
+ cacheSize = 0;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ nComps = nFuncs * funcs[0]->getOutputSize();
+
+ getParameterRange(&sMin, &sMax, xMin, yMin, xMax, yMax);
+ upperBound = ctm->norm() * getDistance(sMin, sMax);
+ maxSize = ceil(upperBound);
+ maxSize = std::max<int>(maxSize, 2);
+
+ {
+ double x[4], y[4];
+
+ ctm->transform(xMin, yMin, &x[0], &y[0]);
+ ctm->transform(xMax, yMin, &x[1], &y[1]);
+ ctm->transform(xMin, yMax, &x[2], &y[2]);
+ ctm->transform(xMax, yMax, &x[3], &y[3]);
+
+ xMin = xMax = x[0];
+ yMin = yMax = y[0];
+ for (i = 1; i < 4; i++) {
+ xMin = std::min<double>(xMin, x[i]);
+ yMin = std::min<double>(yMin, y[i]);
+ xMax = std::max<double>(xMax, x[i]);
+ yMax = std::max<double>(yMax, y[i]);
+ }
+ }
+
+ if (maxSize > (xMax-xMin) * (yMax-yMin)) {
+ return;
+ }
+
+ if (t0 < t1) {
+ tMin = t0 + sMin * (t1 - t0);
+ tMax = t0 + sMax * (t1 - t0);
+ } else {
+ tMin = t0 + sMax * (t1 - t0);
+ tMax = t0 + sMin * (t1 - t0);
+ }
+
+ cacheBounds = (double *)gmallocn(maxSize, sizeof(double) * (nComps + 2));
+ cacheCoeff = cacheBounds + maxSize;
+ cacheValues = cacheCoeff + maxSize;
+
+ if (cacheSize != 0) {
+ for (j = 0; j < cacheSize; ++j) {
+ cacheCoeff[j] = 1 / (cacheBounds[j+1] - cacheBounds[j]);
+ }
+ } else if (tMax != tMin) {
+ double step = (tMax - tMin) / (maxSize - 1);
+ double coeff = (maxSize - 1) / (tMax - tMin);
+
+ cacheSize = maxSize;
+
+ for (j = 0; j < cacheSize; ++j) {
+ cacheBounds[j] = tMin + j * step;
+ cacheCoeff[j] = coeff;
+
+ for (i = 0; i < nComps; ++i) {
+ cacheValues[j*nComps + i] = 0;
+ }
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&cacheBounds[j], &cacheValues[j*nComps + i]);
+ }
+ }
+ }
+
+ lastMatch = 1;
+}
+
+
+//------------------------------------------------------------------------
+// GfxAxialShading
+//------------------------------------------------------------------------
+
+GfxAxialShading::GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A):
+ GfxUnivariateShading(2, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A)
+{
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+}
+
+GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
+ GfxUnivariateShading(shading)
+{
+ x0 = shading->x0;
+ y0 = shading->y0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+}
+
+GfxAxialShading::~GfxAxialShading() {
+}
+
+GfxAxialShading *GfxAxialShading::parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) {
+ GfxAxialShading *shading;
+ double x0A, y0A, x1A, y1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = x1A = y1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ Object obj3, obj4, obj5;
+ obj1.arrayGet(0, &obj2);
+ obj1.arrayGet(1, &obj3);
+ obj1.arrayGet(2, &obj4);
+ obj1.arrayGet(3, &obj5);
+ if (obj2.isNum() && obj3.isNum() && obj4.isNum() && obj5.isNum()) {
+ x0A = obj2.getNum();
+ y0A = obj3.getNum();
+ x1A = obj4.getNum();
+ y1A = obj5.getNum();
+ }
+ obj2.free();
+ obj3.free();
+ obj4.free();
+ obj5.free();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid Coords in shading dictionary");
+ goto err1;
+ }
+ obj1.free();
+
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ Object obj3;
+ obj1.arrayGet(0, &obj2);
+ obj1.arrayGet(1, &obj3);
+ if (obj2.isNum() && obj3.isNum()) {
+ t0A = obj2.getNum();
+ t1A = obj3.getNum();
+ }
+ obj2.free();
+ obj3.free();
+ }
+ obj1.free();
+
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps || nFuncsA == 0) {
+ error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ obj1.free();
+
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isBool()) {
+ extend0A = obj2.getBool();
+ } else {
+ error(errSyntaxWarning, -1, "Invalid axial shading extend (0)");
+ }
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ if (obj2.isBool()) {
+ extend1A = obj2.getBool();
+ } else {
+ error(errSyntaxWarning, -1, "Invalid axial shading extend (1)");
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+ if (!shading->init(res, dict, out, state)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxAxialShading::copy() {
+ return new GfxAxialShading(this);
+}
+
+double GfxAxialShading::getDistance(double sMin, double sMax) {
+ double xMin, yMin, xMax, yMax;
+
+ xMin = x0 + sMin * (x1 - x0);
+ yMin = y0 + sMin * (y1 - y0);
+ xMax = x0 + sMax * (x1 - x0);
+ yMax = y0 + sMax * (y1 - y0);
+
+ return hypot(xMax-xMin, yMax-yMin);
+}
+
+void GfxAxialShading::getParameterRange(double *lower, double *upper,
+ double xMin, double yMin,
+ double xMax, double yMax) {
+ double pdx, pdy, invsqnorm, tdx, tdy, t, range[2];
+
+ // Linear gradients are orthogonal to the line passing through their
+ // extremes. Because of convexity, the parameter range can be
+ // computed as the convex hull (one the real line) of the parameter
+ // values of the 4 corners of the box.
+ //
+ // The parameter value t for a point (x,y) can be computed as:
+ //
+ // t = (p2 - p1) . (x,y) / |p2 - p1|^2
+ //
+ // t0 is the t value for the top left corner
+ // tdx is the difference between left and right corners
+ // tdy is the difference between top and bottom corners
+
+ pdx = x1 - x0;
+ pdy = y1 - y0;
+ invsqnorm = 1.0 / (pdx * pdx + pdy * pdy);
+ pdx *= invsqnorm;
+ pdy *= invsqnorm;
+
+ t = (xMin - x0) * pdx + (yMin - y0) * pdy;
+ tdx = (xMax - xMin) * pdx;
+ tdy = (yMax - yMin) * pdy;
+
+ // Because of the linearity of the t value, tdx can simply be added
+ // the t0 to move along the top edge. After this, *lower and *upper
+ // represent the parameter range for the top edge, so extending it
+ // to include the whole box simply requires adding tdy to the
+ // correct extreme.
+
+ range[0] = range[1] = t;
+ if (tdx < 0)
+ range[0] += tdx;
+ else
+ range[1] += tdx;
+
+ if (tdy < 0)
+ range[0] += tdy;
+ else
+ range[1] += tdy;
+
+ *lower = std::max<double>(0., std::min<double>(1., range[0]));
+ *upper = std::max<double>(0., std::min<double>(1., range[1]));
+}
+
+//------------------------------------------------------------------------
+// GfxRadialShading
+//------------------------------------------------------------------------
+
+#ifndef RADIAL_EPSILON
+#define RADIAL_EPSILON (1. / 1024 / 1024)
+#endif
+
+GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
+ double x1A, double y1A, double r1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A):
+ GfxUnivariateShading(3, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A)
+{
+ x0 = x0A;
+ y0 = y0A;
+ r0 = r0A;
+ x1 = x1A;
+ y1 = y1A;
+ r1 = r1A;
+}
+
+GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
+ GfxUnivariateShading(shading)
+{
+ x0 = shading->x0;
+ y0 = shading->y0;
+ r0 = shading->r0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ r1 = shading->r1;
+}
+
+GfxRadialShading::~GfxRadialShading() {
+}
+
+GfxRadialShading *GfxRadialShading::parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) {
+ GfxRadialShading *shading;
+ double x0A, y0A, r0A, x1A, y1A, r1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = r0A = x1A = y1A = r1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ r0A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(4, &obj2)->getNum();
+ obj2.free();
+ r1A = obj1.arrayGet(5, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid Coords in shading dictionary");
+ goto err1;
+ }
+ obj1.free();
+
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ obj1.free();
+
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
+ }
+ obj1.free();
+
+ shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+ if (!shading->init(res, dict, out, state)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxRadialShading::copy() {
+ return new GfxRadialShading(this);
+}
+
+double GfxRadialShading::getDistance(double sMin, double sMax) {
+ double xMin, yMin, rMin, xMax, yMax, rMax;
+
+ xMin = x0 + sMin * (x1 - x0);
+ yMin = y0 + sMin * (y1 - y0);
+ rMin = r0 + sMin * (r1 - r0);
+
+ xMax = x0 + sMax * (x1 - x0);
+ yMax = y0 + sMax * (y1 - y0);
+ rMax = r0 + sMax * (r1 - r0);
+
+ return hypot(xMax-xMin, yMax-yMin) + fabs(rMax-rMin);
+}
+
+// extend range, adapted from cairo, radialExtendRange
+static GBool
+radialExtendRange (double range[2], double value, GBool valid)
+{
+ if (!valid)
+ range[0] = range[1] = value;
+ else if (value < range[0])
+ range[0] = value;
+ else if (value > range[1])
+ range[1] = value;
+
+ return gTrue;
+}
+
+inline void radialEdge(double num, double den, double delta, double lower, double upper,
+ double dr, double mindr, GBool &valid, double *range)
+{
+ if (fabs (den) >= RADIAL_EPSILON) {
+ double t_edge, v;
+ t_edge = (num) / (den);
+ v = t_edge * (delta);
+ if (t_edge * dr >= mindr && (lower) <= v && v <= (upper))
+ valid = radialExtendRange (range, t_edge, valid);
+ }
+}
+
+inline void radialCorner1(double x, double y, double &b, double dx, double dy, double cr,
+ double dr, double mindr, GBool &valid, double *range)
+{
+ b = (x) * dx + (y) * dy + cr * dr;
+ if (fabs (b) >= RADIAL_EPSILON) {
+ double t_corner;
+ double x2 = (x) * (x);
+ double y2 = (y) * (y);
+ double cr2 = (cr) * (cr);
+ double c = x2 + y2 - cr2;
+
+ t_corner = 0.5 * c / b;
+ if (t_corner * dr >= mindr)
+ valid = radialExtendRange (range, t_corner, valid);
+ }
+}
+
+inline void radialCorner2(double x, double y, double a, double &b, double &c, double &d, double dx, double dy, double cr,
+ double inva, double dr, double mindr, GBool &valid, double *range)
+{
+ b = (x) * dx + (y) * dy + cr * dr;
+ c = (x) * (x) + (y) * (y) - cr * cr;
+ d = b * b - a * c;
+ if (d >= 0) {
+ double t_corner;
+
+ d = sqrt (d);
+ t_corner = (b + d) * inva;
+ if (t_corner * dr >= mindr)
+ valid = radialExtendRange (range, t_corner, valid);
+ t_corner = (b - d) * inva;
+ if (t_corner * dr >= mindr)
+ valid = radialExtendRange (range, t_corner, valid);
+ }
+}
+void GfxRadialShading::getParameterRange(double *lower, double *upper,
+ double xMin, double yMin,
+ double xMax, double yMax) {
+ double cx, cy, cr, dx, dy, dr;
+ double a, x_focus, y_focus;
+ double mindr, minx, miny, maxx, maxy;
+ double range[2];
+ GBool valid;
+
+ // A radial pattern is considered degenerate if it can be
+ // represented as a solid or clear pattern. This corresponds to one
+ // of the two cases:
+ //
+ // 1) The radii are both very small:
+ // |dr| < FLT_EPSILON && min (r0, r1) < FLT_EPSILON
+ //
+ // 2) The two circles have about the same radius and are very
+ // close to each other (approximately a cylinder gradient that
+ // doesn't move with the parameter):
+ // |dr| < FLT_EPSILON && max (|dx|, |dy|) < 2 * FLT_EPSILON
+
+ if (xMin >= xMax || yMin >=yMax ||
+ (fabs (r0 - r1) < RADIAL_EPSILON &&
+ (std::min<double>(r0, r1) < RADIAL_EPSILON ||
+ std::max<double>(fabs (x0 - x1), fabs (y0 - y1)) < 2 * RADIAL_EPSILON))) {
+ *lower = *upper = 0;
+ return;
+ }
+
+ range[0] = range[1] = 0;
+ valid = gFalse;
+
+ x_focus = y_focus = 0; // silence gcc
+
+ cx = x0;
+ cy = y0;
+ cr = r0;
+ dx = x1 - cx;
+ dy = y1 - cy;
+ dr = r1 - cr;
+
+ // translate by -(cx, cy) to simplify computations
+ xMin -= cx;
+ yMin -= cy;
+ xMax -= cx;
+ yMax -= cy;
+
+ // enlarge boundaries slightly to avoid rounding problems in the
+ // parameter range computation
+ xMin -= RADIAL_EPSILON;
+ yMin -= RADIAL_EPSILON;
+ xMax += RADIAL_EPSILON;
+ yMax += RADIAL_EPSILON;
+
+ // enlarge boundaries even more to avoid rounding problems when
+ // testing if a point belongs to the box
+ minx = xMin - RADIAL_EPSILON;
+ miny = yMin - RADIAL_EPSILON;
+ maxx = xMax + RADIAL_EPSILON;
+ maxy = yMax + RADIAL_EPSILON;
+
+ // we dont' allow negative radiuses, so we will be checking that
+ // t*dr >= mindr to consider t valid
+ mindr = -(cr + RADIAL_EPSILON);
+
+ // After the previous transformations, the start circle is centered
+ // in the origin and has radius cr. A 1-unit change in the t
+ // parameter corresponds to dx,dy,dr changes in the x,y,r of the
+ // circle (center coordinates, radius).
+ //
+ // To compute the minimum range needed to correctly draw the
+ // pattern, we start with an empty range and extend it to include
+ // the circles touching the bounding box or within it.
+
+ // Focus, the point where the circle has radius == 0.
+ //
+ // r = cr + t * dr = 0
+ // t = -cr / dr
+ //
+ // If the radius is constant (dr == 0) there is no focus (the
+ // gradient represents a cylinder instead of a cone).
+ if (fabs (dr) >= RADIAL_EPSILON) {
+ double t_focus;
+
+ t_focus = -cr / dr;
+ x_focus = t_focus * dx;
+ y_focus = t_focus * dy;
+ if (minx <= x_focus && x_focus <= maxx &&
+ miny <= y_focus && y_focus <= maxy)
+ {
+ valid = radialExtendRange (range, t_focus, valid);
+ }
+ }
+
+ // Circles externally tangent to box edges.
+ //
+ // All circles have center in (dx, dy) * t
+ //
+ // If the circle is tangent to the line defined by the edge of the
+ // box, then at least one of the following holds true:
+ //
+ // (dx*t) + (cr + dr*t) == x0 (left edge)
+ // (dx*t) - (cr + dr*t) == x1 (right edge)
+ // (dy*t) + (cr + dr*t) == y0 (top edge)
+ // (dy*t) - (cr + dr*t) == y1 (bottom edge)
+ //
+ // The solution is only valid if the tangent point is actually on
+ // the edge, i.e. if its y coordinate is in [y0,y1] for left/right
+ // edges and if its x coordinate is in [x0,x1] for top/bottom edges.
+ //
+ // For the first equation:
+ //
+ // (dx + dr) * t = x0 - cr
+ // t = (x0 - cr) / (dx + dr)
+ // y = dy * t
+ //
+ // in the code this becomes:
+ //
+ // t_edge = (num) / (den)
+ // v = (delta) * t_edge
+ //
+ // If the denominator in t is 0, the pattern is tangent to a line
+ // parallel to the edge under examination. The corner-case where the
+ // boundary line is the same as the edge is handled by the focus
+ // point case and/or by the a==0 case.
+
+ // circles tangent (externally) to left/right/top/bottom edge
+ radialEdge(xMin - cr, dx + dr, dy, miny, maxy, dr, mindr, valid, range);
+ radialEdge(xMax + cr, dx - dr, dy, miny, maxy, dr, mindr, valid, range);
+ radialEdge(yMin - cr, dy + dr, dx, minx, maxx, dr, mindr, valid, range);
+ radialEdge(yMax + cr, dy - dr, dx, minx, maxx, dr, mindr, valid, range);
+
+ // Circles passing through a corner.
+ //
+ // A circle passing through the point (x,y) satisfies:
+ //
+ // (x-t*dx)^2 + (y-t*dy)^2 == (cr + t*dr)^2
+ //
+ // If we set:
+ // a = dx^2 + dy^2 - dr^2
+ // b = x*dx + y*dy + cr*dr
+ // c = x^2 + y^2 - cr^2
+ // we have:
+ // a*t^2 - 2*b*t + c == 0
+
+ a = dx * dx + dy * dy - dr * dr;
+ if (fabs (a) < RADIAL_EPSILON * RADIAL_EPSILON) {
+ double b;
+
+ // Ensure that gradients with both a and dr small are
+ // considered degenerate.
+ // The floating point version of the degeneracy test implemented
+ // in _radial_pattern_is_degenerate() is:
+ //
+ // 1) The circles are practically the same size:
+ // |dr| < RADIAL_EPSILON
+ // AND
+ // 2a) The circles are both very small:
+ // min (r0, r1) < RADIAL_EPSILON
+ // OR
+ // 2b) The circles are very close to each other:
+ // max (|dx|, |dy|) < 2 * RADIAL_EPSILON
+ //
+ // Assuming that the gradient is not degenerate, we want to
+ // show that |a| < RADIAL_EPSILON^2 implies |dr| >= RADIAL_EPSILON.
+ //
+ // If the gradient is not degenerate yet it has |dr| <
+ // RADIAL_EPSILON, (2b) is false, thus:
+ //
+ // max (|dx|, |dy|) >= 2*RADIAL_EPSILON
+ // which implies:
+ // 4*RADIAL_EPSILON^2 <= max (|dx|, |dy|)^2 <= dx^2 + dy^2
+ //
+ // From the definition of a, we get:
+ // a = dx^2 + dy^2 - dr^2 < RADIAL_EPSILON^2
+ // dx^2 + dy^2 - RADIAL_EPSILON^2 < dr^2
+ // 3*RADIAL_EPSILON^2 < dr^2
+ //
+ // which is inconsistent with the hypotheses, thus |dr| <
+ // RADIAL_EPSILON is false or the gradient is degenerate.
+
+ assert (fabs (dr) >= RADIAL_EPSILON);
+
+ // If a == 0, all the circles are tangent to a line in the
+ // focus point. If this line is within the box extents, we
+ // should add the circle with infinite radius, but this would
+ // make the range unbounded. We will be limiting the range to
+ // [0,1] anyway, so we simply add the biggest legitimate
+ // circle (it happens for 0 or for 1).
+ if (dr < 0) {
+ valid = radialExtendRange (range, 0, valid);
+ } else {
+ valid = radialExtendRange (range, 1, valid);
+ }
+
+ // Nondegenerate, nonlimit circles passing through the corners.
+ //
+ // a == 0 && a*t^2 - 2*b*t + c == 0
+ //
+ // t = c / (2*b)
+ //
+ // The b == 0 case has just been handled, so we only have to
+ // compute this if b != 0.
+
+ // circles touching each corner
+ radialCorner1(xMin, yMin, b, dx, dy, cr, dr, mindr, valid, range);
+ radialCorner1(xMin, yMax, b, dx, dy, cr, dr, mindr, valid, range);
+ radialCorner1(xMax, yMin, b, dx, dy, cr, dr, mindr, valid, range);
+ radialCorner1(xMax, yMax, b, dx, dy, cr, dr, mindr, valid, range);
+ } else {
+ double inva, b, c, d;
+
+ inva = 1 / a;
+
+ // Nondegenerate, nonlimit circles passing through the corners.
+ //
+ // a != 0 && a*t^2 - 2*b*t + c == 0
+ //
+ // t = (b +- sqrt (b*b - a*c)) / a
+ //
+ // If the argument of sqrt() is negative, then no circle
+ // passes through the corner.
+
+ // circles touching each corner
+ radialCorner2(xMin, yMin, a, b, c, d, dx, dy, cr, inva, dr, mindr, valid, range);
+ radialCorner2(xMin, yMax, a, b, c, d, dx, dy, cr, inva, dr, mindr, valid, range);
+ radialCorner2(xMax, yMin, a, b, c, d, dx, dy, cr, inva, dr, mindr, valid, range);
+ radialCorner2(xMax, yMax, a, b, c, d, dx, dy, cr, inva, dr, mindr, valid, range);
+ }
+
+ *lower = std::max<double>(0., std::min<double>(1., range[0]));
+ *upper = std::max<double>(0., std::min<double>(1., range[1]));
+}
+
+//------------------------------------------------------------------------
+// GfxShadingBitBuf
+//------------------------------------------------------------------------
+
+class GfxShadingBitBuf {
+public:
+
+ GfxShadingBitBuf(Stream *strA);
+ ~GfxShadingBitBuf();
+ GBool getBits(int n, Guint *val);
+ void flushBits();
+
+private:
+
+ Stream *str;
+ int bitBuf;
+ int nBits;
+};
+
+GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) {
+ str = strA;
+ str->reset();
+ bitBuf = 0;
+ nBits = 0;
+}
+
+GfxShadingBitBuf::~GfxShadingBitBuf() {
+ str->close();
+}
+
+GBool GfxShadingBitBuf::getBits(int n, Guint *val) {
+ int x;
+
+ if (nBits >= n) {
+ x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
+ nBits -= n;
+ } else {
+ x = 0;
+ if (nBits > 0) {
+ x = bitBuf & ((1 << nBits) - 1);
+ n -= nBits;
+ nBits = 0;
+ }
+ while (n > 0) {
+ if ((bitBuf = str->getChar()) == EOF) {
+ nBits = 0;
+ return gFalse;
+ }
+ if (n >= 8) {
+ x = (x << 8) | bitBuf;
+ n -= 8;
+ } else {
+ x = (x << n) | (bitBuf >> (8 - n));
+ nBits = 8 - n;
+ n = 0;
+ }
+ }
+ }
+ *val = x;
+ return gTrue;
+}
+
+void GfxShadingBitBuf::flushBits() {
+ bitBuf = 0;
+ nBits = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxGouraudTriangleShading
+//------------------------------------------------------------------------
+
+GfxGouraudTriangleShading::GfxGouraudTriangleShading(
+ int typeA,
+ GfxGouraudVertex *verticesA, int nVerticesA,
+ int (*trianglesA)[3], int nTrianglesA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(typeA)
+{
+ int i;
+
+ vertices = verticesA;
+ nVertices = nVerticesA;
+ triangles = trianglesA;
+ nTriangles = nTrianglesA;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxGouraudTriangleShading::GfxGouraudTriangleShading(
+ GfxGouraudTriangleShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ nVertices = shading->nVertices;
+ vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex));
+ memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
+ nTriangles = shading->nTriangles;
+ triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
+ memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
+ int i;
+
+ gfree(vertices);
+ gfree(triangles);
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(GfxResources *res, int typeA,
+ Dict *dict,
+ Stream *str,
+ OutputDev *out, GfxState *gfxState) {
+ GfxGouraudTriangleShading *shading;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ int coordBits, compBits, flagBits, vertsPerRow, nRows;
+ double xMin, xMax, yMin, yMax;
+ double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
+ double xMul, yMul;
+ double cMul[gfxColorMaxComps];
+ GfxGouraudVertex *verticesA;
+ int (*trianglesA)[3];
+ int nComps, nVerticesA, nTrianglesA, vertSize, triSize;
+ Guint x, y, flag;
+ Guint c[gfxColorMaxComps];
+ GfxShadingBitBuf *bitBuf;
+ Object obj1, obj2;
+ int i, j, k, state;
+
+ if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+ coordBits = obj1.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid BitsPerCoordinate in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+ compBits = obj1.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid BitsPerComponent in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ flagBits = vertsPerRow = 0; // make gcc happy
+ if (typeA == 4) {
+ if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+ flagBits = obj1.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid BitsPerFlag in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ } else {
+ if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
+ vertsPerRow = obj1.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid VerticesPerRow in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ }
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() >= 6) {
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
+ yMin = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
+ for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+ cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
+ }
+ nComps = i;
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+
+ if (!dict->lookup("Function", &obj1)->isNull()) {
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ } else {
+ nFuncsA = 0;
+ }
+ obj1.free();
+
+ nVerticesA = nTrianglesA = 0;
+ verticesA = NULL;
+ trianglesA = NULL;
+ vertSize = triSize = 0;
+ state = 0;
+ flag = 0; // make gcc happy
+ bitBuf = new GfxShadingBitBuf(str);
+ while (1) {
+ if (typeA == 4) {
+ if (!bitBuf->getBits(flagBits, &flag)) {
+ break;
+ }
+ }
+ if (!bitBuf->getBits(coordBits, &x) ||
+ !bitBuf->getBits(coordBits, &y)) {
+ break;
+ }
+ for (i = 0; i < nComps; ++i) {
+ if (!bitBuf->getBits(compBits, &c[i])) {
+ break;
+ }
+ }
+ if (i < nComps) {
+ break;
+ }
+ if (nVerticesA == vertSize) {
+ int oldVertSize = vertSize;
+ vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
+ verticesA = (GfxGouraudVertex *)
+ greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
+ memset(verticesA + oldVertSize, 0, (vertSize - oldVertSize) * sizeof(GfxGouraudVertex));
+ }
+ verticesA[nVerticesA].x = xMin + xMul * (double)x;
+ verticesA[nVerticesA].y = yMin + yMul * (double)y;
+ for (i = 0; i < nComps; ++i) {
+ verticesA[nVerticesA].color.c[i] =
+ dblToCol(cMin[i] + cMul[i] * (double)c[i]);
+ }
+ ++nVerticesA;
+ bitBuf->flushBits();
+ if (typeA == 4) {
+ if (state == 0 || state == 1) {
+ ++state;
+ } else if (state == 2 || flag > 0) {
+ if (nTrianglesA == triSize) {
+ triSize = (triSize == 0) ? 16 : 2 * triSize;
+ trianglesA = (int (*)[3])
+ greallocn(trianglesA, triSize * 3, sizeof(int));
+ }
+ if (state == 2) {
+ trianglesA[nTrianglesA][0] = nVerticesA - 3;
+ trianglesA[nTrianglesA][1] = nVerticesA - 2;
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ ++state;
+ } else if (flag == 1) {
+ trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
+ trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ } else { // flag == 2
+ trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
+ trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ }
+ ++nTrianglesA;
+ } else { // state == 3 && flag == 0
+ state = 1;
+ }
+ }
+ }
+ delete bitBuf;
+ if (typeA == 5) {
+ nRows = nVerticesA / vertsPerRow;
+ nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
+ trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
+ k = 0;
+ for (i = 0; i < nRows - 1; ++i) {
+ for (j = 0; j < vertsPerRow - 1; ++j) {
+ trianglesA[k][0] = i * vertsPerRow + j;
+ trianglesA[k][1] = i * vertsPerRow + j+1;
+ trianglesA[k][2] = (i+1) * vertsPerRow + j;
+ ++k;
+ trianglesA[k][0] = i * vertsPerRow + j+1;
+ trianglesA[k][1] = (i+1) * vertsPerRow + j;
+ trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
+ ++k;
+ }
+ }
+ }
+
+ shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
+ trianglesA, nTrianglesA,
+ funcsA, nFuncsA);
+ if (!shading->init(res, dict, out, gfxState)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxGouraudTriangleShading::copy() {
+ return new GfxGouraudTriangleShading(this);
+}
+
+void GfxGouraudTriangleShading::getTriangle(
+ int i,
+ double *x0, double *y0, GfxColor *color0,
+ double *x1, double *y1, GfxColor *color1,
+ double *x2, double *y2, GfxColor *color2) {
+ double in;
+ double out[gfxColorMaxComps];
+ int v, j;
+
+ assert(!isParameterized());
+
+ v = triangles[i][0];
+ *x0 = vertices[v].x;
+ *y0 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color0->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color0 = vertices[v].color;
+ }
+ v = triangles[i][1];
+ *x1 = vertices[v].x;
+ *y1 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color1->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color1 = vertices[v].color;
+ }
+ v = triangles[i][2];
+ *x2 = vertices[v].x;
+ *y2 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color2->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color2 = vertices[v].color;
+ }
+}
+
+void GfxGouraudTriangleShading::getParameterizedColor(double t, GfxColor *color) {
+ double out[gfxColorMaxComps];
+
+ for (int j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&t, &out[j]);
+ }
+ for (int j = 0; j < gfxColorMaxComps; ++j) {
+ color->c[j] = dblToCol(out[j]);
+ }
+}
+
+void GfxGouraudTriangleShading::getTriangle(int i,
+ double *x0, double *y0, double *color0,
+ double *x1, double *y1, double *color1,
+ double *x2, double *y2, double *color2) {
+ int v;
+
+ assert(isParameterized());
+
+ v = triangles[i][0];
+ *x0 = vertices[v].x;
+ *y0 = vertices[v].y;
+ *color0 = colToDbl(vertices[v].color.c[0]);
+ v = triangles[i][1];
+ *x1 = vertices[v].x;
+ *y1 = vertices[v].y;
+ *color1 = colToDbl(vertices[v].color.c[0]);
+ v = triangles[i][2];
+ *x2 = vertices[v].x;
+ *y2 = vertices[v].y;
+ *color2 = colToDbl(vertices[v].color.c[0]);
+}
+
+//------------------------------------------------------------------------
+// GfxPatchMeshShading
+//------------------------------------------------------------------------
+
+GfxPatchMeshShading::GfxPatchMeshShading(int typeA,
+ GfxPatch *patchesA, int nPatchesA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(typeA)
+{
+ int i;
+
+ patches = patchesA;
+ nPatches = nPatchesA;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ nPatches = shading->nPatches;
+ patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch));
+ memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch));
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxPatchMeshShading::~GfxPatchMeshShading() {
+ int i;
+
+ gfree(patches);
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Dict *dict,
+ Stream *str, OutputDev *out, GfxState *state) {
+ GfxPatchMeshShading *shading;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ int coordBits, compBits, flagBits;
+ double xMin, xMax, yMin, yMax;
+ double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
+ double xMul, yMul;
+ double cMul[gfxColorMaxComps];
+ GfxPatch *patchesA, *p;
+ int nComps, nPatchesA, patchesSize, nPts, nColors;
+ Guint flag;
+ double x[16], y[16];
+ Guint xi, yi;
+ double c[4][gfxColorMaxComps];
+ Guint ci;
+ GfxShadingBitBuf *bitBuf;
+ Object obj1, obj2;
+ int i, j;
+
+ if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+ coordBits = obj1.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid BitsPerCoordinate in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+ compBits = obj1.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid BitsPerComponent in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+ flagBits = obj1.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid BitsPerFlag in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() >= 6) {
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
+ yMin = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
+ for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+ cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
+ }
+ nComps = i;
+ } else {
+ error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+
+ if (!dict->lookup("Function", &obj1)->isNull()) {
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ } else {
+ nFuncsA = 0;
+ }
+ obj1.free();
+
+ nPatchesA = 0;
+ patchesA = NULL;
+ patchesSize = 0;
+ bitBuf = new GfxShadingBitBuf(str);
+ while (1) {
+ if (!bitBuf->getBits(flagBits, &flag)) {
+ break;
+ }
+ if (typeA == 6) {
+ switch (flag) {
+ case 0: nPts = 12; nColors = 4; break;
+ case 1:
+ case 2:
+ case 3:
+ default: nPts = 8; nColors = 2; break;
+ }
+ } else {
+ switch (flag) {
+ case 0: nPts = 16; nColors = 4; break;
+ case 1:
+ case 2:
+ case 3:
+ default: nPts = 12; nColors = 2; break;
+ }
+ }
+ for (i = 0; i < nPts; ++i) {
+ if (!bitBuf->getBits(coordBits, &xi) ||
+ !bitBuf->getBits(coordBits, &yi)) {
+ break;
+ }
+ x[i] = xMin + xMul * (double)xi;
+ y[i] = yMin + yMul * (double)yi;
+ }
+ if (i < nPts) {
+ break;
+ }
+ for (i = 0; i < nColors; ++i) {
+ for (j = 0; j < nComps; ++j) {
+ if (!bitBuf->getBits(compBits, &ci)) {
+ break;
+ }
+ c[i][j] = cMin[j] + cMul[j] * (double)ci;
+ if( nFuncsA == 0 ) {
+ // ... and colorspace values can also be stored into doubles.
+ // They will be casted later.
+ c[i][j] = dblToCol(c[i][j]);
+ }
+ }
+ if (j < nComps) {
+ break;
+ }
+ }
+ if (i < nColors) {
+ break;
+ }
+ if (nPatchesA == patchesSize) {
+ int oldPatchesSize = patchesSize;
+ patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
+ patchesA = (GfxPatch *)greallocn(patchesA,
+ patchesSize, sizeof(GfxPatch));
+ memset(patchesA + oldPatchesSize, 0, (patchesSize - oldPatchesSize) * sizeof(GfxPatch));
+ }
+ p = &patchesA[nPatchesA];
+ if (typeA == 6) {
+ switch (flag) {
+ case 0:
+ p->x[0][0] = x[0];
+ p->y[0][0] = y[0];
+ p->x[0][1] = x[1];
+ p->y[0][1] = y[1];
+ p->x[0][2] = x[2];
+ p->y[0][2] = y[2];
+ p->x[0][3] = x[3];
+ p->y[0][3] = y[3];
+ p->x[1][3] = x[4];
+ p->y[1][3] = y[4];
+ p->x[2][3] = x[5];
+ p->y[2][3] = y[5];
+ p->x[3][3] = x[6];
+ p->y[3][3] = y[6];
+ p->x[3][2] = x[7];
+ p->y[3][2] = y[7];
+ p->x[3][1] = x[8];
+ p->y[3][1] = y[8];
+ p->x[3][0] = x[9];
+ p->y[3][0] = y[9];
+ p->x[2][0] = x[10];
+ p->y[2][0] = y[10];
+ p->x[1][0] = x[11];
+ p->y[1][0] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = c[0][j];
+ p->color[0][1].c[j] = c[1][j];
+ p->color[1][1].c[j] = c[2][j];
+ p->color[1][0].c[j] = c[3][j];
+ }
+ break;
+ case 1:
+ if (nPatchesA == 0) {
+ goto err1;
+ }
+ p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
+ p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
+ p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
+ p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 2:
+ if (nPatchesA == 0) {
+ goto err1;
+ }
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
+ p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
+ p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
+ p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 3:
+ if (nPatchesA == 0) {
+ goto err1;
+ }
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
+ p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
+ p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
+ p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
+ p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
+ p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ }
+ } else {
+ switch (flag) {
+ case 0:
+ p->x[0][0] = x[0];
+ p->y[0][0] = y[0];
+ p->x[0][1] = x[1];
+ p->y[0][1] = y[1];
+ p->x[0][2] = x[2];
+ p->y[0][2] = y[2];
+ p->x[0][3] = x[3];
+ p->y[0][3] = y[3];
+ p->x[1][3] = x[4];
+ p->y[1][3] = y[4];
+ p->x[2][3] = x[5];
+ p->y[2][3] = y[5];
+ p->x[3][3] = x[6];
+ p->y[3][3] = y[6];
+ p->x[3][2] = x[7];
+ p->y[3][2] = y[7];
+ p->x[3][1] = x[8];
+ p->y[3][1] = y[8];
+ p->x[3][0] = x[9];
+ p->y[3][0] = y[9];
+ p->x[2][0] = x[10];
+ p->y[2][0] = y[10];
+ p->x[1][0] = x[11];
+ p->y[1][0] = y[11];
+ p->x[1][1] = x[12];
+ p->y[1][1] = y[12];
+ p->x[1][2] = x[13];
+ p->y[1][2] = y[13];
+ p->x[2][2] = x[14];
+ p->y[2][2] = y[14];
+ p->x[2][1] = x[15];
+ p->y[2][1] = y[15];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = c[0][j];
+ p->color[0][1].c[j] = c[1][j];
+ p->color[1][1].c[j] = c[2][j];
+ p->color[1][0].c[j] = c[3][j];
+ }
+ break;
+ case 1:
+ if (nPatchesA == 0) {
+ goto err1;
+ }
+ p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
+ p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
+ p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
+ p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 2:
+ if (nPatchesA == 0) {
+ goto err1;
+ }
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
+ p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
+ p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
+ p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 3:
+ if (nPatchesA == 0) {
+ goto err1;
+ }
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
+ p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
+ p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
+ p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
+ p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
+ p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ }
+ }
+ ++nPatchesA;
+ bitBuf->flushBits();
+ }
+ delete bitBuf;
+
+ if (typeA == 6) {
+ for (i = 0; i < nPatchesA; ++i) {
+ p = &patchesA[i];
+ p->x[1][1] = (-4 * p->x[0][0]
+ +6 * (p->x[0][1] + p->x[1][0])
+ -2 * (p->x[0][3] + p->x[3][0])
+ +3 * (p->x[3][1] + p->x[1][3])
+ - p->x[3][3]) / 9;
+ p->y[1][1] = (-4 * p->y[0][0]
+ +6 * (p->y[0][1] + p->y[1][0])
+ -2 * (p->y[0][3] + p->y[3][0])
+ +3 * (p->y[3][1] + p->y[1][3])
+ - p->y[3][3]) / 9;
+ p->x[1][2] = (-4 * p->x[0][3]
+ +6 * (p->x[0][2] + p->x[1][3])
+ -2 * (p->x[0][0] + p->x[3][3])
+ +3 * (p->x[3][2] + p->x[1][0])
+ - p->x[3][0]) / 9;
+ p->y[1][2] = (-4 * p->y[0][3]
+ +6 * (p->y[0][2] + p->y[1][3])
+ -2 * (p->y[0][0] + p->y[3][3])
+ +3 * (p->y[3][2] + p->y[1][0])
+ - p->y[3][0]) / 9;
+ p->x[2][1] = (-4 * p->x[3][0]
+ +6 * (p->x[3][1] + p->x[2][0])
+ -2 * (p->x[3][3] + p->x[0][0])
+ +3 * (p->x[0][1] + p->x[2][3])
+ - p->x[0][3]) / 9;
+ p->y[2][1] = (-4 * p->y[3][0]
+ +6 * (p->y[3][1] + p->y[2][0])
+ -2 * (p->y[3][3] + p->y[0][0])
+ +3 * (p->y[0][1] + p->y[2][3])
+ - p->y[0][3]) / 9;
+ p->x[2][2] = (-4 * p->x[3][3]
+ +6 * (p->x[3][2] + p->x[2][3])
+ -2 * (p->x[3][0] + p->x[0][3])
+ +3 * (p->x[0][2] + p->x[2][0])
+ - p->x[0][0]) / 9;
+ p->y[2][2] = (-4 * p->y[3][3]
+ +6 * (p->y[3][2] + p->y[2][3])
+ -2 * (p->y[3][0] + p->y[0][3])
+ +3 * (p->y[0][2] + p->y[2][0])
+ - p->y[0][0]) / 9;
+ }
+ }
+
+ shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
+ funcsA, nFuncsA);
+ if (!shading->init(res, dict, out, state)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+void GfxPatchMeshShading::getParameterizedColor(double t, GfxColor *color) {
+ double out[gfxColorMaxComps];
+
+ for (int j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&t, &out[j]);
+ }
+ for (int j = 0; j < gfxColorMaxComps; ++j) {
+ color->c[j] = dblToCol(out[j]);
+ }
+}
+
+GfxShading *GfxPatchMeshShading::copy() {
+ return new GfxPatchMeshShading(this);
+}
+
+//------------------------------------------------------------------------
+// GfxImageColorMap
+//------------------------------------------------------------------------
+
+GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
+ GfxColorSpace *colorSpaceA) {
+ GfxIndexedColorSpace *indexedCS;
+ GfxSeparationColorSpace *sepCS;
+ int maxPixel, indexHigh;
+ Guchar *indexedLookup;
+ Function *sepFunc;
+ Object obj;
+ double x[gfxColorMaxComps];
+ double y[gfxColorMaxComps];
+ int i, j, k;
+ double mapped;
+ GBool useByteLookup;
+
+ ok = gTrue;
+
+ // bits per component and color space
+ bits = bitsA;
+ maxPixel = (1 << bits) - 1;
+ colorSpace = colorSpaceA;
+
+ // this is a hack to support 16 bits images, everywhere
+ // we assume a component fits in 8 bits, with this hack
+ // we treat 16 bit images as 8 bit ones until it's fixed correctly.
+ // The hack has another part on ImageStream::getLine
+ if (maxPixel > 255) maxPixel = 255;
+
+ // initialize
+ for (k = 0; k < gfxColorMaxComps; ++k) {
+ lookup[k] = NULL;
+ lookup2[k] = NULL;
+ }
+ byte_lookup = NULL;
+
+ // get decode map
+ if (decode->isNull()) {
+ nComps = colorSpace->getNComps();
+ colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
+ } else if (decode->isArray()) {
+ nComps = decode->arrayGetLength() / 2;
+ if (nComps < colorSpace->getNComps()) {
+ goto err1;
+ }
+ if (nComps > colorSpace->getNComps()) {
+ error(errSyntaxWarning, -1, "Too many elements in Decode array");
+ nComps = colorSpace->getNComps();
+ }
+ for (i = 0; i < nComps; ++i) {
+ decode->arrayGet(2*i, &obj);
+ if (!obj.isNum()) {
+ goto err2;
+ }
+ decodeLow[i] = obj.getNum();
+ obj.free();
+ decode->arrayGet(2*i+1, &obj);
+ if (!obj.isNum()) {
+ goto err2;
+ }
+ decodeRange[i] = obj.getNum() - decodeLow[i];
+ obj.free();
+ }
+ } else {
+ goto err1;
+ }
+
+ // Construct a lookup table -- this stores pre-computed decoded
+ // values for each component, i.e., the result of applying the
+ // decode mapping to each possible image pixel component value.
+ for (k = 0; k < nComps; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ lookup[k][i] = dblToCol(decodeLow[k] +
+ (i * decodeRange[k]) / maxPixel);
+ }
+ }
+
+ // Optimization: for Indexed and Separation color spaces (which have
+ // only one component), we pre-compute a second lookup table with
+ // color values
+ colorSpace2 = NULL;
+ nComps2 = 0;
+ useByteLookup = gFalse;
+ switch (colorSpace->getMode()) {
+ case csIndexed:
+ // Note that indexHigh may not be the same as maxPixel --
+ // Distiller will remove unused palette entries, resulting in
+ // indexHigh < maxPixel.
+ indexedCS = (GfxIndexedColorSpace *)colorSpace;
+ colorSpace2 = indexedCS->getBase();
+ indexHigh = indexedCS->getIndexHigh();
+ nComps2 = colorSpace2->getNComps();
+ indexedLookup = indexedCS->getLookup();
+ colorSpace2->getDefaultRanges(x, y, indexHigh);
+ if (colorSpace2->useGetGrayLine() || colorSpace2->useGetRGBLine() || colorSpace2->useGetCMYKLine() || colorSpace2->useGetDeviceNLine()) {
+ byte_lookup = (Guchar *)gmallocn ((maxPixel + 1), nComps2);
+ useByteLookup = gTrue;
+ }
+ for (k = 0; k < nComps2; ++k) {
+ lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
+ if (j < 0) {
+ j = 0;
+ } else if (j > indexHigh) {
+ j = indexHigh;
+ }
+
+ mapped = x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k];
+ lookup2[k][i] = dblToCol(mapped);
+ if (useByteLookup)
+ byte_lookup[i * nComps2 + k] = (Guchar) (mapped * 255);
+ }
+ }
+ break;
+ case csSeparation:
+ sepCS = (GfxSeparationColorSpace *)colorSpace;
+ colorSpace2 = sepCS->getAlt();
+ nComps2 = colorSpace2->getNComps();
+ sepFunc = sepCS->getFunc();
+ if (colorSpace2->useGetGrayLine() || colorSpace2->useGetRGBLine() || colorSpace2->useGetCMYKLine() || colorSpace2->useGetDeviceNLine()) {
+ byte_lookup = (Guchar *)gmallocn ((maxPixel + 1), nComps2);
+ useByteLookup = gTrue;
+ }
+ for (k = 0; k < nComps2; ++k) {
+ lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
+ sepFunc->transform(x, y);
+ lookup2[k][i] = dblToCol(y[k]);
+ if (useByteLookup)
+ byte_lookup[i*nComps2 + k] = (Guchar) (y[k] * 255);
+ }
+ }
+ break;
+ default:
+ if (colorSpace->useGetGrayLine() || colorSpace->useGetRGBLine() || colorSpace->useGetCMYKLine() || colorSpace->useGetDeviceNLine()) {
+ byte_lookup = (Guchar *)gmallocn ((maxPixel + 1), nComps);
+ useByteLookup = gTrue;
+ }
+ for (k = 0; k < nComps; ++k) {
+ lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ mapped = decodeLow[k] + (i * decodeRange[k]) / maxPixel;
+ lookup2[k][i] = dblToCol(mapped);
+ if (useByteLookup) {
+ int byte;
+
+ byte = (int) (mapped * 255.0 + 0.5);
+ if (byte < 0)
+ byte = 0;
+ else if (byte > 255)
+ byte = 255;
+ byte_lookup[i * nComps + k] = byte;
+ }
+ }
+ }
+ }
+
+ return;
+
+ err2:
+ obj.free();
+ err1:
+ ok = gFalse;
+}
+
+GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
+ int n, i, k;
+
+ colorSpace = colorMap->colorSpace->copy();
+ bits = colorMap->bits;
+ nComps = colorMap->nComps;
+ nComps2 = colorMap->nComps2;
+ colorSpace2 = NULL;
+ for (k = 0; k < gfxColorMaxComps; ++k) {
+ lookup[k] = NULL;
+ }
+ n = 1 << bits;
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ } else if (colorSpace->getMode() == csSeparation) {
+ colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ } else {
+ for (k = 0; k < nComps; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ }
+ if (colorMap->byte_lookup) {
+ int nc = colorSpace2 ? nComps2 : nComps;
+
+ byte_lookup = (Guchar *)gmallocn (n, nc);
+ memcpy(byte_lookup, colorMap->byte_lookup, n * nc);
+ }
+ for (i = 0; i < nComps; ++i) {
+ decodeLow[i] = colorMap->decodeLow[i];
+ decodeRange[i] = colorMap->decodeRange[i];
+ }
+ ok = gTrue;
+}
+
+GfxImageColorMap::~GfxImageColorMap() {
+ int i;
+
+ delete colorSpace;
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ gfree(lookup[i]);
+ gfree(lookup2[i]);
+ }
+ gfree(byte_lookup);
+}
+
+void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) {
+ GfxColor color;
+ int i;
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = lookup2[i][x[0]];
+ }
+ colorSpace2->getGray(&color, gray);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup2[i][x[i]];
+ }
+ colorSpace->getGray(&color, gray);
+ }
+}
+
+void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
+ GfxColor color;
+ int i;
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = lookup2[i][x[0]];
+ }
+ colorSpace2->getRGB(&color, rgb);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup2[i][x[i]];
+ }
+ colorSpace->getRGB(&color, rgb);
+ }
+}
+
+void GfxImageColorMap::getGrayLine(Guchar *in, Guchar *out, int length) {
+ int i, j;
+ Guchar *inp, *tmp_line;
+
+ if ((colorSpace2 && !colorSpace2->useGetGrayLine ()) ||
+ (!colorSpace2 && !colorSpace->useGetGrayLine ())) {
+ GfxGray gray;
+
+ inp = in;
+ for (i = 0; i < length; i++) {
+ getGray (inp, &gray);
+ out[i] = colToByte(gray);
+ inp += nComps;
+ }
+ return;
+ }
+
+ switch (colorSpace->getMode()) {
+ case csIndexed:
+ case csSeparation:
+ tmp_line = (Guchar *) gmallocn (length, nComps2);
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < nComps2; j++) {
+ tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j];
+ }
+ }
+ colorSpace2->getGrayLine(tmp_line, out, length);
+ gfree (tmp_line);
+ break;
+
+ default:
+ inp = in;
+ for (j = 0; j < length; j++)
+ for (i = 0; i < nComps; i++) {
+ *inp = byte_lookup[*inp * nComps + i];
+ inp++;
+ }
+ colorSpace->getGrayLine(in, out, length);
+ break;
+ }
+
+}
+
+void GfxImageColorMap::getRGBLine(Guchar *in, unsigned int *out, int length) {
+ int i, j;
+ Guchar *inp, *tmp_line;
+
+ if (!useRGBLine()) {
+ GfxRGB rgb;
+
+ inp = in;
+ for (i = 0; i < length; i++) {
+ getRGB (inp, &rgb);
+ out[i] =
+ ((int) colToByte(rgb.r) << 16) |
+ ((int) colToByte(rgb.g) << 8) |
+ ((int) colToByte(rgb.b) << 0);
+ inp += nComps;
+ }
+ return;
+ }
+
+ switch (colorSpace->getMode()) {
+ case csIndexed:
+ case csSeparation:
+ tmp_line = (Guchar *) gmallocn (length, nComps2);
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < nComps2; j++) {
+ tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j];
+ }
+ }
+ colorSpace2->getRGBLine(tmp_line, out, length);
+ gfree (tmp_line);
+ break;
+
+ default:
+ inp = in;
+ for (j = 0; j < length; j++)
+ for (i = 0; i < nComps; i++) {
+ *inp = byte_lookup[*inp * nComps + i];
+ inp++;
+ }
+ colorSpace->getRGBLine(in, out, length);
+ break;
+ }
+
+}
+
+void GfxImageColorMap::getRGBLine(Guchar *in, Guchar *out, int length) {
+ int i, j;
+ Guchar *inp, *tmp_line;
+
+ if (!useRGBLine()) {
+ GfxRGB rgb;
+
+ inp = in;
+ for (i = 0; i < length; i++) {
+ getRGB (inp, &rgb);
+ *out++ = colToByte(rgb.r);
+ *out++ = colToByte(rgb.g);
+ *out++ = colToByte(rgb.b);
+ inp += nComps;
+ }
+ return;
+ }
+
+ switch (colorSpace->getMode()) {
+ case csIndexed:
+ case csSeparation:
+ tmp_line = (Guchar *) gmallocn (length, nComps2);
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < nComps2; j++) {
+ tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j];
+ }
+ }
+ colorSpace2->getRGBLine(tmp_line, out, length);
+ gfree (tmp_line);
+ break;
+
+ default:
+ inp = in;
+ for (j = 0; j < length; j++)
+ for (i = 0; i < nComps; i++) {
+ *inp = byte_lookup[*inp * nComps + i];
+ inp++;
+ }
+ colorSpace->getRGBLine(in, out, length);
+ break;
+ }
+
+}
+
+void GfxImageColorMap::getRGBXLine(Guchar *in, Guchar *out, int length) {
+ int i, j;
+ Guchar *inp, *tmp_line;
+
+ if (!useRGBLine()) {
+ GfxRGB rgb;
+
+ inp = in;
+ for (i = 0; i < length; i++) {
+ getRGB (inp, &rgb);
+ *out++ = colToByte(rgb.r);
+ *out++ = colToByte(rgb.g);
+ *out++ = colToByte(rgb.b);
+ *out++ = 255;
+ inp += nComps;
+ }
+ return;
+ }
+
+ switch (colorSpace->getMode()) {
+ case csIndexed:
+ case csSeparation:
+ tmp_line = (Guchar *) gmallocn (length, nComps2);
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < nComps2; j++) {
+ tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j];
+ }
+ }
+ colorSpace2->getRGBXLine(tmp_line, out, length);
+ gfree (tmp_line);
+ break;
+
+ default:
+ inp = in;
+ for (j = 0; j < length; j++)
+ for (i = 0; i < nComps; i++) {
+ *inp = byte_lookup[*inp * nComps + i];
+ inp++;
+ }
+ colorSpace->getRGBXLine(in, out, length);
+ break;
+ }
+
+}
+
+void GfxImageColorMap::getCMYKLine(Guchar *in, Guchar *out, int length) {
+ int i, j;
+ Guchar *inp, *tmp_line;
+
+ if (!useCMYKLine()) {
+ GfxCMYK cmyk;
+
+ inp = in;
+ for (i = 0; i < length; i++) {
+ getCMYK (inp, &cmyk);
+ *out++ = colToByte(cmyk.c);
+ *out++ = colToByte(cmyk.m);
+ *out++ = colToByte(cmyk.y);
+ *out++ = colToByte(cmyk.k);
+ inp += nComps;
+ }
+ return;
+ }
+
+ switch (colorSpace->getMode()) {
+ case csIndexed:
+ case csSeparation:
+ tmp_line = (Guchar *) gmallocn (length, nComps2);
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < nComps2; j++) {
+ tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j];
+ }
+ }
+ colorSpace2->getCMYKLine(tmp_line, out, length);
+ gfree (tmp_line);
+ break;
+
+ default:
+ inp = in;
+ for (j = 0; j < length; j++)
+ for (i = 0; i < nComps; i++) {
+ *inp = byte_lookup[*inp * nComps + i];
+ inp++;
+ }
+ colorSpace->getCMYKLine(in, out, length);
+ break;
+ }
+
+}
+
+void GfxImageColorMap::getDeviceNLine(Guchar *in, Guchar *out, int length) {
+ int i, j;
+ Guchar *inp, *tmp_line;
+
+ if (!useDeviceNLine()) {
+ GfxColor deviceN;
+
+ inp = in;
+ for (i = 0; i < length; i++) {
+ getDeviceN (inp, &deviceN);
+ for (int j = 0; j < SPOT_NCOMPS+4; j++)
+ *out++ = deviceN.c[j];
+ inp += nComps;
+ }
+ return;
+ }
+
+ switch (colorSpace->getMode()) {
+ case csIndexed:
+ case csSeparation:
+ tmp_line = (Guchar *) gmallocn (length, nComps2);
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < nComps2; j++) {
+ tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j];
+ }
+ }
+ colorSpace2->getDeviceNLine(tmp_line, out, length);
+ gfree (tmp_line);
+ break;
+
+ default:
+ inp = in;
+ for (j = 0; j < length; j++)
+ for (i = 0; i < nComps; i++) {
+ *inp = byte_lookup[*inp * nComps + i];
+ inp++;
+ }
+ colorSpace->getDeviceNLine(in, out, length);
+ break;
+ }
+
+}
+
+void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
+ GfxColor color;
+ int i;
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = lookup2[i][x[0]];
+ }
+ colorSpace2->getCMYK(&color, cmyk);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[i][x[i]];
+ }
+ colorSpace->getCMYK(&color, cmyk);
+ }
+}
+
+void GfxImageColorMap::getDeviceN(Guchar *x, GfxColor *deviceN) {
+ GfxColor color;
+ int i;
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = lookup2[i][x[0]];
+ }
+ colorSpace2->getDeviceN(&color, deviceN);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[i][x[i]];
+ }
+ colorSpace->getDeviceN(&color, deviceN);
+ }
+}
+
+void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
+ int maxPixel, i;
+
+ maxPixel = (1 << bits) - 1;
+ for (i = 0; i < nComps; ++i) {
+ color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxSubpath and GfxPath
+//------------------------------------------------------------------------
+
+GfxSubpath::GfxSubpath(double x1, double y1) {
+ size = 16;
+ x = (double *)gmallocn(size, sizeof(double));
+ y = (double *)gmallocn(size, sizeof(double));
+ curve = (GBool *)gmallocn(size, sizeof(GBool));
+ n = 1;
+ x[0] = x1;
+ y[0] = y1;
+ curve[0] = gFalse;
+ closed = gFalse;
+}
+
+GfxSubpath::~GfxSubpath() {
+ gfree(x);
+ gfree(y);
+ gfree(curve);
+}
+
+// Used for copy().
+GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
+ size = subpath->size;
+ n = subpath->n;
+ x = (double *)gmallocn(size, sizeof(double));
+ y = (double *)gmallocn(size, sizeof(double));
+ curve = (GBool *)gmallocn(size, sizeof(GBool));
+ memcpy(x, subpath->x, n * sizeof(double));
+ memcpy(y, subpath->y, n * sizeof(double));
+ memcpy(curve, subpath->curve, n * sizeof(GBool));
+ closed = subpath->closed;
+}
+
+void GfxSubpath::lineTo(double x1, double y1) {
+ if (n >= size) {
+ size *= 2;
+ x = (double *)greallocn(x, size, sizeof(double));
+ y = (double *)greallocn(y, size, sizeof(double));
+ curve = (GBool *)greallocn(curve, size, sizeof(GBool));
+ }
+ x[n] = x1;
+ y[n] = y1;
+ curve[n] = gFalse;
+ ++n;
+}
+
+void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+ if (n+3 > size) {
+ size *= 2;
+ x = (double *)greallocn(x, size, sizeof(double));
+ y = (double *)greallocn(y, size, sizeof(double));
+ curve = (GBool *)greallocn(curve, size, sizeof(GBool));
+ }
+ x[n] = x1;
+ y[n] = y1;
+ x[n+1] = x2;
+ y[n+1] = y2;
+ x[n+2] = x3;
+ y[n+2] = y3;
+ curve[n] = curve[n+1] = gTrue;
+ curve[n+2] = gFalse;
+ n += 3;
+}
+
+void GfxSubpath::close() {
+ if (x[n-1] != x[0] || y[n-1] != y[0]) {
+ lineTo(x[0], y[0]);
+ }
+ closed = gTrue;
+}
+
+void GfxSubpath::offset(double dx, double dy) {
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ x[i] += dx;
+ y[i] += dy;
+ }
+}
+
+GfxPath::GfxPath() {
+ justMoved = gFalse;
+ size = 16;
+ n = 0;
+ firstX = firstY = 0;
+ subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
+}
+
+GfxPath::~GfxPath() {
+ int i;
+
+ for (i = 0; i < n; ++i)
+ delete subpaths[i];
+ gfree(subpaths);
+}
+
+// Used for copy().
+GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
+ GfxSubpath **subpaths1, int n1, int size1) {
+ int i;
+
+ justMoved = justMoved1;
+ firstX = firstX1;
+ firstY = firstY1;
+ size = size1;
+ n = n1;
+ subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
+ for (i = 0; i < n; ++i)
+ subpaths[i] = subpaths1[i]->copy();
+}
+
+void GfxPath::moveTo(double x, double y) {
+ justMoved = gTrue;
+ firstX = x;
+ firstY = y;
+}
+
+void GfxPath::lineTo(double x, double y) {
+ if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
+ if (n >= size) {
+ size *= 2;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ if (justMoved) {
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ } else {
+ subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
+ subpaths[n-1]->getLastY());
+ }
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->lineTo(x, y);
+}
+
+void GfxPath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+ if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
+ if (n >= size) {
+ size *= 2;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ if (justMoved) {
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ } else {
+ subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
+ subpaths[n-1]->getLastY());
+ }
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void GfxPath::close() {
+ // this is necessary to handle the pathological case of
+ // moveto/closepath/clip, which defines an empty clipping region
+ if (justMoved) {
+ if (n >= size) {
+ size *= 2;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->close();
+}
+
+void GfxPath::append(GfxPath *path) {
+ int i;
+
+ if (n + path->n > size) {
+ size = n + path->n;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ for (i = 0; i < path->n; ++i) {
+ subpaths[n++] = path->subpaths[i]->copy();
+ }
+ justMoved = gFalse;
+}
+
+void GfxPath::offset(double dx, double dy) {
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ subpaths[i]->offset(dx, dy);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxState
+//------------------------------------------------------------------------
+GfxState::ReusablePathIterator::ReusablePathIterator(GfxPath *path)
+ : path(path),
+ subPathOff(0),
+ coordOff(0),
+ numCoords(0),
+ curSubPath(NULL)
+{
+ if( path->getNumSubpaths() ) {
+ curSubPath = path->getSubpath(subPathOff);
+ numCoords = curSubPath->getNumPoints();
+ }
+}
+
+bool GfxState::ReusablePathIterator::isEnd() const {
+ return coordOff >= numCoords;
+}
+
+void GfxState::ReusablePathIterator::next() {
+ ++coordOff;
+ if (coordOff == numCoords) {
+ ++subPathOff;
+ if (subPathOff < path->getNumSubpaths()) {
+ coordOff = 0;
+ curSubPath = path->getSubpath(subPathOff);
+ numCoords = curSubPath->getNumPoints();
+ }
+ }
+}
+
+void GfxState::ReusablePathIterator::setCoord(double x, double y) {
+ curSubPath->setX(coordOff, x);
+ curSubPath->setY(coordOff, y);
+}
+
+void GfxState::ReusablePathIterator::reset() {
+ coordOff = 0;
+ subPathOff = 0;
+ curSubPath = path->getSubpath(0);
+ numCoords = curSubPath->getNumPoints();
+}
+
+GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
+ int rotateA, GBool upsideDown) {
+ double kx, ky;
+
+ hDPI = hDPIA;
+ vDPI = vDPIA;
+ rotate = rotateA;
+ px1 = pageBox->x1;
+ py1 = pageBox->y1;
+ px2 = pageBox->x2;
+ py2 = pageBox->y2;
+ kx = hDPI / 72.0;
+ ky = vDPI / 72.0;
+ if (rotate == 90) {
+ ctm[0] = 0;
+ ctm[1] = upsideDown ? ky : -ky;
+ ctm[2] = kx;
+ ctm[3] = 0;
+ ctm[4] = -kx * py1;
+ ctm[5] = ky * (upsideDown ? -px1 : px2);
+ pageWidth = kx * (py2 - py1);
+ pageHeight = ky * (px2 - px1);
+ } else if (rotate == 180) {
+ ctm[0] = -kx;
+ ctm[1] = 0;
+ ctm[2] = 0;
+ ctm[3] = upsideDown ? ky : -ky;
+ ctm[4] = kx * px2;
+ ctm[5] = ky * (upsideDown ? -py1 : py2);
+ pageWidth = kx * (px2 - px1);
+ pageHeight = ky * (py2 - py1);
+ } else if (rotate == 270) {
+ ctm[0] = 0;
+ ctm[1] = upsideDown ? -ky : ky;
+ ctm[2] = -kx;
+ ctm[3] = 0;
+ ctm[4] = kx * py2;
+ ctm[5] = ky * (upsideDown ? px2 : -px1);
+ pageWidth = kx * (py2 - py1);
+ pageHeight = ky * (px2 - px1);
+ } else {
+ ctm[0] = kx;
+ ctm[1] = 0;
+ ctm[2] = 0;
+ ctm[3] = upsideDown ? -ky : ky;
+ ctm[4] = -kx * px1;
+ ctm[5] = ky * (upsideDown ? py2 : -py1);
+ pageWidth = kx * (px2 - px1);
+ pageHeight = ky * (py2 - py1);
+ }
+
+ fillColorSpace = new GfxDeviceGrayColorSpace();
+ strokeColorSpace = new GfxDeviceGrayColorSpace();
+ fillColor.c[0] = 0;
+ strokeColor.c[0] = 0;
+ fillPattern = NULL;
+ strokePattern = NULL;
+ blendMode = gfxBlendNormal;
+ fillOpacity = 1;
+ strokeOpacity = 1;
+ fillOverprint = gFalse;
+ strokeOverprint = gFalse;
+ overprintMode = 0;
+ transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
+
+ lineWidth = 1;
+ lineDash = NULL;
+ lineDashLength = 0;
+ lineDashStart = 0;
+ flatness = 1;
+ lineJoin = 0;
+ lineCap = 0;
+ miterLimit = 10;
+ strokeAdjust = gFalse;
+ alphaIsShape = gFalse;
+ textKnockout = gFalse;
+
+ font = NULL;
+ fontSize = 0;
+ textMat[0] = 1; textMat[1] = 0;
+ textMat[2] = 0; textMat[3] = 1;
+ textMat[4] = 0; textMat[5] = 0;
+ charSpace = 0;
+ wordSpace = 0;
+ horizScaling = 1;
+ leading = 0;
+ rise = 0;
+ render = 0;
+
+ path = new GfxPath();
+ curX = curY = 0;
+ lineX = lineY = 0;
+
+ clipXMin = 0;
+ clipYMin = 0;
+ clipXMax = pageWidth;
+ clipYMax = pageHeight;
+
+ renderingIntent[0] = 0;
+
+ saved = NULL;
+#ifdef USE_CMS
+ GfxColorSpace::setupColorProfiles();
+ XYZ2DisplayTransformRelCol = NULL;
+ XYZ2DisplayTransformAbsCol = NULL;
+ XYZ2DisplayTransformSat = NULL;
+ XYZ2DisplayTransformPerc = NULL;
+ localDisplayProfile = NULL;
+ displayProfileRef = 0;
+#endif
+}
+
+GfxState::~GfxState() {
+ int i;
+
+ if (fillColorSpace) {
+ delete fillColorSpace;
+ }
+ if (strokeColorSpace) {
+ delete strokeColorSpace;
+ }
+ if (fillPattern) {
+ delete fillPattern;
+ }
+ if (strokePattern) {
+ delete strokePattern;
+ }
+ for (i = 0; i < 4; ++i) {
+ if (transfer[i]) {
+ delete transfer[i];
+ }
+ }
+ gfree(lineDash);
+ if (path) {
+ // this gets set to NULL by restore()
+ delete path;
+ }
+ if (font) {
+ font->decRefCnt();
+ }
+#ifdef USE_CMS
+ if (XYZ2DisplayTransformRelCol) {
+ if (XYZ2DisplayTransformRelCol->unref() == 0)
+ delete XYZ2DisplayTransformRelCol;
+ }
+ if (XYZ2DisplayTransformAbsCol) {
+ if (XYZ2DisplayTransformAbsCol->unref() == 0)
+ delete XYZ2DisplayTransformAbsCol;
+ }
+ if (XYZ2DisplayTransformSat) {
+ if (XYZ2DisplayTransformSat->unref() == 0)
+ delete XYZ2DisplayTransformSat;
+ }
+ if (XYZ2DisplayTransformPerc) {
+ if (XYZ2DisplayTransformPerc->unref() == 0)
+ delete XYZ2DisplayTransformPerc;
+ }
+ if (--displayProfileRef == 0 && localDisplayProfile != NULL) {
+ cmsCloseProfile(localDisplayProfile);
+ }
+#endif
+}
+
+// Used for copy();
+GfxState::GfxState(GfxState *state, GBool copyPath) {
+ int i;
+
+ memcpy(this, state, sizeof(GfxState));
+ if (fillColorSpace) {
+ fillColorSpace = state->fillColorSpace->copy();
+ }
+ if (strokeColorSpace) {
+ strokeColorSpace = state->strokeColorSpace->copy();
+ }
+ if (fillPattern) {
+ fillPattern = state->fillPattern->copy();
+ }
+ if (strokePattern) {
+ strokePattern = state->strokePattern->copy();
+ }
+ for (i = 0; i < 4; ++i) {
+ if (transfer[i]) {
+ transfer[i] = state->transfer[i]->copy();
+ }
+ }
+ if (lineDashLength > 0) {
+ lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
+ memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
+ }
+ if (font)
+ font->incRefCnt();
+
+ if (copyPath) {
+ path = state->path->copy();
+ }
+ saved = NULL;
+#ifdef USE_CMS
+ if (XYZ2DisplayTransformRelCol) {
+ XYZ2DisplayTransformRelCol->ref();
+ }
+ if (XYZ2DisplayTransformAbsCol) {
+ XYZ2DisplayTransformAbsCol->ref();
+ }
+ if (XYZ2DisplayTransformSat) {
+ XYZ2DisplayTransformSat->ref();
+ }
+ if (XYZ2DisplayTransformPerc) {
+ XYZ2DisplayTransformPerc->ref();
+ }
+ if (localDisplayProfile) {
+ displayProfileRef++;
+ }
+#endif
+}
+
+#ifdef USE_CMS
+void GfxState::setDisplayProfile(cmsHPROFILE localDisplayProfileA) {
+ if (localDisplayProfile != NULL) {
+ cmsCloseProfile(localDisplayProfile);
+ }
+ localDisplayProfile = localDisplayProfileA;
+ if (localDisplayProfileA != NULL) {
+ cmsHTRANSFORM transform;
+ unsigned int nChannels;
+ unsigned int localDisplayPixelType;
+
+ localDisplayPixelType = getCMSColorSpaceType(cmsGetColorSpace(localDisplayProfile));
+ nChannels = getCMSNChannels(cmsGetColorSpace(localDisplayProfile));
+ displayProfileRef = 1;
+ // create transform from XYZ
+ cmsHPROFILE XYZProfile = cmsCreateXYZProfile();
+ if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
+ localDisplayProfile,
+ COLORSPACE_SH(localDisplayPixelType) |
+ CHANNELS_SH(nChannels) | BYTES_SH(1),
+ INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == 0) {
+ error(errSyntaxWarning, -1, "Can't create Lab transform");
+ } else {
+ XYZ2DisplayTransformRelCol = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
+ }
+ if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
+ localDisplayProfile,
+ COLORSPACE_SH(localDisplayPixelType) |
+ CHANNELS_SH(nChannels) | BYTES_SH(1),
+ INTENT_ABSOLUTE_COLORIMETRIC,LCMS_FLAGS)) == 0) {
+ error(errSyntaxWarning, -1, "Can't create Lab transform");
+ } else {
+ XYZ2DisplayTransformAbsCol = new GfxColorTransform(transform, INTENT_ABSOLUTE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
+ }
+ if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
+ localDisplayProfile,
+ COLORSPACE_SH(localDisplayPixelType) |
+ CHANNELS_SH(nChannels) | BYTES_SH(1),
+ INTENT_SATURATION,LCMS_FLAGS)) == 0) {
+ error(errSyntaxWarning, -1, "Can't create Lab transform");
+ } else {
+ XYZ2DisplayTransformSat = new GfxColorTransform(transform, INTENT_SATURATION, PT_XYZ, localDisplayPixelType);
+ }
+ if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
+ localDisplayProfile,
+ COLORSPACE_SH(localDisplayPixelType) |
+ CHANNELS_SH(nChannels) | BYTES_SH(1),
+ INTENT_PERCEPTUAL,LCMS_FLAGS)) == 0) {
+ error(errSyntaxWarning, -1, "Can't create Lab transform");
+ } else {
+ XYZ2DisplayTransformPerc = new GfxColorTransform(transform, INTENT_PERCEPTUAL, PT_XYZ, localDisplayPixelType);
+ }
+ cmsCloseProfile(XYZProfile);
+ }
+}
+
+GfxColorTransform *GfxState::getXYZ2DisplayTransform() {
+ GfxColorTransform *transform;
+
+ transform = XYZ2DisplayTransformRelCol;
+ if (strcmp(renderingIntent, "AbsoluteColorimetric") == 0) {
+ transform = XYZ2DisplayTransformAbsCol;
+ } else if (strcmp(renderingIntent, "Saturation") == 0) {
+ transform = XYZ2DisplayTransformSat;
+ } else if (strcmp(renderingIntent, "Perceptual") == 0) {
+ transform = XYZ2DisplayTransformPerc;
+ }
+ if (transform == NULL) {
+ transform = XYZ2DisplayTransform;
+ }
+ return transform;
+}
+
+#endif
+
+void GfxState::setPath(GfxPath *pathA) {
+ delete path;
+ path = pathA;
+}
+
+void GfxState::getUserClipBBox(double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ double ictm[6];
+ double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
+
+ // invert the CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+
+ // transform all four corners of the clip bbox; find the min and max
+ // x and y values
+ xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
+ yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
+ tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
+ ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+ tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
+ ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+ tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
+ ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+
+ *xMin = xMin1;
+ *yMin = yMin1;
+ *xMax = xMax1;
+ *yMax = yMax1;
+}
+
+double GfxState::transformWidth(double w) {
+ double x, y;
+
+ x = ctm[0] + ctm[2];
+ y = ctm[1] + ctm[3];
+ return w * sqrt(0.5 * (x * x + y * y));
+}
+
+double GfxState::getTransformedFontSize() {
+ double x1, y1, x2, y2;
+
+ x1 = textMat[2] * fontSize;
+ y1 = textMat[3] * fontSize;
+ x2 = ctm[0] * x1 + ctm[2] * y1;
+ y2 = ctm[1] * x1 + ctm[3] * y1;
+ return sqrt(x2 * x2 + y2 * y2);
+}
+
+void GfxState::getFontTransMat(double *m11, double *m12,
+ double *m21, double *m22) {
+ *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
+ *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
+ *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
+ *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
+}
+
+void GfxState::setCTM(double a, double b, double c,
+ double d, double e, double f) {
+ ctm[0] = a;
+ ctm[1] = b;
+ ctm[2] = c;
+ ctm[3] = d;
+ ctm[4] = e;
+ ctm[5] = f;
+}
+
+void GfxState::concatCTM(double a, double b, double c,
+ double d, double e, double f) {
+ double a1 = ctm[0];
+ double b1 = ctm[1];
+ double c1 = ctm[2];
+ double d1 = ctm[3];
+
+ ctm[0] = a * a1 + b * c1;
+ ctm[1] = a * b1 + b * d1;
+ ctm[2] = c * a1 + d * c1;
+ ctm[3] = c * b1 + d * d1;
+ ctm[4] = e * a1 + f * c1 + ctm[4];
+ ctm[5] = e * b1 + f * d1 + ctm[5];
+}
+
+void GfxState::shiftCTMAndClip(double tx, double ty) {
+ ctm[4] += tx;
+ ctm[5] += ty;
+ clipXMin += tx;
+ clipYMin += ty;
+ clipXMax += tx;
+ clipYMax += ty;
+}
+
+void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
+ if (fillColorSpace) {
+ delete fillColorSpace;
+ }
+ fillColorSpace = colorSpace;
+}
+
+void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
+ if (strokeColorSpace) {
+ delete strokeColorSpace;
+ }
+ strokeColorSpace = colorSpace;
+}
+
+void GfxState::setFillPattern(GfxPattern *pattern) {
+ if (fillPattern) {
+ delete fillPattern;
+ }
+ fillPattern = pattern;
+}
+
+void GfxState::setStrokePattern(GfxPattern *pattern) {
+ if (strokePattern) {
+ delete strokePattern;
+ }
+ strokePattern = pattern;
+}
+
+void GfxState::setFont(GfxFont *fontA, double fontSizeA) {
+ if (font)
+ font->decRefCnt();
+
+ font = fontA;
+ fontSize = fontSizeA;
+}
+
+void GfxState::setTransfer(Function **funcs) {
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ if (transfer[i]) {
+ delete transfer[i];
+ }
+ transfer[i] = funcs[i];
+ }
+}
+
+void GfxState::setLineDash(double *dash, int length, double start) {
+ if (lineDash)
+ gfree(lineDash);
+ lineDash = dash;
+ lineDashLength = length;
+ lineDashStart = start;
+}
+
+void GfxState::clearPath() {
+ delete path;
+ path = new GfxPath();
+}
+
+void GfxState::clip() {
+ double xMin, yMin, xMax, yMax, x, y;
+ GfxSubpath *subpath;
+ int i, j;
+
+ xMin = xMax = yMin = yMax = 0; // make gcc happy
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ for (j = 0; j < subpath->getNumPoints(); ++j) {
+ transform(subpath->getX(j), subpath->getY(j), &x, &y);
+ if (i == 0 && j == 0) {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ } else {
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ }
+ }
+ }
+ if (xMin > clipXMin) {
+ clipXMin = xMin;
+ }
+ if (yMin > clipYMin) {
+ clipYMin = yMin;
+ }
+ if (xMax < clipXMax) {
+ clipXMax = xMax;
+ }
+ if (yMax < clipYMax) {
+ clipYMax = yMax;
+ }
+}
+
+void GfxState::clipToStrokePath() {
+ double xMin, yMin, xMax, yMax, x, y, t0, t1;
+ GfxSubpath *subpath;
+ int i, j;
+
+ xMin = xMax = yMin = yMax = 0; // make gcc happy
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ for (j = 0; j < subpath->getNumPoints(); ++j) {
+ transform(subpath->getX(j), subpath->getY(j), &x, &y);
+ if (i == 0 && j == 0) {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ } else {
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ }
+ }
+ }
+
+ // allow for the line width
+ //~ miter joins can extend farther than this
+ t0 = fabs(ctm[0]);
+ t1 = fabs(ctm[2]);
+ if (t0 > t1) {
+ xMin -= 0.5 * lineWidth * t0;
+ xMax += 0.5 * lineWidth * t0;
+ } else {
+ xMin -= 0.5 * lineWidth * t1;
+ xMax += 0.5 * lineWidth * t1;
+ }
+ t0 = fabs(ctm[0]);
+ t1 = fabs(ctm[3]);
+ if (t0 > t1) {
+ yMin -= 0.5 * lineWidth * t0;
+ yMax += 0.5 * lineWidth * t0;
+ } else {
+ yMin -= 0.5 * lineWidth * t1;
+ yMax += 0.5 * lineWidth * t1;
+ }
+
+ if (xMin > clipXMin) {
+ clipXMin = xMin;
+ }
+ if (yMin > clipYMin) {
+ clipYMin = yMin;
+ }
+ if (xMax < clipXMax) {
+ clipXMax = xMax;
+ }
+ if (yMax < clipYMax) {
+ clipYMax = yMax;
+ }
+}
+
+void GfxState::clipToRect(double xMin, double yMin, double xMax, double yMax) {
+ double x, y, xMin1, yMin1, xMax1, yMax1;
+
+ transform(xMin, yMin, &x, &y);
+ xMin1 = xMax1 = x;
+ yMin1 = yMax1 = y;
+ transform(xMax, yMin, &x, &y);
+ if (x < xMin1) {
+ xMin1 = x;
+ } else if (x > xMax1) {
+ xMax1 = x;
+ }
+ if (y < yMin1) {
+ yMin1 = y;
+ } else if (y > yMax1) {
+ yMax1 = y;
+ }
+ transform(xMax, yMax, &x, &y);
+ if (x < xMin1) {
+ xMin1 = x;
+ } else if (x > xMax1) {
+ xMax1 = x;
+ }
+ if (y < yMin1) {
+ yMin1 = y;
+ } else if (y > yMax1) {
+ yMax1 = y;
+ }
+ transform(xMin, yMax, &x, &y);
+ if (x < xMin1) {
+ xMin1 = x;
+ } else if (x > xMax1) {
+ xMax1 = x;
+ }
+ if (y < yMin1) {
+ yMin1 = y;
+ } else if (y > yMax1) {
+ yMax1 = y;
+ }
+
+ if (xMin1 > clipXMin) {
+ clipXMin = xMin1;
+ }
+ if (yMin1 > clipYMin) {
+ clipYMin = yMin1;
+ }
+ if (xMax1 < clipXMax) {
+ clipXMax = xMax1;
+ }
+ if (yMax1 < clipYMax) {
+ clipYMax = yMax1;
+ }
+}
+
+void GfxState::textShift(double tx, double ty) {
+ double dx, dy;
+
+ textTransformDelta(tx, ty, &dx, &dy);
+ curX += dx;
+ curY += dy;
+}
+
+void GfxState::shift(double dx, double dy) {
+ curX += dx;
+ curY += dy;
+}
+
+GfxState *GfxState::save() {
+ GfxState *newState;
+
+ newState = copy();
+ newState->saved = this;
+ return newState;
+}
+
+GfxState *GfxState::restore() {
+ GfxState *oldState;
+
+ if (saved) {
+ oldState = saved;
+
+ // these attributes aren't saved/restored by the q/Q operators
+ oldState->path = path;
+ oldState->curX = curX;
+ oldState->curY = curY;
+ oldState->lineX = lineX;
+ oldState->lineY = lineY;
+
+ path = NULL;
+ saved = NULL;
+ delete this;
+
+ } else {
+ oldState = this;
+ }
+
+ return oldState;
+}
+
+GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
+ Object obj2;
+ int i, j;
+
+ if (obj->isName()) {
+ for (i = 0; i < nGfxBlendModeNames; ++i) {
+ if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) {
+ *mode = gfxBlendModeNames[i].mode;
+ return gTrue;
+ }
+ }
+ return gFalse;
+ } else if (obj->isArray()) {
+ for (i = 0; i < obj->arrayGetLength(); ++i) {
+ obj->arrayGet(i, &obj2);
+ if (!obj2.isName()) {
+ obj2.free();
+ return gFalse;
+ }
+ for (j = 0; j < nGfxBlendModeNames; ++j) {
+ if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
+ obj2.free();
+ *mode = gfxBlendModeNames[j].mode;
+ return gTrue;
+ }
+ }
+ obj2.free();
+ }
+ *mode = gfxBlendNormal;
+ return gTrue;
+ } else {
+ return gFalse;
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState.h
new file mode 100644
index 00000000000..f018e93dd34
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState.h
@@ -0,0 +1,1651 @@
+//========================================================================
+//
+// GfxState.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2009-2011, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
+// Copyright (C) 2011-2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Lu Wang <coolwanglu@gmail.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef GFXSTATE_H
+#define GFXSTATE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+
+#include "goo/gtypes.h"
+#include "Object.h"
+#include "Function.h"
+
+#include <assert.h>
+#include <map>
+
+class Array;
+class Gfx;
+class GfxFont;
+class PDFRectangle;
+class GfxShading;
+class PopplerCache;
+class GooList;
+class OutputDev;
+class GfxState;
+class GfxResources;
+
+class Matrix {
+public:
+ double m[6];
+
+ GBool invertTo(Matrix *other) const;
+ void transform(double x, double y, double *tx, double *ty) const;
+ double determinant() const { return m[0] * m[3] - m[1] * m[2]; }
+ double norm() const;
+};
+
+//------------------------------------------------------------------------
+// GfxBlendMode
+//------------------------------------------------------------------------
+
+enum GfxBlendMode {
+ gfxBlendNormal,
+ gfxBlendMultiply,
+ gfxBlendScreen,
+ gfxBlendOverlay,
+ gfxBlendDarken,
+ gfxBlendLighten,
+ gfxBlendColorDodge,
+ gfxBlendColorBurn,
+ gfxBlendHardLight,
+ gfxBlendSoftLight,
+ gfxBlendDifference,
+ gfxBlendExclusion,
+ gfxBlendHue,
+ gfxBlendSaturation,
+ gfxBlendColor,
+ gfxBlendLuminosity
+};
+
+//------------------------------------------------------------------------
+// GfxColorComp
+//------------------------------------------------------------------------
+
+// 16.16 fixed point color component
+typedef int GfxColorComp;
+
+#define gfxColorComp1 0x10000
+
+static inline GfxColorComp dblToCol(double x) {
+ return (GfxColorComp)(x * gfxColorComp1);
+}
+
+static inline double colToDbl(GfxColorComp x) {
+ return (double)x / (double)gfxColorComp1;
+}
+
+static inline Guchar dblToByte(double x) {
+ return (x * 255.0);
+}
+
+static inline double byteToDbl(Guchar x) {
+ return (double)x / (double)255.0;
+}
+
+static inline GfxColorComp byteToCol(Guchar x) {
+ // (x / 255) << 16 = (0.0000000100000001... * x) << 16
+ // = ((x << 8) + (x) + (x >> 8) + ...) << 16
+ // = (x << 8) + (x) + (x >> 7)
+ // [for rounding]
+ return (GfxColorComp)((x << 8) + x + (x >> 7));
+}
+
+static inline Guchar colToByte(GfxColorComp x) {
+ // 255 * x + 0.5 = 256 * x - x + 0x8000
+ return (Guchar)(((x << 8) - x + 0x8000) >> 16);
+}
+
+//------------------------------------------------------------------------
+// GfxColor
+//------------------------------------------------------------------------
+
+#define gfxColorMaxComps funcMaxOutputs
+
+struct GfxColor {
+ GfxColorComp c[gfxColorMaxComps];
+};
+
+//------------------------------------------------------------------------
+// GfxGray
+//------------------------------------------------------------------------
+
+typedef GfxColorComp GfxGray;
+
+//------------------------------------------------------------------------
+// GfxRGB
+//------------------------------------------------------------------------
+
+struct GfxRGB {
+ GfxColorComp r, g, b;
+};
+
+//------------------------------------------------------------------------
+// GfxCMYK
+//------------------------------------------------------------------------
+
+struct GfxCMYK {
+ GfxColorComp c, m, y, k;
+};
+
+//------------------------------------------------------------------------
+// GfxColorSpace
+//------------------------------------------------------------------------
+
+// NB: The nGfxColorSpaceModes constant and the gfxColorSpaceModeNames
+// array defined in GfxState.cc must match this enum.
+enum GfxColorSpaceMode {
+ csDeviceGray,
+ csCalGray,
+ csDeviceRGB,
+ csCalRGB,
+ csDeviceCMYK,
+ csLab,
+ csICCBased,
+ csIndexed,
+ csSeparation,
+ csDeviceN,
+ csPattern
+};
+
+// wrapper of cmsHTRANSFORM to copy
+class GfxColorTransform {
+public:
+ void doTransform(void *in, void *out, unsigned int size);
+ // transformA should be a cmsHTRANSFORM
+ GfxColorTransform(void *transformA, int cmsIntent, unsigned int inputPixelType, unsigned int transformPixelType);
+ ~GfxColorTransform();
+ int getIntent() { return cmsIntent; }
+ int getInputPixelType() { return inputPixelType; }
+ int getTransformPixelType() { return transformPixelType; }
+ void ref();
+ unsigned int unref();
+private:
+ GfxColorTransform() {}
+ void *transform;
+ unsigned int refCount;
+ int cmsIntent;
+ unsigned int inputPixelType;
+ unsigned int transformPixelType;
+};
+
+class GfxColorSpace {
+public:
+
+ GfxColorSpace();
+ virtual ~GfxColorSpace();
+ virtual GfxColorSpace *copy() = 0;
+ virtual GfxColorSpaceMode getMode() = 0;
+
+ // Construct a color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(GfxResources *res, Object *csObj, OutputDev *out, GfxState *state, int recursion = 0);
+
+ // Convert to gray, RGB, or CMYK.
+ virtual void getGray(GfxColor *color, GfxGray *gray) = 0;
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0;
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0;
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN) = 0;
+ virtual void getGrayLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getGrayLine this should not happen"); }
+ virtual void getRGBLine(Guchar * /*in*/, unsigned int * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBLine (first variant) this should not happen"); }
+ virtual void getRGBLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBLine (second variant) this should not happen"); }
+ virtual void getRGBXLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBXLine this should not happen"); }
+ virtual void getCMYKLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getCMYKLine this should not happen"); }
+ virtual void getDeviceNLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getDeviceNLine this should not happen"); }
+
+ // create mapping for spot colorants
+ virtual void createMapping(GooList *separationList, int maxSepComps);
+
+ // Does this ColorSpace support getRGBLine?
+ virtual GBool useGetRGBLine() { return gFalse; }
+ // Does this ColorSpace support getGrayLine?
+ virtual GBool useGetGrayLine() { return gFalse; }
+ // Does this ColorSpace support getCMYKLine?
+ virtual GBool useGetCMYKLine() { return gFalse; }
+ // Does this ColorSpace support getDeviceNLine?
+ virtual GBool useGetDeviceNLine() { return gFalse; }
+
+ // 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 color space's overprint mask.
+ Guint getOverprintMask() { return overprintMask; }
+
+ // Return the number of color space modes
+ static int getNumColorSpaceModes();
+
+ // Return the name of the <idx>th color space mode.
+ static const char *getColorSpaceModeName(int idx);
+
+#ifdef USE_CMS
+ static int setupColorProfiles();
+ // displayProfileA should be a cmsHPROFILE
+ static void setDisplayProfile(void *displayProfileA);
+ static void setDisplayProfileName(GooString *name);
+ // result will be a cmsHPROFILE
+ static void *getRGBProfile();
+ // result will be a cmsHPROFILE
+ static void *getDisplayProfile();
+#endif
+protected:
+
+ Guint overprintMask;
+ int *mapping;
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceGrayColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceGrayColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceGrayColorSpace();
+ virtual ~GfxDeviceGrayColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceGray; }
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+ virtual void getGrayLine(Guchar *in, Guchar *out, int length);
+ virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
+ virtual void getRGBLine(Guchar *in, Guchar *out, int length);
+ virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
+ virtual void getCMYKLine(Guchar *in, Guchar *out, int length);
+ virtual void getDeviceNLine(Guchar *in, Guchar *out, int length);
+
+ virtual GBool useGetRGBLine() { return gTrue; }
+ virtual GBool useGetGrayLine() { return gTrue; }
+ virtual GBool useGetCMYKLine() { return gTrue; }
+ virtual GBool useGetDeviceNLine() { return gTrue; }
+
+ virtual int getNComps() { return 1; }
+ virtual void getDefaultColor(GfxColor *color);
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxCalGrayColorSpace
+//------------------------------------------------------------------------
+
+class GfxCalGrayColorSpace: public GfxColorSpace {
+public:
+
+ GfxCalGrayColorSpace();
+ virtual ~GfxCalGrayColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csCalGray; }
+
+ // Construct a CalGray color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr, GfxState *state);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+ virtual int getNComps() { return 1; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ // CalGray-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getGamma() { return gamma; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double gamma; // gamma value
+ double kr, kg, kb; // gamut mapping mulitpliers
+ void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ);
+#ifdef USE_CMS
+ GfxColorTransform *transform;
+#endif
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceRGBColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceRGBColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceRGBColorSpace();
+ virtual ~GfxDeviceRGBColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceRGB; }
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+ virtual void getGrayLine(Guchar *in, Guchar *out, int length);
+ virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
+ virtual void getRGBLine(Guchar *in, Guchar *out, int length);
+ virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
+ virtual void getCMYKLine(Guchar *in, Guchar *out, int length);
+ virtual void getDeviceNLine(Guchar *in, Guchar *out, int length);
+
+ virtual GBool useGetRGBLine() { return gTrue; }
+ virtual GBool useGetGrayLine() { return gTrue; }
+ virtual GBool useGetCMYKLine() { return gTrue; }
+ virtual GBool useGetDeviceNLine() { return gTrue; }
+
+ virtual int getNComps() { return 3; }
+ virtual void getDefaultColor(GfxColor *color);
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxCalRGBColorSpace
+//------------------------------------------------------------------------
+
+class GfxCalRGBColorSpace: public GfxColorSpace {
+public:
+
+ GfxCalRGBColorSpace();
+ virtual ~GfxCalRGBColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csCalRGB; }
+
+ // Construct a CalRGB color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr, GfxState *state);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+ virtual int getNComps() { return 3; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ // CalRGB-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getGammaR() { return gammaR; }
+ double getGammaG() { return gammaG; }
+ double getGammaB() { return gammaB; }
+ double *getMatrix() { return mat; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double gammaR, gammaG, gammaB; // gamma values
+ double mat[9]; // ABC -> XYZ transform matrix
+ double kr, kg, kb; // gamut mapping mulitpliers
+ void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ);
+#ifdef USE_CMS
+ GfxColorTransform *transform;
+#endif
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceCMYKColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceCMYKColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceCMYKColorSpace();
+ virtual ~GfxDeviceCMYKColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; }
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+ virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
+ virtual void getRGBLine(Guchar *, Guchar *out, int length);
+ virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
+ virtual void getCMYKLine(Guchar *in, Guchar *out, int length);
+ virtual void getDeviceNLine(Guchar *in, Guchar *out, int length);
+ virtual GBool useGetRGBLine() { return gTrue; }
+ virtual GBool useGetCMYKLine() { return gTrue; }
+ virtual GBool useGetDeviceNLine() { return gTrue; }
+
+ virtual int getNComps() { return 4; }
+ virtual void getDefaultColor(GfxColor *color);
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxLabColorSpace
+//------------------------------------------------------------------------
+
+class GfxLabColorSpace: public GfxColorSpace {
+public:
+
+ GfxLabColorSpace();
+ virtual ~GfxLabColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csLab; }
+
+ // Construct a Lab color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr, GfxState *state);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+ virtual int getNComps() { return 3; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // Lab-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getAMin() { return aMin; }
+ double getAMax() { return aMax; }
+ double getBMin() { return bMin; }
+ double getBMax() { return bMax; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double aMin, aMax, bMin, bMax; // range for the a and b components
+ double kr, kg, kb; // gamut mapping mulitpliers
+ void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ);
+#ifdef USE_CMS
+ GfxColorTransform *transform;
+#endif
+};
+
+//------------------------------------------------------------------------
+// GfxICCBasedColorSpace
+//------------------------------------------------------------------------
+
+class GfxICCBasedColorSpace: public GfxColorSpace {
+public:
+
+ GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA);
+ virtual ~GfxICCBasedColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csICCBased; }
+
+ // Construct an ICCBased color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr, OutputDev *out, GfxState *state, int recursion);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+ virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
+ virtual void getRGBLine(Guchar *in, Guchar *out, int length);
+ virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
+ virtual void getCMYKLine(Guchar *in, Guchar *out, int length);
+ virtual void getDeviceNLine(Guchar *in, Guchar *out, int length);
+
+ virtual GBool useGetRGBLine();
+ virtual GBool useGetCMYKLine();
+ virtual GBool useGetDeviceNLine();
+
+ virtual int getNComps() { return nComps; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // ICCBased-specific access.
+ GfxColorSpace *getAlt() { return alt; }
+
+private:
+
+ int nComps; // number of color components (1, 3, or 4)
+ GfxColorSpace *alt; // alternate color space
+ double rangeMin[4]; // min values for each component
+ double rangeMax[4]; // max values for each component
+ Ref iccProfileStream; // the ICC profile
+#ifdef USE_CMS
+ int getIntent() { return (transform != NULL) ? transform->getIntent() : 0; }
+ GfxColorTransform *transform;
+ GfxColorTransform *lineTransform; // color transform for line
+ std::map<unsigned int, unsigned int> cmsCache;
+#endif
+};
+//------------------------------------------------------------------------
+// GfxIndexedColorSpace
+//------------------------------------------------------------------------
+
+class GfxIndexedColorSpace: public GfxColorSpace {
+public:
+
+ GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA);
+ virtual ~GfxIndexedColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csIndexed; }
+
+ // Construct an Indexed color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+ virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
+ virtual void getRGBLine(Guchar *in, Guchar *out, int length);
+ virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
+ virtual void getCMYKLine(Guchar *in, Guchar *out, int length);
+ virtual void getDeviceNLine(Guchar *in, Guchar *out, int length);
+
+ virtual GBool useGetRGBLine() { return gTrue; }
+ virtual GBool useGetCMYKLine() { return gTrue; }
+ virtual GBool useGetDeviceNLine() { return gTrue; }
+
+ virtual int getNComps() { return 1; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // Indexed-specific access.
+ GfxColorSpace *getBase() { return base; }
+ int getIndexHigh() { return indexHigh; }
+ Guchar *getLookup() { return lookup; }
+ GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor);
+ Guint getOverprintMask() { return base->getOverprintMask(); }
+ virtual void createMapping(GooList *separationList, int maxSepComps)
+ { base->createMapping(separationList, maxSepComps); }
+
+
+private:
+
+ GfxColorSpace *base; // base color space
+ int indexHigh; // max pixel value
+ Guchar *lookup; // lookup table
+};
+
+//------------------------------------------------------------------------
+// GfxSeparationColorSpace
+//------------------------------------------------------------------------
+
+class GfxSeparationColorSpace: public GfxColorSpace {
+public:
+
+ GfxSeparationColorSpace(GooString *nameA, GfxColorSpace *altA,
+ Function *funcA);
+ virtual ~GfxSeparationColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csSeparation; }
+
+ // Construct a Separation color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+ virtual void createMapping(GooList *separationList, int maxSepComps);
+
+ virtual int getNComps() { return 1; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual GBool isNonMarking() { return nonMarking; }
+
+ // Separation-specific access.
+ GooString *getName() { return name; }
+ GfxColorSpace *getAlt() { return alt; }
+ Function *getFunc() { return func; }
+
+private:
+
+ GfxSeparationColorSpace(GooString *nameA, GfxColorSpace *altA,
+ Function *funcA, GBool nonMarkingA,
+ Guint overprintMaskA, int *mappingA);
+
+ GooString *name; // colorant name
+ GfxColorSpace *alt; // alternate color space
+ Function *func; // tint transform (into alternate color space)
+ GBool nonMarking;
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceNColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceNColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceNColorSpace(int nCompsA, GooString **namesA,
+ GfxColorSpace *alt, Function *func, GooList *sepsCS);
+ virtual ~GfxDeviceNColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceN; }
+
+ // Construct a DeviceN color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+ virtual void createMapping(GooList *separationList, int maxSepComps);
+
+ virtual int getNComps() { return nComps; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual GBool isNonMarking() { return nonMarking; }
+
+ // DeviceN-specific access.
+ GooString *getColorantName(int i) { return names[i]; }
+ GfxColorSpace *getAlt() { return alt; }
+ Function *getTintTransformFunc() { return func; }
+
+private:
+
+ GfxDeviceNColorSpace(int nCompsA, GooString **namesA,
+ GfxColorSpace *alt, Function *func, GooList *sepsCSA,
+ int *mappingA, GBool nonMarkingA, Guint overprintMaskA);
+
+ int nComps; // number of components
+ GooString // colorant names
+ *names[gfxColorMaxComps];
+ GfxColorSpace *alt; // alternate color space
+ Function *func; // tint transform (into alternate color space)
+ GBool nonMarking;
+ GooList *sepsCS; // list of separation cs for spot colorants;
+};
+
+//------------------------------------------------------------------------
+// GfxPatternColorSpace
+//------------------------------------------------------------------------
+
+class GfxPatternColorSpace: public GfxColorSpace {
+public:
+
+ GfxPatternColorSpace(GfxColorSpace *underA);
+ virtual ~GfxPatternColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csPattern; }
+
+ // Construct a Pattern color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+ virtual int getNComps() { return 0; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ // Pattern-specific access.
+ GfxColorSpace *getUnder() { return under; }
+
+private:
+
+ GfxColorSpace *under; // underlying color space (for uncolored
+ // patterns)
+};
+
+//------------------------------------------------------------------------
+// GfxPattern
+//------------------------------------------------------------------------
+
+class GfxPattern {
+public:
+
+ GfxPattern(int typeA);
+ virtual ~GfxPattern();
+
+ static GfxPattern *parse(GfxResources *res, Object *obj, OutputDev *out, GfxState *state);
+
+ virtual GfxPattern *copy() = 0;
+
+ int getType() { return type; }
+
+private:
+
+ int type;
+};
+
+//------------------------------------------------------------------------
+// GfxTilingPattern
+//------------------------------------------------------------------------
+
+class GfxTilingPattern: public GfxPattern {
+public:
+
+ static GfxTilingPattern *parse(Object *patObj);
+ virtual ~GfxTilingPattern();
+
+ virtual GfxPattern *copy();
+
+ int getPaintType() { return paintType; }
+ int getTilingType() { return tilingType; }
+ double *getBBox() { return bbox; }
+ double getXStep() { return xStep; }
+ double getYStep() { return yStep; }
+ Dict *getResDict()
+ { return resDict.isDict() ? resDict.getDict() : (Dict *)NULL; }
+ double *getMatrix() { return matrix; }
+ Object *getContentStream() { return &contentStream; }
+
+private:
+
+ GfxTilingPattern(int paintTypeA, int tilingTypeA,
+ double *bboxA, double xStepA, double yStepA,
+ Object *resDictA, double *matrixA,
+ Object *contentStreamA);
+
+ int paintType;
+ int tilingType;
+ double bbox[4];
+ double xStep, yStep;
+ Object resDict;
+ double matrix[6];
+ Object contentStream;
+};
+
+//------------------------------------------------------------------------
+// GfxShadingPattern
+//------------------------------------------------------------------------
+
+class GfxShadingPattern: public GfxPattern {
+public:
+
+ static GfxShadingPattern *parse(GfxResources *res, Object *patObj, OutputDev *out, GfxState *state);
+ virtual ~GfxShadingPattern();
+
+ virtual GfxPattern *copy();
+
+ GfxShading *getShading() { return shading; }
+ double *getMatrix() { return matrix; }
+
+private:
+
+ GfxShadingPattern(GfxShading *shadingA, double *matrixA);
+
+ GfxShading *shading;
+ double matrix[6];
+};
+
+//------------------------------------------------------------------------
+// GfxShading
+//------------------------------------------------------------------------
+
+class GfxShading {
+public:
+
+ GfxShading(int typeA);
+ GfxShading(GfxShading *shading);
+ virtual ~GfxShading();
+
+ static GfxShading *parse(GfxResources *res, Object *obj, OutputDev *out, GfxState *state);
+
+ virtual GfxShading *copy() = 0;
+
+ int getType() { return type; }
+ GfxColorSpace *getColorSpace() { return colorSpace; }
+ GfxColor *getBackground() { return &background; }
+ GBool getHasBackground() { return hasBackground; }
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ GBool getHasBBox() { return hasBBox; }
+
+protected:
+
+ GBool init(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state);
+
+ int type;
+ GfxColorSpace *colorSpace;
+ GfxColor background;
+ GBool hasBackground;
+ double xMin, yMin, xMax, yMax;
+ GBool hasBBox;
+};
+
+//------------------------------------------------------------------------
+// GfxUnivariateShading
+//------------------------------------------------------------------------
+
+class GfxUnivariateShading: public GfxShading {
+public:
+
+ GfxUnivariateShading(int typeA,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ GfxUnivariateShading(GfxUnivariateShading *shading);
+ virtual ~GfxUnivariateShading();
+
+ double getDomain0() { return t0; }
+ double getDomain1() { return t1; }
+ GBool getExtend0() { return extend0; }
+ GBool getExtend1() { return extend1; }
+ int getNFuncs() { return nFuncs; }
+ Function *getFunc(int i) { return funcs[i]; }
+ void getColor(double t, GfxColor *color);
+
+ void setupCache(const Matrix *ctm,
+ double xMin, double yMin,
+ double xMax, double yMax);
+
+ virtual void getParameterRange(double *lower, double *upper,
+ double xMin, double yMin,
+ double xMax, double yMax) = 0;
+
+ virtual double getDistance(double tMin, double tMax) = 0;
+
+private:
+
+ double t0, t1;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+ GBool extend0, extend1;
+
+ int cacheSize, lastMatch;
+ double *cacheBounds;
+ double *cacheCoeff;
+ double *cacheValues;
+};
+
+//------------------------------------------------------------------------
+// GfxFunctionShading
+//------------------------------------------------------------------------
+
+class GfxFunctionShading: public GfxShading {
+public:
+
+ GfxFunctionShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double *matrixA,
+ Function **funcsA, int nFuncsA);
+ GfxFunctionShading(GfxFunctionShading *shading);
+ virtual ~GfxFunctionShading();
+
+ static GfxFunctionShading *parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state);
+
+ virtual GfxShading *copy();
+
+ void getDomain(double *x0A, double *y0A, double *x1A, double *y1A)
+ { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
+ double *getMatrix() { return matrix; }
+ int getNFuncs() { return nFuncs; }
+ Function *getFunc(int i) { return funcs[i]; }
+ void getColor(double x, double y, GfxColor *color);
+
+private:
+
+ double x0, y0, x1, y1;
+ double matrix[6];
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
+// GfxAxialShading
+//------------------------------------------------------------------------
+
+class GfxAxialShading: public GfxUnivariateShading {
+public:
+
+ GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ GfxAxialShading(GfxAxialShading *shading);
+ virtual ~GfxAxialShading();
+
+ static GfxAxialShading *parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state);
+
+ virtual GfxShading *copy();
+
+ void getCoords(double *x0A, double *y0A, double *x1A, double *y1A)
+ { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
+
+ virtual void getParameterRange(double *lower, double *upper,
+ double xMin, double yMin,
+ double xMax, double yMax);
+
+ virtual double getDistance(double tMin, double tMax);
+
+private:
+
+ double x0, y0, x1, y1;
+};
+
+//------------------------------------------------------------------------
+// GfxRadialShading
+//------------------------------------------------------------------------
+
+class GfxRadialShading: public GfxUnivariateShading {
+public:
+
+ GfxRadialShading(double x0A, double y0A, double r0A,
+ double x1A, double y1A, double r1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ GfxRadialShading(GfxRadialShading *shading);
+ virtual ~GfxRadialShading();
+
+ static GfxRadialShading *parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state);
+
+ virtual GfxShading *copy();
+
+ void getCoords(double *x0A, double *y0A, double *r0A,
+ double *x1A, double *y1A, double *r1A)
+ { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; }
+
+ virtual void getParameterRange(double *lower, double *upper,
+ double xMin, double yMin,
+ double xMax, double yMax);
+
+ virtual double getDistance(double tMin, double tMax);
+
+private:
+
+ double x0, y0, r0, x1, y1, r1;
+};
+
+//------------------------------------------------------------------------
+// GfxGouraudTriangleShading
+//------------------------------------------------------------------------
+
+struct GfxGouraudVertex {
+ double x, y;
+ GfxColor color;
+};
+
+class GfxGouraudTriangleShading: public GfxShading {
+public:
+
+ GfxGouraudTriangleShading(int typeA,
+ GfxGouraudVertex *verticesA, int nVerticesA,
+ int (*trianglesA)[3], int nTrianglesA,
+ Function **funcsA, int nFuncsA);
+ GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading);
+ virtual ~GfxGouraudTriangleShading();
+
+ static GfxGouraudTriangleShading *parse(GfxResources *res, int typeA, Dict *dict, Stream *str, OutputDev *out, GfxState *state);
+
+ virtual GfxShading *copy();
+
+ int getNTriangles() { return nTriangles; }
+
+ bool isParameterized() const { return nFuncs > 0; }
+
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMin() const { assert(isParameterized()); return funcs[0]->getDomainMin(0); }
+
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMax() const { assert(isParameterized()); return funcs[0]->getDomainMax(0); }
+
+ /**
+ * @precondition isParameterized() == false
+ */
+ void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
+ double *x1, double *y1, GfxColor *color1,
+ double *x2, double *y2, GfxColor *color2);
+
+ /**
+ * Variant for functions.
+ *
+ * @precondition isParameterized() == true
+ */
+ void getTriangle(int i, double *x0, double *y0, double *color0,
+ double *x1, double *y1, double *color1,
+ double *x2, double *y2, double *color2);
+
+ void getParameterizedColor(double t, GfxColor *color);
+
+private:
+
+ GfxGouraudVertex *vertices;
+ int nVertices;
+ int (*triangles)[3];
+ int nTriangles;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
+// GfxPatchMeshShading
+//------------------------------------------------------------------------
+
+/**
+ * A tensor product cubic bezier patch consisting of 4x4 points and 4 color
+ * values.
+ *
+ * See the Shading Type 7 specifications. Note that Shading Type 6 is also
+ * represented using GfxPatch.
+ */
+struct GfxPatch {
+ /**
+ * Represents a single color value for the patch.
+ */
+ struct ColorValue {
+ /**
+ * For parameterized patches, only element 0 is valid; it contains
+ * the single parameter.
+ *
+ * For non-parameterized patches, c contains all color components
+ * as decoded from the input stream. In this case, you will need to
+ * use dblToCol() before assigning them to GfxColor.
+ */
+ double c[gfxColorMaxComps];
+ };
+
+ double x[4][4];
+ double y[4][4];
+ ColorValue color[2][2];
+};
+
+class GfxPatchMeshShading: public GfxShading {
+public:
+
+ GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA,
+ Function **funcsA, int nFuncsA);
+ GfxPatchMeshShading(GfxPatchMeshShading *shading);
+ virtual ~GfxPatchMeshShading();
+
+ static GfxPatchMeshShading *parse(GfxResources *res, int typeA, Dict *dict, Stream *str, OutputDev *out, GfxState *state);
+
+ virtual GfxShading *copy();
+
+ int getNPatches() { return nPatches; }
+ GfxPatch *getPatch(int i) { return &patches[i]; }
+
+ bool isParameterized() const { return nFuncs > 0; }
+
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMin() const { assert(isParameterized()); return funcs[0]->getDomainMin(0); }
+
+ /**
+ * @precondition isParameterized() == true
+ */
+ double getParameterDomainMax() const { assert(isParameterized()); return funcs[0]->getDomainMax(0); }
+
+ void getParameterizedColor(double t, GfxColor *color);
+
+private:
+
+ GfxPatch *patches;
+ int nPatches;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
+// GfxImageColorMap
+//------------------------------------------------------------------------
+
+class GfxImageColorMap {
+public:
+
+ // Constructor.
+ GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA);
+
+ // Destructor.
+ ~GfxImageColorMap();
+
+ // Return a copy of this color map.
+ GfxImageColorMap *copy() { return new GfxImageColorMap(this); }
+
+ // Is color map valid?
+ GBool isOk() { return ok; }
+
+ // Get the color space.
+ GfxColorSpace *getColorSpace() { return colorSpace; }
+
+ // Get stream decoding info.
+ int getNumPixelComps() { return nComps; }
+ int getBits() { return bits; }
+
+ // Get decode table.
+ double getDecodeLow(int i) { return decodeLow[i]; }
+ double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; }
+
+ bool useRGBLine() { return (colorSpace2 && colorSpace2->useGetRGBLine ()) || (!colorSpace2 && colorSpace->useGetRGBLine ()); }
+ bool useCMYKLine() { return (colorSpace2 && colorSpace2->useGetCMYKLine ()) || (!colorSpace2 && colorSpace->useGetCMYKLine ()); }
+ bool useDeviceNLine() { return (colorSpace2 && colorSpace2->useGetDeviceNLine ()) || (!colorSpace2 && colorSpace->useGetDeviceNLine ()); }
+
+ // Convert an image pixel to a color.
+ void getGray(Guchar *x, GfxGray *gray);
+ void getRGB(Guchar *x, GfxRGB *rgb);
+ void getRGBLine(Guchar *in, unsigned int *out, int length);
+ void getRGBLine(Guchar *in, Guchar *out, int length);
+ void getRGBXLine(Guchar *in, Guchar *out, int length);
+ void getGrayLine(Guchar *in, Guchar *out, int length);
+ void getCMYKLine(Guchar *in, Guchar *out, int length);
+ void getDeviceNLine(Guchar *in, Guchar *out, int length);
+ void getCMYK(Guchar *x, GfxCMYK *cmyk);
+ void getDeviceN(Guchar *x, GfxColor *deviceN);
+ void getColor(Guchar *x, GfxColor *color);
+
+private:
+
+ GfxImageColorMap(GfxImageColorMap *colorMap);
+
+ GfxColorSpace *colorSpace; // the image color space
+ int bits; // bits per component
+ int nComps; // number of components in a pixel
+ GfxColorSpace *colorSpace2; // secondary color space
+ int nComps2; // number of components in colorSpace2
+ GfxColorComp * // lookup table
+ lookup[gfxColorMaxComps];
+ GfxColorComp * // optimized case lookup table
+ lookup2[gfxColorMaxComps];
+ Guchar *byte_lookup;
+ double // minimum values for each component
+ decodeLow[gfxColorMaxComps];
+ double // max - min value for each component
+ decodeRange[gfxColorMaxComps];
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// GfxSubpath and GfxPath
+//------------------------------------------------------------------------
+
+class GfxSubpath {
+public:
+
+ // Constructor.
+ GfxSubpath(double x1, double y1);
+
+ // Destructor.
+ ~GfxSubpath();
+
+ // Copy.
+ GfxSubpath *copy() { return new GfxSubpath(this); }
+
+ // Get points.
+ int getNumPoints() { return n; }
+ double getX(int i) { return x[i]; }
+ double getY(int i) { return y[i]; }
+ GBool getCurve(int i) { return curve[i]; }
+
+ void setX(int i, double a) { x[i] = a; }
+ void setY(int i, double a) { y[i] = a; }
+
+ // Get last point.
+ double getLastX() { return x[n-1]; }
+ double getLastY() { return y[n-1]; }
+
+ // Add a line segment.
+ void lineTo(double x1, double y1);
+
+ // Add a Bezier curve.
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3);
+
+ // Close the subpath.
+ void close();
+ GBool isClosed() { return closed; }
+
+ // Add (<dx>, <dy>) to each point in the subpath.
+ void offset(double dx, double dy);
+
+private:
+
+ double *x, *y; // points
+ GBool *curve; // curve[i] => point i is a control point
+ // for a Bezier curve
+ int n; // number of points
+ int size; // size of x/y arrays
+ GBool closed; // set if path is closed
+
+ GfxSubpath(GfxSubpath *subpath);
+};
+
+class GfxPath {
+public:
+
+ // Constructor.
+ GfxPath();
+
+ // Destructor.
+ ~GfxPath();
+
+ // Copy.
+ GfxPath *copy()
+ { return new GfxPath(justMoved, firstX, firstY, subpaths, n, size); }
+
+ // Is there a current point?
+ GBool isCurPt() { return n > 0 || justMoved; }
+
+ // Is the path non-empty, i.e., is there at least one segment?
+ GBool isPath() { return n > 0; }
+
+ // Get subpaths.
+ int getNumSubpaths() { return n; }
+ GfxSubpath *getSubpath(int i) { return subpaths[i]; }
+
+ // Get last point on last subpath.
+ double getLastX() { return subpaths[n-1]->getLastX(); }
+ double getLastY() { return subpaths[n-1]->getLastY(); }
+
+ // Move the current point.
+ void moveTo(double x, double y);
+
+ // Add a segment to the last subpath.
+ void lineTo(double x, double y);
+
+ // Add a Bezier curve to the last subpath
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3);
+
+ // Close the last subpath.
+ void close();
+
+ // Append <path> to <this>.
+ void append(GfxPath *path);
+
+ // Add (<dx>, <dy>) to each point in the path.
+ void offset(double dx, double dy);
+
+private:
+
+ GBool justMoved; // set if a new subpath was just started
+ double firstX, firstY; // first point in new subpath
+ GfxSubpath **subpaths; // subpaths
+ int n; // number of subpaths
+ int size; // size of subpaths array
+
+ GfxPath(GBool justMoved1, double firstX1, double firstY1,
+ GfxSubpath **subpaths1, int n1, int size1);
+};
+
+//------------------------------------------------------------------------
+// GfxState
+//------------------------------------------------------------------------
+
+class GfxState {
+public:
+ /**
+ * When GfxState::getReusablePath() is invoked, the currently active
+ * path is taken per reference and its coordinates can be re-edited.
+ *
+ * A ReusablePathIterator is intented to reduce overhead when the same
+ * path type is used a lot of times, only with different coordinates. It
+ * allows just to update the coordinates (occuring in the same order as
+ * in the original path).
+ */
+ class ReusablePathIterator {
+ public:
+ /**
+ * Creates the ReusablePathIterator. This should only be done from
+ * GfxState::getReusablePath().
+ *
+ * @param path the path as it is used so far. Changing this path,
+ * deleting it or starting a new path from scratch will most likely
+ * invalidate the iterator (and may cause serious problems). Make
+ * sure the path's memory structure is not changed during the
+ * lifetime of the ReusablePathIterator.
+ */
+ ReusablePathIterator( GfxPath* path );
+
+ /**
+ * Returns true if and only if the current iterator position is
+ * beyond the last valid point.
+ *
+ * A call to setCoord() will be undefined.
+ */
+ bool isEnd() const;
+
+ /**
+ * Advances the iterator.
+ */
+ void next();
+
+ /**
+ * Updates the coordinates associated to the current iterator
+ * position.
+ */
+ void setCoord( double x, double y );
+
+ /**
+ * Resets the iterator.
+ */
+ void reset();
+ private:
+ GfxPath *path;
+ int subPathOff;
+
+ int coordOff;
+ int numCoords;
+
+ GfxSubpath *curSubPath;
+ };
+
+ // 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 hDPIA, double vDPIA, PDFRectangle *pageBox,
+ int rotateA, GBool upsideDown);
+
+ // Destructor.
+ ~GfxState();
+
+ // Copy.
+ GfxState *copy(GBool copyPath = gFalse)
+ { return new GfxState(this, copyPath); }
+
+ // Accessors.
+ double getHDPI() { return hDPI; }
+ double getVDPI() { return vDPI; }
+ double *getCTM() { return ctm; }
+ void getCTM(Matrix *m) { memcpy (m->m, ctm, sizeof m->m); }
+ double getX1() { return px1; }
+ double getY1() { return py1; }
+ double getX2() { return px2; }
+ double getY2() { return py2; }
+ double getPageWidth() { return pageWidth; }
+ double getPageHeight() { return pageHeight; }
+ int getRotate() { return rotate; }
+ GfxColor *getFillColor() { return &fillColor; }
+ GfxColor *getStrokeColor() { return &strokeColor; }
+ void getFillGray(GfxGray *gray)
+ { fillColorSpace->getGray(&fillColor, gray); }
+ void getStrokeGray(GfxGray *gray)
+ { strokeColorSpace->getGray(&strokeColor, gray); }
+ void getFillRGB(GfxRGB *rgb)
+ { fillColorSpace->getRGB(&fillColor, rgb); }
+ void getStrokeRGB(GfxRGB *rgb)
+ { strokeColorSpace->getRGB(&strokeColor, rgb); }
+ void getFillCMYK(GfxCMYK *cmyk)
+ { fillColorSpace->getCMYK(&fillColor, cmyk); }
+ void getFillDeviceN(GfxColor *deviceN)
+ { fillColorSpace->getDeviceN(&fillColor, deviceN); }
+ void getStrokeCMYK(GfxCMYK *cmyk)
+ { strokeColorSpace->getCMYK(&strokeColor, cmyk); }
+ void getStrokeDeviceN(GfxColor *deviceN)
+ { strokeColorSpace->getDeviceN(&strokeColor, deviceN); }
+ GfxColorSpace *getFillColorSpace() { return fillColorSpace; }
+ GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; }
+ GfxPattern *getFillPattern() { return fillPattern; }
+ GfxPattern *getStrokePattern() { return strokePattern; }
+ GfxBlendMode getBlendMode() { return blendMode; }
+ double getFillOpacity() { return fillOpacity; }
+ double getStrokeOpacity() { return strokeOpacity; }
+ GBool getFillOverprint() { return fillOverprint; }
+ GBool getStrokeOverprint() { return strokeOverprint; }
+ int getOverprintMode() { return overprintMode; }
+ Function **getTransfer() { return transfer; }
+ double getLineWidth() { return lineWidth; }
+ void getLineDash(double **dash, int *length, double *start)
+ { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; }
+ int getFlatness() { return flatness; }
+ int getLineJoin() { return lineJoin; }
+ int getLineCap() { return lineCap; }
+ double getMiterLimit() { return miterLimit; }
+ GBool getStrokeAdjust() { return strokeAdjust; }
+ GBool getAlphaIsShape() { return alphaIsShape; }
+ GBool getTextKnockout() { return textKnockout; }
+ GfxFont *getFont() { return font; }
+ double getFontSize() { return fontSize; }
+ double *getTextMat() { return textMat; }
+ double getCharSpace() { return charSpace; }
+ double getWordSpace() { return wordSpace; }
+ double getHorizScaling() { return horizScaling; }
+ double getLeading() { return leading; }
+ double getRise() { return rise; }
+ int getRender() { return render; }
+ char *getRenderingIntent() { return renderingIntent; }
+ GfxPath *getPath() { return path; }
+ void setPath(GfxPath *pathA);
+ double getCurX() { return curX; }
+ double getCurY() { return curY; }
+ void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax)
+ { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; }
+ void getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax);
+ double getLineX() { return lineX; }
+ double getLineY() { return lineY; }
+
+ // Is there a current point/path?
+ GBool isCurPt() { return path->isCurPt(); }
+ GBool isPath() { return path->isPath(); }
+
+ // Transforms.
+ void transform(double x1, double y1, double *x2, double *y2)
+ { *x2 = ctm[0] * x1 + ctm[2] * y1 + ctm[4];
+ *y2 = ctm[1] * x1 + ctm[3] * y1 + ctm[5]; }
+ void transformDelta(double x1, double y1, double *x2, double *y2)
+ { *x2 = ctm[0] * x1 + ctm[2] * y1;
+ *y2 = ctm[1] * x1 + ctm[3] * y1; }
+ void textTransform(double x1, double y1, double *x2, double *y2)
+ { *x2 = textMat[0] * x1 + textMat[2] * y1 + textMat[4];
+ *y2 = textMat[1] * x1 + textMat[3] * y1 + textMat[5]; }
+ void textTransformDelta(double x1, double y1, double *x2, double *y2)
+ { *x2 = textMat[0] * x1 + textMat[2] * y1;
+ *y2 = textMat[1] * x1 + textMat[3] * y1; }
+ double transformWidth(double w);
+ double getTransformedLineWidth()
+ { return transformWidth(lineWidth); }
+ double getTransformedFontSize();
+ void getFontTransMat(double *m11, double *m12, double *m21, double *m22);
+
+ // Change state parameters.
+ void setCTM(double a, double b, double c,
+ double d, double e, double f);
+ void concatCTM(double a, double b, double c,
+ double d, double e, double f);
+ void shiftCTMAndClip(double tx, double ty);
+ void setFillColorSpace(GfxColorSpace *colorSpace);
+ void setStrokeColorSpace(GfxColorSpace *colorSpace);
+ void setFillColor(GfxColor *color) { fillColor = *color; }
+ void setStrokeColor(GfxColor *color) { strokeColor = *color; }
+ void setFillPattern(GfxPattern *pattern);
+ void setStrokePattern(GfxPattern *pattern);
+ void setBlendMode(GfxBlendMode mode) { blendMode = mode; }
+ void setFillOpacity(double opac) { fillOpacity = opac; }
+ void setStrokeOpacity(double opac) { strokeOpacity = opac; }
+ void setFillOverprint(GBool op) { fillOverprint = op; }
+ void setStrokeOverprint(GBool op) { strokeOverprint = op; }
+ void setOverprintMode(int op) { overprintMode = 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 setAlphaIsShape(GBool ais) { alphaIsShape = ais; }
+ void setTextKnockout(GBool tk) { textKnockout = tk; }
+ void setFont(GfxFont *fontA, double fontSizeA);
+ void setTextMat(double a, double b, double c,
+ double d, double e, double f)
+ { textMat[0] = a; textMat[1] = b; textMat[2] = c;
+ textMat[3] = d; textMat[4] = e; textMat[5] = f; }
+ void setCharSpace(double space)
+ { charSpace = space; }
+ void setWordSpace(double space)
+ { wordSpace = space; }
+ void setHorizScaling(double scale)
+ { horizScaling = 0.01 * scale; }
+ void setLeading(double leadingA)
+ { leading = leadingA; }
+ void setRise(double riseA)
+ { rise = riseA; }
+ void setRender(int renderA)
+ { render = renderA; }
+ void setRenderingIntent(const char *intent)
+ { strncpy(renderingIntent, intent, 31); }
+
+#ifdef USE_CMS
+ void setDisplayProfile(void *localDisplayProfileA);
+ void *getDisplayProfile() { return localDisplayProfile; }
+ GfxColorTransform *getXYZ2DisplayTransform();
+#endif
+
+ // Add to path.
+ void moveTo(double x, double y)
+ { path->moveTo(curX = x, curY = y); }
+ void lineTo(double x, double y)
+ { path->lineTo(curX = x, curY = y); }
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3)
+ { path->curveTo(x1, y1, x2, y2, curX = x3, curY = y3); }
+ void closePath()
+ { path->close(); curX = path->getLastX(); curY = path->getLastY(); }
+ void clearPath();
+
+ // Update clip region.
+ void clip();
+ void clipToStrokePath();
+ void clipToRect(double xMin, double yMin, double xMax, double yMax);
+
+ // Text position.
+ void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; }
+ void textMoveTo(double tx, double ty)
+ { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); }
+ void textShift(double tx, double ty);
+ void shift(double dx, double dy);
+
+ // Push/pop GfxState on/off stack.
+ GfxState *save();
+ GfxState *restore();
+ GBool hasSaves() { return saved != NULL; }
+ GBool isParentState(GfxState *state) { return saved == state || (saved && saved->isParentState(state)); }
+
+ // Misc
+ GBool parseBlendMode(Object *obj, GfxBlendMode *mode);
+
+ ReusablePathIterator *getReusablePath() { return new ReusablePathIterator(path); }
+private:
+
+ double hDPI, vDPI; // resolution
+ double ctm[6]; // coord transform matrix
+ double px1, py1, px2, py2; // page corners (user coords)
+ double pageWidth, pageHeight; // page size (pixels)
+ int rotate; // page rotation angle
+
+ GfxColorSpace *fillColorSpace; // fill color space
+ GfxColorSpace *strokeColorSpace; // stroke color space
+ GfxColor fillColor; // fill color
+ GfxColor strokeColor; // stroke color
+ GfxPattern *fillPattern; // fill pattern
+ GfxPattern *strokePattern; // stroke pattern
+ GfxBlendMode blendMode; // transparency blend mode
+ double fillOpacity; // fill opacity
+ double strokeOpacity; // stroke opacity
+ GBool fillOverprint; // fill overprint
+ GBool strokeOverprint; // stroke overprint
+ int overprintMode; // overprint mode
+ Function *transfer[4]; // transfer function (entries may be: all
+ // NULL = identity; last three NULL =
+ // single function; all four non-NULL =
+ // R,G,B,gray functions)
+
+ double lineWidth; // line width
+ double *lineDash; // line dash
+ int lineDashLength;
+ double lineDashStart;
+ int flatness; // curve flatness
+ int lineJoin; // line join style
+ int lineCap; // line cap style
+ double miterLimit; // line miter limit
+ GBool strokeAdjust; // stroke adjustment
+ GBool alphaIsShape; // alpha is shape
+ GBool textKnockout; // text knockout
+
+ GfxFont *font; // font
+ double fontSize; // font size
+ double textMat[6]; // text matrix
+ double charSpace; // character spacing
+ double wordSpace; // word spacing
+ double horizScaling; // horizontal scaling
+ double leading; // text leading
+ double rise; // text rise
+ int render; // text rendering mode
+
+ GfxPath *path; // array of path elements
+ double curX, curY; // current point (user coords)
+ double lineX, lineY; // start of current text line (text coords)
+
+ double clipXMin, clipYMin, // bounding box for clip region
+ clipXMax, clipYMax;
+ char renderingIntent[32];
+
+ GfxState *saved; // next GfxState on stack
+
+ GfxState(GfxState *state, GBool copyPath);
+
+#ifdef USE_CMS
+ void *localDisplayProfile;
+ int displayProfileRef;
+ GfxColorTransform *XYZ2DisplayTransformRelCol;
+ GfxColorTransform *XYZ2DisplayTransformAbsCol;
+ GfxColorTransform *XYZ2DisplayTransformSat;
+ GfxColorTransform *XYZ2DisplayTransformPerc;
+#endif
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState_helpers.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState_helpers.h
new file mode 100644
index 00000000000..bc0024edd79
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/GfxState_helpers.h
@@ -0,0 +1,82 @@
+//========================================================================
+//
+// GfxState.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009, 2011 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include "GfxState.h"
+
+static inline GfxColorComp clip01(GfxColorComp x) {
+ return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
+}
+
+static inline double clip01(double x) {
+ return (x < 0) ? 0 : (x > 1) ? 1 : x;
+}
+
+static inline void cmykToRGBMatrixMultiplication(const double &c, const double &m, const double &y, const double &k, const double &c1, const double &m1, const double &y1, const double &k1, double &r, double &g, double &b)
+{
+ double x;
+ // this is a matrix multiplication, unrolled for performance
+ // C M Y K
+ x = c1 * m1 * y1 * k1; // 0 0 0 0
+ r = g = b = x;
+ x = c1 * m1 * y1 * k; // 0 0 0 1
+ r += 0.1373 * x;
+ g += 0.1216 * x;
+ b += 0.1255 * x;
+ x = c1 * m1 * y * k1; // 0 0 1 0
+ r += x;
+ g += 0.9490 * x;
+ x = c1 * m1 * y * k; // 0 0 1 1
+ r += 0.1098 * x;
+ g += 0.1020 * x;
+ x = c1 * m * y1 * k1; // 0 1 0 0
+ r += 0.9255 * x;
+ b += 0.5490 * x;
+ x = c1 * m * y1 * k; // 0 1 0 1
+ r += 0.1412 * x;
+ x = c1 * m * y * k1; // 0 1 1 0
+ r += 0.9294 * x;
+ g += 0.1098 * x;
+ b += 0.1412 * x;
+ x = c1 * m * y * k; // 0 1 1 1
+ r += 0.1333 * x;
+ x = c * m1 * y1 * k1; // 1 0 0 0
+ g += 0.6784 * x;
+ b += 0.9373 * x;
+ x = c * m1 * y1 * k; // 1 0 0 1
+ g += 0.0588 * x;
+ b += 0.1412 * x;
+ x = c * m1 * y * k1; // 1 0 1 0
+ g += 0.6510 * x;
+ b += 0.3137 * x;
+ x = c * m1 * y * k; // 1 0 1 1
+ g += 0.0745 * x;
+ x = c * m * y1 * k1; // 1 1 0 0
+ r += 0.1804 * x;
+ g += 0.1922 * x;
+ b += 0.5725 * x;
+ x = c * m * y1 * k; // 1 1 0 1
+ b += 0.0078 * x;
+ x = c * m * y * k1; // 1 1 1 0
+ r += 0.2118 * x;
+ g += 0.2119 * x;
+ b += 0.2235 * x;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParams.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParams.cc
new file mode 100644
index 00000000000..e5434084c31
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParams.cc
@@ -0,0 +1,2031 @@
+//========================================================================
+//
+// GlobalParams.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
+// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005, 2007-2010, 2012, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
+// Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2006 Ed Catmur <ed@catmur.co.uk>
+// Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2007, 2009 Jonathan Kew <jonathan_kew@sil.org>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2009, 2011, 2012, 2015 William Bader <williambader@hotmail.com>
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2010, 2012 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2010 Patrick Spendrin <ps_ml@gmx.de>
+// Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net>
+// Copyright (C) 2011 Pino Toscano <pino@kde.org>
+// Copyright (C) 2011 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2012 Yi Yang <ahyangyi@gmail.com>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Peter Breitenlohner <peb@mppmu.mpg.de>
+// Copyright (C) 2013, 2014 Jason Crain <jason@aquaticape.us>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#ifdef ENABLE_PLUGINS
+# ifndef _WIN32
+# include <dlfcn.h>
+# endif
+#endif
+#ifdef _WIN32
+# include <shlobj.h>
+# include <mbstring.h>
+#endif
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "goo/GooList.h"
+#include "goo/GooHash.h"
+#include "goo/gfile.h"
+#include "Error.h"
+#include "NameToCharCode.h"
+#include "CharCodeToUnicode.h"
+#include "UnicodeMap.h"
+#include "CMap.h"
+#include "BuiltinFontTables.h"
+#include "FontEncodingTables.h"
+#ifdef ENABLE_PLUGINS
+# include "XpdfPluginAPI.h"
+#endif
+#include "GlobalParams.h"
+#include "GfxFont.h"
+
+#if WITH_FONTCONFIGURATION_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#endif
+
+#ifdef _WIN32
+# define strcasecmp stricmp
+#else
+# include <strings.h>
+#endif
+
+#if MULTITHREADED
+# define lockGlobalParams gLockMutex(&mutex)
+# define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex)
+# define lockCMapCache gLockMutex(&cMapCacheMutex)
+# define unlockGlobalParams gUnlockMutex(&mutex)
+# define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex)
+# define unlockCMapCache gUnlockMutex(&cMapCacheMutex)
+#else
+# define lockGlobalParams
+# define lockUnicodeMapCache
+# define lockCMapCache
+# define unlockGlobalParams
+# define unlockUnicodeMapCache
+# define unlockCMapCache
+#endif
+
+#ifndef FC_WEIGHT_BOOK
+#define FC_WEIGHT_BOOK 75
+#endif
+
+#include "NameToUnicodeTable.h"
+#include "UnicodeMapTables.h"
+#include "UTF8.h"
+
+#ifdef ENABLE_PLUGINS
+# ifdef _WIN32
+extern XpdfPluginVecTable xpdfPluginVecTable;
+# endif
+#endif
+
+//------------------------------------------------------------------------
+
+#define cidToUnicodeCacheSize 4
+#define unicodeToUnicodeCacheSize 4
+
+//------------------------------------------------------------------------
+
+GlobalParams *globalParams = NULL;
+
+//------------------------------------------------------------------------
+// PSFontParam16
+//------------------------------------------------------------------------
+
+PSFontParam16::PSFontParam16(GooString *nameA, int wModeA,
+ GooString *psFontNameA, GooString *encodingA) {
+ name = nameA;
+ wMode = wModeA;
+ psFontName = psFontNameA;
+ encoding = encodingA;
+}
+
+PSFontParam16::~PSFontParam16() {
+ delete name;
+ delete psFontName;
+ delete encoding;
+}
+
+#if ENABLE_RELOCATABLE && defined(_WIN32)
+
+/* search for data relative to where we are installed */
+
+static HMODULE hmodule;
+
+extern "C" {
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ hmodule = hinstDLL;
+ break;
+ }
+
+ return TRUE;
+}
+}
+
+static const char *
+get_poppler_datadir (void)
+{
+ static char retval[MAX_PATH];
+ static int beenhere = 0;
+
+ unsigned char *p;
+
+ if (beenhere)
+ return retval;
+
+ if (!GetModuleFileName (hmodule, (CHAR *) retval, sizeof(retval) - 20))
+ return POPPLER_DATADIR;
+
+ p = _mbsrchr ((unsigned char *) retval, '\\');
+ *p = '\0';
+ p = _mbsrchr ((unsigned char *) retval, '\\');
+ if (p) {
+ if (stricmp ((const char *) (p+1), "bin") == 0)
+ *p = '\0';
+ }
+ strcat (retval, "\\share\\poppler");
+
+ beenhere = 1;
+
+ return retval;
+}
+
+#undef POPPLER_DATADIR
+#define POPPLER_DATADIR get_poppler_datadir ()
+
+#endif
+
+//------------------------------------------------------------------------
+// SysFontInfo
+//------------------------------------------------------------------------
+
+class SysFontInfo {
+public:
+
+ GooString *name;
+ GBool bold;
+ GBool italic;
+ GBool oblique;
+ GBool fixedWidth;
+ GooString *path;
+ SysFontType type;
+ int fontNum; // for TrueType collections
+ GooString *substituteName;
+
+ SysFontInfo(GooString *nameA, GBool boldA, GBool italicA, GBool obliqueA, GBool fixedWidthA,
+ GooString *pathA, SysFontType typeA, int fontNumA, GooString *substituteNameA);
+ ~SysFontInfo();
+ GBool match(SysFontInfo *fi);
+ GBool match(GooString *nameA, GBool boldA, GBool italicA, GBool obliqueA, GBool fixedWidthA);
+ GBool match(GooString *nameA, GBool boldA, GBool italicA);
+};
+
+SysFontInfo::SysFontInfo(GooString *nameA, GBool boldA, GBool italicA, GBool obliqueA, GBool fixedWidthA,
+ GooString *pathA, SysFontType typeA, int fontNumA, GooString *substituteNameA) {
+ name = nameA;
+ bold = boldA;
+ italic = italicA;
+ oblique = obliqueA;
+ fixedWidth = fixedWidthA;
+ path = pathA;
+ type = typeA;
+ fontNum = fontNumA;
+ substituteName = substituteNameA;
+}
+
+SysFontInfo::~SysFontInfo() {
+ delete name;
+ delete path;
+ delete substituteName;
+}
+
+GBool SysFontInfo::match(SysFontInfo *fi) {
+ return !strcasecmp(name->getCString(), fi->name->getCString()) &&
+ bold == fi->bold && italic == fi->italic && oblique == fi->oblique && fixedWidth == fi->fixedWidth;
+}
+
+GBool SysFontInfo::match(GooString *nameA, GBool boldA, GBool italicA, GBool obliqueA, GBool fixedWidthA) {
+ return !strcasecmp(name->getCString(), nameA->getCString()) &&
+ bold == boldA && italic == italicA && oblique == obliqueA && fixedWidth == fixedWidthA;
+}
+
+GBool SysFontInfo::match(GooString *nameA, GBool boldA, GBool italicA) {
+ return !strcasecmp(name->getCString(), nameA->getCString()) &&
+ bold == boldA && italic == italicA;
+}
+
+//------------------------------------------------------------------------
+// SysFontList
+//------------------------------------------------------------------------
+
+class SysFontList {
+public:
+
+ SysFontList();
+ ~SysFontList();
+ SysFontInfo *find(GooString *name, GBool isFixedWidth, GBool exact);
+
+#ifdef WIN32
+ void scanWindowsFonts(GooString *winFontDir);
+#endif
+#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
+ void addFcFont(SysFontInfo *si) {fonts->append(si);}
+#endif
+private:
+
+#ifdef WIN32
+ SysFontInfo *makeWindowsFont(char *name, int fontNum,
+ char *path);
+#endif
+
+ GooList *fonts; // [SysFontInfo]
+};
+
+SysFontList::SysFontList() {
+ fonts = new GooList();
+}
+
+SysFontList::~SysFontList() {
+ deleteGooList(fonts, SysFontInfo);
+}
+
+SysFontInfo *SysFontList::find(GooString *name, GBool fixedWidth, GBool exact) {
+ GooString *name2;
+ GBool bold, italic, oblique;
+ SysFontInfo *fi;
+ char c;
+ int n, i;
+
+ name2 = name->copy();
+
+ // remove space, comma, dash chars
+ i = 0;
+ while (i < name2->getLength()) {
+ c = name2->getChar(i);
+ if (c == ' ' || c == ',' || c == '-') {
+ name2->del(i);
+ } else {
+ ++i;
+ }
+ }
+ n = name2->getLength();
+
+ // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
+ if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
+ name2->del(n - 2, 2);
+ n -= 2;
+ }
+
+ // look for "Regular"
+ if (n > 7 && !strcmp(name2->getCString() + n - 7, "Regular")) {
+ name2->del(n - 7, 7);
+ n -= 7;
+ }
+
+ // look for "Italic"
+ if (n > 6 && !strcmp(name2->getCString() + n - 6, "Italic")) {
+ name2->del(n - 6, 6);
+ italic = gTrue;
+ n -= 6;
+ } else {
+ italic = gFalse;
+ }
+
+ // look for "Oblique"
+ if (n > 6 && !strcmp(name2->getCString() + n - 7, "Oblique")) {
+ name2->del(n - 7, 7);
+ oblique = gTrue;
+ n -= 6;
+ } else {
+ oblique = gFalse;
+ }
+
+ // look for "Bold"
+ if (n > 4 && !strcmp(name2->getCString() + n - 4, "Bold")) {
+ name2->del(n - 4, 4);
+ bold = gTrue;
+ n -= 4;
+ } else {
+ bold = gFalse;
+ }
+
+ // remove trailing "MT" (FooMT-Bold, etc.)
+ if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
+ name2->del(n - 2, 2);
+ n -= 2;
+ }
+
+ // remove trailing "PS"
+ if (n > 2 && !strcmp(name2->getCString() + n - 2, "PS")) {
+ name2->del(n - 2, 2);
+ n -= 2;
+ }
+
+ // remove trailing "IdentityH"
+ if (n > 9 && !strcmp(name2->getCString() + n - 9, "IdentityH")) {
+ name2->del(n - 9, 9);
+ n -= 9;
+ }
+
+ // search for the font
+ fi = NULL;
+ for (i = 0; i < fonts->getLength(); ++i) {
+ fi = (SysFontInfo *)fonts->get(i);
+ if (fi->match(name2, bold, italic, oblique, fixedWidth)) {
+ break;
+ }
+ fi = NULL;
+ }
+ if (!fi && !exact && bold) {
+ // try ignoring the bold flag
+ for (i = 0; i < fonts->getLength(); ++i) {
+ fi = (SysFontInfo *)fonts->get(i);
+ if (fi->match(name2, gFalse, italic)) {
+ break;
+ }
+ fi = NULL;
+ }
+ }
+ if (!fi && !exact && (bold || italic)) {
+ // try ignoring the bold and italic flags
+ for (i = 0; i < fonts->getLength(); ++i) {
+ fi = (SysFontInfo *)fonts->get(i);
+ if (fi->match(name2, gFalse, gFalse)) {
+ break;
+ }
+ fi = NULL;
+ }
+ }
+
+ delete name2;
+ return fi;
+}
+
+
+#ifdef ENABLE_PLUGINS
+//------------------------------------------------------------------------
+// Plugin
+//------------------------------------------------------------------------
+
+class Plugin {
+public:
+
+ static Plugin *load(char *type, char *name);
+ ~Plugin();
+
+private:
+
+#ifdef _WIN32
+ Plugin(HMODULE libA);
+ HMODULE lib;
+#else
+ Plugin(void *dlA);
+ void *dl;
+#endif
+};
+
+Plugin *Plugin::load(char *type, char *name) {
+ GooString *path;
+ Plugin *plugin;
+ XpdfPluginVecTable *vt;
+ XpdfBool (*xpdfInitPlugin)(void);
+#ifdef _WIN32
+ HMODULE libA;
+#else
+ void *dlA;
+#endif
+
+ path = new GooString(POPPLER_DATADIR);
+ appendToPath(path, "plugins");
+ appendToPath(path, type);
+ appendToPath(path, name);
+
+#ifdef _WIN32
+ path->append(".dll");
+ if (!(libA = LoadLibrary(path->getCString()))) {
+ error(errIO, -1, "Failed to load plugin '{0:t}'", path);
+ goto err1;
+ }
+ if (!(vt = (XpdfPluginVecTable *)
+ GetProcAddress(libA, "xpdfPluginVecTable"))) {
+ error(errIO, -1, "Failed to find xpdfPluginVecTable in plugin '{0:t}'",
+ path);
+ goto err2;
+ }
+#else
+ //~ need to deal with other extensions here
+ path->append(".so");
+ if (!(dlA = dlopen(path->getCString(), RTLD_NOW))) {
+ error(errIO, -1, "Failed to load plugin '{0:t}': {1:s}",
+ path, dlerror());
+ goto err1;
+ }
+ if (!(vt = (XpdfPluginVecTable *)dlsym(dlA, "xpdfPluginVecTable"))) {
+ error(errIO, -1, "Failed to find xpdfPluginVecTable in plugin '{0:t}'",
+ path);
+ goto err2;
+ }
+#endif
+
+ if (vt->version != xpdfPluginVecTable.version) {
+ error(errIO, -1, "Plugin '{0:t}' is wrong version", path);
+ goto err2;
+ }
+ memcpy(vt, &xpdfPluginVecTable, sizeof(xpdfPluginVecTable));
+
+#ifdef _WIN32
+ if (!(xpdfInitPlugin = (XpdfBool (*)(void))
+ GetProcAddress(libA, "xpdfInitPlugin"))) {
+ error(errIO, -1, "Failed to find xpdfInitPlugin in plugin '{0:t}'",
+ path);
+ goto err2;
+ }
+#else
+ if (!(xpdfInitPlugin = (XpdfBool (*)(void))dlsym(dlA, "xpdfInitPlugin"))) {
+ error(errIO, -1, "Failed to find xpdfInitPlugin in plugin '{0:t}'",
+ path);
+ goto err2;
+ }
+#endif
+
+ if (!(*xpdfInitPlugin)()) {
+ error(errIO, -1, "Initialization of plugin '{0:t}' failed", path);
+ goto err2;
+ }
+
+#ifdef _WIN32
+ plugin = new Plugin(libA);
+#else
+ plugin = new Plugin(dlA);
+#endif
+
+ delete path;
+ return plugin;
+
+ err2:
+#ifdef _WIN32
+ FreeLibrary(libA);
+#else
+ dlclose(dlA);
+#endif
+ err1:
+ delete path;
+ return NULL;
+}
+
+#ifdef _WIN32
+Plugin::Plugin(HMODULE libA) {
+ lib = libA;
+}
+#else
+Plugin::Plugin(void *dlA) {
+ dl = dlA;
+}
+#endif
+
+Plugin::~Plugin() {
+ void (*xpdfFreePlugin)(void);
+
+#ifdef _WIN32
+ if ((xpdfFreePlugin = (void (*)(void))
+ GetProcAddress(lib, "xpdfFreePlugin"))) {
+ (*xpdfFreePlugin)();
+ }
+ FreeLibrary(lib);
+#else
+ if ((xpdfFreePlugin = (void (*)(void))dlsym(dl, "xpdfFreePlugin"))) {
+ (*xpdfFreePlugin)();
+ }
+ dlclose(dl);
+#endif
+}
+
+#endif // ENABLE_PLUGINS
+
+//------------------------------------------------------------------------
+// parsing
+//------------------------------------------------------------------------
+
+GlobalParams::GlobalParams(const char *customPopplerDataDir)
+ : popplerDataDir(customPopplerDataDir)
+{
+ UnicodeMap *map;
+ int i;
+
+#if MULTITHREADED
+ gInitMutex(&mutex);
+ gInitMutex(&unicodeMapCacheMutex);
+ gInitMutex(&cMapCacheMutex);
+#endif
+
+ initBuiltinFontTables();
+
+ // scan the encoding in reverse because we want the lowest-numbered
+ // index for each char name ('space' is encoded twice)
+ macRomanReverseMap = new NameToCharCode();
+ for (i = 255; i >= 0; --i) {
+ if (macRomanEncoding[i]) {
+ macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i);
+ }
+ }
+
+#ifdef _WIN32
+ substFiles = new GooHash(gTrue);
+#endif
+ nameToUnicodeZapfDingbats = new NameToCharCode();
+ nameToUnicodeText = new NameToCharCode();
+ cidToUnicodes = new GooHash(gTrue);
+ unicodeToUnicodes = new GooHash(gTrue);
+ residentUnicodeMaps = new GooHash();
+ unicodeMaps = new GooHash(gTrue);
+ cMapDirs = new GooHash(gTrue);
+ toUnicodeDirs = new GooList();
+ fontFiles = new GooHash(gTrue);
+ fontDirs = new GooList();
+ ccFontFiles = new GooHash(gTrue);
+ sysFonts = new SysFontList();
+ psExpandSmaller = gFalse;
+ psShrinkLarger = gTrue;
+ psCenter = gTrue;
+ psLevel = psLevel2;
+ psFile = NULL;
+ psResidentFonts = new GooHash(gTrue);
+ psResidentFonts16 = new GooList();
+ psResidentFontsCC = new GooList();
+ textEncoding = new GooString("UTF-8");
+#if defined(_WIN32)
+ textEOL = eolDOS;
+#elif defined(MACOS)
+ textEOL = eolMac;
+#else
+ textEOL = eolUnix;
+#endif
+ textPageBreaks = gTrue;
+ textKeepTinyChars = gFalse;
+ enableFreeType = gTrue;
+ strokeAdjust = gTrue;
+ screenType = screenUnset;
+ screenSize = -1;
+ screenDotRadius = -1;
+ screenGamma = 1.0;
+ screenBlackThreshold = 0.0;
+ screenWhiteThreshold = 1.0;
+ minLineWidth = 0.0;
+ overprintPreview = gFalse;
+ mapNumericCharNames = gTrue;
+ mapUnknownCharNames = gTrue;
+ printCommands = gFalse;
+ profileCommands = gFalse;
+ errQuiet = gFalse;
+
+ cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize);
+ unicodeToUnicodeCache =
+ new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize);
+ unicodeMapCache = new UnicodeMapCache();
+ cMapCache = new CMapCache();
+
+ baseFontsInitialized = gFalse;
+#ifdef ENABLE_PLUGINS
+ plugins = new GooList();
+ securityHandlers = new GooList();
+#endif
+
+ // set up the initial nameToUnicode tables
+ for (i = 0; nameToUnicodeZapfDingbatsTab[i].name; ++i) {
+ nameToUnicodeZapfDingbats->add(nameToUnicodeZapfDingbatsTab[i].name, nameToUnicodeZapfDingbatsTab[i].u);
+ }
+
+ for (i = 0; nameToUnicodeTextTab[i].name; ++i) {
+ nameToUnicodeText->add(nameToUnicodeTextTab[i].name, nameToUnicodeTextTab[i].u);
+ }
+
+ // set up the residentUnicodeMaps table
+ map = new UnicodeMap("Latin1", gFalse,
+ latin1UnicodeMapRanges, latin1UnicodeMapLen);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("ASCII7", gFalse,
+ ascii7UnicodeMapRanges, ascii7UnicodeMapLen);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("Symbol", gFalse,
+ symbolUnicodeMapRanges, symbolUnicodeMapLen);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("ZapfDingbats", gFalse, zapfDingbatsUnicodeMapRanges,
+ zapfDingbatsUnicodeMapLen);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("UTF-8", gTrue, &mapUTF8);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("UCS-2", gTrue, &mapUCS2);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+
+ scanEncodingDirs();
+}
+
+void GlobalParams::scanEncodingDirs() {
+ GDir *dir;
+ GDirEntry *entry;
+ const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR;
+
+ // allocate buffer large enough to append "/nameToUnicode"
+ size_t bufSize = strlen(dataRoot) + strlen("/nameToUnicode") + 1;
+ char *dataPathBuffer = new char[bufSize];
+
+ snprintf(dataPathBuffer, bufSize, "%s/nameToUnicode", dataRoot);
+ dir = new GDir(dataPathBuffer, gTrue);
+ while (entry = dir->getNextEntry(), entry != NULL) {
+ if (!entry->isDir()) {
+ parseNameToUnicode(entry->getFullPath());
+ }
+ delete entry;
+ }
+ delete dir;
+
+ snprintf(dataPathBuffer, bufSize, "%s/cidToUnicode", dataRoot);
+ dir = new GDir(dataPathBuffer, gFalse);
+ while (entry = dir->getNextEntry(), entry != NULL) {
+ addCIDToUnicode(entry->getName(), entry->getFullPath());
+ delete entry;
+ }
+ delete dir;
+
+ snprintf(dataPathBuffer, bufSize, "%s/unicodeMap", dataRoot);
+ dir = new GDir(dataPathBuffer, gFalse);
+ while (entry = dir->getNextEntry(), entry != NULL) {
+ addUnicodeMap(entry->getName(), entry->getFullPath());
+ delete entry;
+ }
+ delete dir;
+
+ snprintf(dataPathBuffer, bufSize, "%s/cMap", dataRoot);
+ dir = new GDir(dataPathBuffer, gFalse);
+ while (entry = dir->getNextEntry(), entry != NULL) {
+ addCMapDir(entry->getName(), entry->getFullPath());
+ toUnicodeDirs->append(entry->getFullPath()->copy());
+ delete entry;
+ }
+ delete dir;
+
+ delete[] dataPathBuffer;
+}
+
+void GlobalParams::parseNameToUnicode(GooString *name) {
+ char *tok1, *tok2;
+ FILE *f;
+ char buf[256];
+ int line;
+ Unicode u;
+ char *tokptr;
+
+ if (!(f = openFile(name->getCString(), "r"))) {
+ error(errIO, -1, "Couldn't open 'nameToUnicode' file '{0:t}'",
+ name);
+ return;
+ }
+ line = 1;
+ while (getLine(buf, sizeof(buf), f)) {
+ tok1 = strtok_r(buf, " \t\r\n", &tokptr);
+ tok2 = strtok_r(NULL, " \t\r\n", &tokptr);
+ if (tok1 && tok2) {
+ sscanf(tok1, "%x", &u);
+ nameToUnicodeText->add(tok2, u);
+ } else {
+ error(errConfig, -1, "Bad line in 'nameToUnicode' file ({0:t}:{1:d})",
+ name, line);
+ }
+ ++line;
+ }
+ fclose(f);
+}
+
+void GlobalParams::addCIDToUnicode(GooString *collection,
+ GooString *fileName) {
+ GooString *old;
+
+ if ((old = (GooString *)cidToUnicodes->remove(collection))) {
+ delete old;
+ }
+ cidToUnicodes->add(collection->copy(), fileName->copy());
+}
+
+void GlobalParams::addUnicodeMap(GooString *encodingName, GooString *fileName)
+{
+ GooString *old;
+
+ if ((old = (GooString *)unicodeMaps->remove(encodingName))) {
+ delete old;
+ }
+ unicodeMaps->add(encodingName->copy(), fileName->copy());
+}
+
+void GlobalParams::addCMapDir(GooString *collection, GooString *dir) {
+ GooList *list;
+
+ if (!(list = (GooList *)cMapDirs->lookup(collection))) {
+ list = new GooList();
+ cMapDirs->add(collection->copy(), list);
+ }
+ list->append(dir->copy());
+}
+
+GBool GlobalParams::parseYesNo2(const char *token, GBool *flag) {
+ if (!strcmp(token, "yes")) {
+ *flag = gTrue;
+ } else if (!strcmp(token, "no")) {
+ *flag = gFalse;
+ } else {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+GlobalParams::~GlobalParams() {
+ freeBuiltinFontTables();
+
+ delete macRomanReverseMap;
+
+ delete nameToUnicodeZapfDingbats;
+ delete nameToUnicodeText;
+ deleteGooHash(cidToUnicodes, GooString);
+ deleteGooHash(unicodeToUnicodes, GooString);
+ deleteGooHash(residentUnicodeMaps, UnicodeMap);
+ deleteGooHash(unicodeMaps, GooString);
+ deleteGooList(toUnicodeDirs, GooString);
+ deleteGooHash(fontFiles, GooString);
+ deleteGooList(fontDirs, GooString);
+ deleteGooHash(ccFontFiles, GooString);
+#ifdef _WIN32
+ deleteGooHash(substFiles, GooString);
+#endif
+ delete sysFonts;
+ if (psFile) {
+ delete psFile;
+ }
+ deleteGooHash(psResidentFonts, GooString);
+ deleteGooList(psResidentFonts16, PSFontParam16);
+ deleteGooList(psResidentFontsCC, PSFontParam16);
+ delete textEncoding;
+
+ GooHashIter *iter;
+ GooString *key;
+ cMapDirs->startIter(&iter);
+ void *val;
+ while (cMapDirs->getNext(&iter, &key, &val)) {
+ GooList* list = (GooList*)val;
+ deleteGooList(list, GooString);
+ }
+ delete cMapDirs;
+
+ delete cidToUnicodeCache;
+ delete unicodeToUnicodeCache;
+ delete unicodeMapCache;
+ delete cMapCache;
+
+#ifdef ENABLE_PLUGINS
+ delete securityHandlers;
+ deleteGooList(plugins, Plugin);
+#endif
+
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+ gDestroyMutex(&unicodeMapCacheMutex);
+ gDestroyMutex(&cMapCacheMutex);
+#endif
+}
+
+//------------------------------------------------------------------------
+// accessors
+//------------------------------------------------------------------------
+
+CharCode GlobalParams::getMacRomanCharCode(char *charName) {
+ // no need to lock - macRomanReverseMap is constant
+ return macRomanReverseMap->lookup(charName);
+}
+
+Unicode GlobalParams::mapNameToUnicodeAll(const char *charName) {
+ // no need to lock - nameToUnicodeZapfDingbats and nameToUnicodeText are constant
+ Unicode u = nameToUnicodeZapfDingbats->lookup(charName);
+ if (!u)
+ u = nameToUnicodeText->lookup(charName);
+ return u;
+}
+
+Unicode GlobalParams::mapNameToUnicodeText(const char *charName) {
+ // no need to lock - nameToUnicodeText is constant
+ return nameToUnicodeText->lookup(charName);
+}
+
+UnicodeMap *GlobalParams::getResidentUnicodeMap(GooString *encodingName) {
+ UnicodeMap *map;
+
+ lockGlobalParams;
+ map = (UnicodeMap *)residentUnicodeMaps->lookup(encodingName);
+ unlockGlobalParams;
+ if (map) {
+ map->incRefCnt();
+ }
+ return map;
+}
+
+FILE *GlobalParams::getUnicodeMapFile(GooString *encodingName) {
+ GooString *fileName;
+ FILE *f;
+
+ lockGlobalParams;
+ if ((fileName = (GooString *)unicodeMaps->lookup(encodingName))) {
+ f = openFile(fileName->getCString(), "r");
+ } else {
+ f = NULL;
+ }
+ unlockGlobalParams;
+ return f;
+}
+
+FILE *GlobalParams::findCMapFile(GooString *collection, GooString *cMapName) {
+ GooList *list;
+ GooString *dir;
+ GooString *fileName;
+ FILE *f;
+ int i;
+
+ lockGlobalParams;
+ if (!(list = (GooList *)cMapDirs->lookup(collection))) {
+ unlockGlobalParams;
+ return NULL;
+ }
+ for (i = 0; i < list->getLength(); ++i) {
+ dir = (GooString *)list->get(i);
+ fileName = appendToPath(dir->copy(), cMapName->getCString());
+ f = openFile(fileName->getCString(), "r");
+ delete fileName;
+ if (f) {
+ unlockGlobalParams;
+ return f;
+ }
+ }
+ unlockGlobalParams;
+ return NULL;
+}
+
+FILE *GlobalParams::findToUnicodeFile(GooString *name) {
+ GooString *dir, *fileName;
+ FILE *f;
+ int i;
+
+ lockGlobalParams;
+ for (i = 0; i < toUnicodeDirs->getLength(); ++i) {
+ dir = (GooString *)toUnicodeDirs->get(i);
+ fileName = appendToPath(dir->copy(), name->getCString());
+ f = openFile(fileName->getCString(), "r");
+ delete fileName;
+ if (f) {
+ unlockGlobalParams;
+ return f;
+ }
+ }
+ unlockGlobalParams;
+ return NULL;
+}
+
+#if WITH_FONTCONFIGURATION_FONTCONFIG
+static GBool findModifier(const char *name, const char *modifier, const char **start)
+{
+ const char *match;
+
+ if (name == NULL)
+ return gFalse;
+
+ match = strstr(name, modifier);
+ if (match) {
+ if (*start == NULL || match < *start)
+ *start = match;
+ return gTrue;
+ }
+ else {
+ return gFalse;
+ }
+}
+
+static const char *getFontLang(GfxFont *font)
+{
+ const char *lang;
+
+ // find the language we want the font to support
+ if (font->isCIDFont())
+ {
+ GooString *collection = ((GfxCIDFont *)font)->getCollection();
+ if (collection)
+ {
+ if (strcmp(collection->getCString(), "Adobe-GB1") == 0)
+ lang = "zh-cn"; // Simplified Chinese
+ else if (strcmp(collection->getCString(), "Adobe-CNS1") == 0)
+ lang = "zh-tw"; // Traditional Chinese
+ else if (strcmp(collection->getCString(), "Adobe-Japan1") == 0)
+ lang = "ja"; // Japanese
+ else if (strcmp(collection->getCString(), "Adobe-Japan2") == 0)
+ lang = "ja"; // Japanese
+ else if (strcmp(collection->getCString(), "Adobe-Korea1") == 0)
+ lang = "ko"; // Korean
+ else if (strcmp(collection->getCString(), "Adobe-UCS") == 0)
+ lang = "xx";
+ else if (strcmp(collection->getCString(), "Adobe-Identity") == 0)
+ lang = "xx";
+ else
+ {
+ error(errUnimplemented, -1, "Unknown CID font collection, please report to poppler bugzilla.");
+ lang = "xx";
+ }
+ }
+ else lang = "xx";
+ }
+ else lang = "xx";
+ return lang;
+}
+
+static FcPattern *buildFcPattern(GfxFont *font, GooString *base14Name)
+{
+ int weight = -1,
+ slant = -1,
+ width = -1,
+ spacing = -1;
+ bool deleteFamily = false;
+ char *family, *name, *modifiers;
+ const char *start;
+ FcPattern *p;
+
+ // this is all heuristics will be overwritten if font had proper info
+ name = (base14Name == NULL) ? font->getName()->getCString() : base14Name->getCString();
+
+ modifiers = strchr (name, ',');
+ if (modifiers == NULL)
+ modifiers = strchr (name, '-');
+
+ // remove the - from the names, for some reason, Fontconfig does not
+ // understand "MS-Mincho" but does with "MS Mincho"
+ int len = strlen(name);
+ for (int i = 0; i < len; i++)
+ name[i] = (name[i] == '-' ? ' ' : name[i]);
+
+ start = NULL;
+ findModifier(modifiers, "Regular", &start);
+ findModifier(modifiers, "Roman", &start);
+
+ if (findModifier(modifiers, "Oblique", &start))
+ slant = FC_SLANT_OBLIQUE;
+ if (findModifier(modifiers, "Italic", &start))
+ slant = FC_SLANT_ITALIC;
+ if (findModifier(modifiers, "Bold", &start))
+ weight = FC_WEIGHT_BOLD;
+ if (findModifier(modifiers, "Light", &start))
+ weight = FC_WEIGHT_LIGHT;
+ if (findModifier(modifiers, "Medium", &start))
+ weight = FC_WEIGHT_MEDIUM;
+ if (findModifier(modifiers, "Condensed", &start))
+ width = FC_WIDTH_CONDENSED;
+
+ if (start) {
+ // There have been "modifiers" in the name, crop them to obtain
+ // the family name
+ family = new char[len+1];
+ strcpy(family, name);
+ int pos = (modifiers - name);
+ family[pos] = '\0';
+ deleteFamily = true;
+ }
+ else {
+ family = name;
+ }
+
+ // use font flags
+ if (font->isFixedWidth())
+ spacing = FC_MONO;
+ if (font->isBold())
+ weight = FC_WEIGHT_BOLD;
+ if (font->isItalic())
+ slant = FC_SLANT_ITALIC;
+
+ // if the FontDescriptor specified a family name use it
+ if (font->getFamily()) {
+ if (deleteFamily) {
+ delete[] family;
+ deleteFamily = false;
+ }
+ family = font->getFamily()->getCString();
+ }
+
+ // if the FontDescriptor specified a weight use it
+ switch (font -> getWeight())
+ {
+ case GfxFont::W100: weight = FC_WEIGHT_EXTRALIGHT; break;
+ case GfxFont::W200: weight = FC_WEIGHT_LIGHT; break;
+ case GfxFont::W300: weight = FC_WEIGHT_BOOK; break;
+ case GfxFont::W400: weight = FC_WEIGHT_NORMAL; break;
+ case GfxFont::W500: weight = FC_WEIGHT_MEDIUM; break;
+ case GfxFont::W600: weight = FC_WEIGHT_DEMIBOLD; break;
+ case GfxFont::W700: weight = FC_WEIGHT_BOLD; break;
+ case GfxFont::W800: weight = FC_WEIGHT_EXTRABOLD; break;
+ case GfxFont::W900: weight = FC_WEIGHT_BLACK; break;
+ default: break;
+ }
+
+ // if the FontDescriptor specified a width use it
+ switch (font -> getStretch())
+ {
+ case GfxFont::UltraCondensed: width = FC_WIDTH_ULTRACONDENSED; break;
+ case GfxFont::ExtraCondensed: width = FC_WIDTH_EXTRACONDENSED; break;
+ case GfxFont::Condensed: width = FC_WIDTH_CONDENSED; break;
+ case GfxFont::SemiCondensed: width = FC_WIDTH_SEMICONDENSED; break;
+ case GfxFont::Normal: width = FC_WIDTH_NORMAL; break;
+ case GfxFont::SemiExpanded: width = FC_WIDTH_SEMIEXPANDED; break;
+ case GfxFont::Expanded: width = FC_WIDTH_EXPANDED; break;
+ case GfxFont::ExtraExpanded: width = FC_WIDTH_EXTRAEXPANDED; break;
+ case GfxFont::UltraExpanded: width = FC_WIDTH_ULTRAEXPANDED; break;
+ default: break;
+ }
+
+ const char *lang = getFontLang(font);
+
+ p = FcPatternBuild(NULL,
+ FC_FAMILY, FcTypeString, family,
+ FC_LANG, FcTypeString, lang,
+ NULL);
+ if (slant != -1) FcPatternAddInteger(p, FC_SLANT, slant);
+ if (weight != -1) FcPatternAddInteger(p, FC_WEIGHT, weight);
+ if (width != -1) FcPatternAddInteger(p, FC_WIDTH, width);
+ if (spacing != -1) FcPatternAddInteger(p, FC_SPACING, spacing);
+
+ if (deleteFamily)
+ delete[] family;
+ return p;
+}
+#endif
+
+GooString *GlobalParams::findFontFile(GooString *fontName) {
+ static const char *exts[] = { ".pfa", ".pfb", ".ttf", ".ttc", ".otf" };
+ GooString *path, *dir;
+#ifdef WIN32
+ GooString *fontNameU;
+#endif
+ const char *ext;
+ FILE *f;
+ int i, j;
+
+ setupBaseFonts(NULL);
+ lockGlobalParams;
+ if ((path = (GooString *)fontFiles->lookup(fontName))) {
+ path = path->copy();
+ unlockGlobalParams;
+ return path;
+ }
+ for (i = 0; i < fontDirs->getLength(); ++i) {
+ dir = (GooString *)fontDirs->get(i);
+ for (j = 0; j < (int)(sizeof(exts) / sizeof(exts[0])); ++j) {
+ ext = exts[j];
+#ifdef WIN32
+ fontNameU = fileNameToUTF8(fontName->getCString());
+ path = appendToPath(dir->copy(), fontNameU->getCString());
+ delete fontNameU;
+#else
+ path = appendToPath(dir->copy(), fontName->getCString());
+#endif
+ path->append(ext);
+ if ((f = openFile(path->getCString(), "rb"))) {
+ fclose(f);
+ unlockGlobalParams;
+ return path;
+ }
+ delete path;
+ }
+ }
+ unlockGlobalParams;
+ return NULL;
+}
+
+/* if you can't or don't want to use Fontconfig, you need to implement
+ this function for your platform. For Windows, it's in GlobalParamsWin.cc
+*/
+#if WITH_FONTCONFIGURATION_FONTCONFIG
+// not needed for fontconfig
+void GlobalParams::setupBaseFonts(char *dir) {
+}
+
+GooString *GlobalParams::findBase14FontFile(GooString *base14Name, GfxFont *font) {
+ SysFontType type;
+ int fontNum;
+
+ return findSystemFontFile(font, &type, &fontNum, NULL, base14Name);
+}
+
+GooString *GlobalParams::findSystemFontFile(GfxFont *font,
+ SysFontType *type,
+ int *fontNum, GooString *substituteFontName, GooString *base14Name) {
+ SysFontInfo *fi = NULL;
+ FcPattern *p=0;
+ GooString *path = NULL;
+ GooString *fontName = font->getName();
+ GooString substituteName;
+ if (!fontName) return NULL;
+ lockGlobalParams;
+
+ if ((fi = sysFonts->find(fontName, font->isFixedWidth(), gTrue))) {
+ path = fi->path->copy();
+ *type = fi->type;
+ *fontNum = fi->fontNum;
+ substituteName.Set(fi->substituteName->getCString());
+ } else {
+ FcChar8* s;
+ char * ext;
+ FcResult res;
+ FcFontSet *set;
+ int i;
+ FcLangSet *lb = NULL;
+ p = buildFcPattern(font, base14Name);
+
+ if (!p)
+ goto fin;
+ FcConfigSubstitute(NULL, p, FcMatchPattern);
+ FcDefaultSubstitute(p);
+ set = FcFontSort(NULL, p, FcFalse, NULL, &res);
+ if (!set)
+ goto fin;
+
+ // find the language we want the font to support
+ const char *lang = getFontLang(font);
+ if (strcmp(lang,"xx") != 0) {
+ lb = FcLangSetCreate();
+ FcLangSetAdd(lb,(FcChar8 *)lang);
+ }
+
+ /*
+ scan twice.
+ first: fonts support the language
+ second: all fonts (fall back)
+ */
+ while (fi == NULL)
+ {
+ for (i = 0; i < set->nfont; ++i)
+ {
+ res = FcPatternGetString(set->fonts[i], FC_FILE, 0, &s);
+ if (res != FcResultMatch || !s)
+ continue;
+ if (lb != NULL) {
+ FcLangSet *l;
+ res = FcPatternGetLangSet(set->fonts[i], FC_LANG, 0, &l);
+ if (res != FcResultMatch || !FcLangSetContains(l,lb)) {
+ continue;
+ }
+ }
+ FcChar8* s2;
+ res = FcPatternGetString(set->fonts[i], FC_FULLNAME, 0, &s2);
+ if (res == FcResultMatch && s2) {
+ substituteName.Set((char*)s2);
+ } else {
+ // fontconfig does not extract fullname for some fonts
+ // create the fullname from family and style
+ res = FcPatternGetString(set->fonts[i], FC_FAMILY, 0, &s2);
+ if (res == FcResultMatch && s2) {
+ substituteName.Set((char*)s2);
+ res = FcPatternGetString(set->fonts[i], FC_STYLE, 0, &s2);
+ if (res == FcResultMatch && s2) {
+ GooString *style = new GooString((char*)s2);
+ if (style->cmp("Regular") != 0) {
+ substituteName.append(" ");
+ substituteName.append(style);
+ }
+ delete style;
+ }
+ }
+ }
+ ext = strrchr((char*)s,'.');
+ if (!ext)
+ continue;
+ if (!strncasecmp(ext,".ttf",4) || !strncasecmp(ext, ".ttc", 4) || !strncasecmp(ext, ".otf", 4))
+ {
+ int weight, slant;
+ GBool bold = font->isBold();
+ GBool italic = font->isItalic();
+ GBool oblique = gFalse;
+ FcPatternGetInteger(set->fonts[i], FC_WEIGHT, 0, &weight);
+ FcPatternGetInteger(set->fonts[i], FC_SLANT, 0, &slant);
+ if (weight == FC_WEIGHT_DEMIBOLD || weight == FC_WEIGHT_BOLD
+ || weight == FC_WEIGHT_EXTRABOLD || weight == FC_WEIGHT_BLACK)
+ {
+ bold = gTrue;
+ }
+ if (slant == FC_SLANT_ITALIC)
+ italic = gTrue;
+ if (slant == FC_SLANT_OBLIQUE)
+ oblique = gTrue;
+ *fontNum = 0;
+ *type = (!strncasecmp(ext,".ttc",4)) ? sysFontTTC : sysFontTTF;
+ FcPatternGetInteger(set->fonts[i], FC_INDEX, 0, fontNum);
+ fi = new SysFontInfo(fontName->copy(), bold, italic, oblique, font->isFixedWidth(),
+ new GooString((char*)s), *type, *fontNum, substituteName.copy());
+ sysFonts->addFcFont(fi);
+ path = new GooString((char*)s);
+ }
+ else if (!strncasecmp(ext,".pfa",4) || !strncasecmp(ext,".pfb",4))
+ {
+ int weight, slant;
+ GBool bold = font->isBold();
+ GBool italic = font->isItalic();
+ GBool oblique = gFalse;
+ FcPatternGetInteger(set->fonts[i], FC_WEIGHT, 0, &weight);
+ FcPatternGetInteger(set->fonts[i], FC_SLANT, 0, &slant);
+ if (weight == FC_WEIGHT_DEMIBOLD || weight == FC_WEIGHT_BOLD
+ || weight == FC_WEIGHT_EXTRABOLD || weight == FC_WEIGHT_BLACK)
+ {
+ bold = gTrue;
+ }
+ if (slant == FC_SLANT_ITALIC)
+ italic = gTrue;
+ if (slant == FC_SLANT_OBLIQUE)
+ oblique = gTrue;
+ *fontNum = 0;
+ *type = (!strncasecmp(ext,".pfa",4)) ? sysFontPFA : sysFontPFB;
+ FcPatternGetInteger(set->fonts[i], FC_INDEX, 0, fontNum);
+ fi = new SysFontInfo(fontName->copy(), bold, italic, oblique, font->isFixedWidth(),
+ new GooString((char*)s), *type, *fontNum, substituteName.copy());
+ sysFonts->addFcFont(fi);
+ path = new GooString((char*)s);
+ }
+ else
+ continue;
+ break;
+ }
+ if (lb != NULL) {
+ FcLangSetDestroy(lb);
+ lb = NULL;
+ } else {
+ /* scan all fonts of the list */
+ break;
+ }
+ }
+ FcFontSetDestroy(set);
+ }
+ if (path == NULL && (fi = sysFonts->find(fontName, font->isFixedWidth(), gFalse))) {
+ path = fi->path->copy();
+ *type = fi->type;
+ *fontNum = fi->fontNum;
+ }
+ if (substituteFontName) {
+ substituteFontName->Set(substituteName.getCString());
+ }
+fin:
+ if (p)
+ FcPatternDestroy(p);
+ unlockGlobalParams;
+ return path;
+}
+
+#elif WITH_FONTCONFIGURATION_WIN32
+#include "GlobalParamsWin.cc"
+
+GooString *GlobalParams::findBase14FontFile(GooString *base14Name, GfxFont *font) {
+ return findFontFile(base14Name);
+}
+#else
+GooString *GlobalParams::findBase14FontFile(GooString *base14Name, GfxFont *font) {
+ return findFontFile(base14Name);
+}
+
+static struct {
+ const char *name;
+ const char *t1FileName;
+ const char *ttFileName;
+} displayFontTab[] = {
+ {"Courier", "n022003l.pfb", "cour.ttf"},
+ {"Courier-Bold", "n022004l.pfb", "courbd.ttf"},
+ {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf"},
+ {"Courier-Oblique", "n022023l.pfb", "couri.ttf"},
+ {"Helvetica", "n019003l.pfb", "arial.ttf"},
+ {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf"},
+ {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"},
+ {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf"},
+ {"Symbol", "s050000l.pfb", NULL},
+ {"Times-Bold", "n021004l.pfb", "timesbd.ttf"},
+ {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf"},
+ {"Times-Italic", "n021023l.pfb", "timesi.ttf"},
+ {"Times-Roman", "n021003l.pfb", "times.ttf"},
+ {"ZapfDingbats", "d050000l.pfb", NULL},
+ {NULL}
+};
+
+static const char *displayFontDirs[] = {
+ "/usr/share/ghostscript/fonts",
+ "/usr/local/share/ghostscript/fonts",
+ "/usr/share/fonts/default/Type1",
+ "/usr/share/fonts/default/ghostscript",
+ "/usr/share/fonts/type1/gsfonts",
+ NULL
+};
+
+void GlobalParams::setupBaseFonts(char *dir) {
+ GooString *fontName;
+ GooString *fileName;
+ FILE *f;
+ int i, j;
+
+ for (i = 0; displayFontTab[i].name; ++i) {
+ if (fontFiles->lookup(displayFontTab[i].name)) {
+ continue;
+ }
+ fontName = new GooString(displayFontTab[i].name);
+ fileName = NULL;
+ if (dir) {
+ fileName = appendToPath(new GooString(dir), displayFontTab[i].t1FileName);
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+ delete fileName;
+ fileName = NULL;
+ }
+ }
+ for (j = 0; !fileName && displayFontDirs[j]; ++j) {
+ fileName = appendToPath(new GooString(displayFontDirs[j]),
+ displayFontTab[i].t1FileName);
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+ delete fileName;
+ fileName = NULL;
+ }
+ }
+ if (!fileName) {
+ error(errConfig, -1, "No display font for '{0:s}'",
+ displayFontTab[i].name);
+ delete fontName;
+ continue;
+ }
+ addFontFile(fontName, fileName);
+ }
+
+}
+
+GooString *GlobalParams::findSystemFontFile(GfxFont *font,
+ SysFontType *type,
+ int *fontNum, GooString * /*substituteFontName*/,
+ GooString * /*base14Name*/) {
+ SysFontInfo *fi;
+ GooString *path;
+
+ path = NULL;
+ lockGlobalParams;
+ if ((fi = sysFonts->find(font->getName(), font->isFixedWidth(), gFalse))) {
+ path = fi->path->copy();
+ *type = fi->type;
+ *fontNum = fi->fontNum;
+ }
+ unlockGlobalParams;
+ return path;
+}
+#endif
+
+GooString *GlobalParams::findCCFontFile(GooString *collection) {
+ GooString *path;
+
+ lockGlobalParams;
+ if ((path = (GooString *)ccFontFiles->lookup(collection))) {
+ path = path->copy();
+ }
+ unlockGlobalParams;
+ return path;
+}
+
+
+GBool GlobalParams::getPSExpandSmaller() {
+ GBool f;
+
+ lockGlobalParams;
+ f = psExpandSmaller;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getPSShrinkLarger() {
+ GBool f;
+
+ lockGlobalParams;
+ f = psShrinkLarger;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getPSCenter() {
+ GBool f;
+
+ lockGlobalParams;
+ f = psCenter;
+ unlockGlobalParams;
+ return f;
+}
+
+PSLevel GlobalParams::getPSLevel() {
+ PSLevel level;
+
+ lockGlobalParams;
+ level = psLevel;
+ unlockGlobalParams;
+ return level;
+}
+
+GooString *GlobalParams::getPSResidentFont(GooString *fontName) {
+ GooString *psName;
+
+ lockGlobalParams;
+ psName = (GooString *)psResidentFonts->lookup(fontName);
+ unlockGlobalParams;
+ return psName;
+}
+
+GooList *GlobalParams::getPSResidentFonts() {
+ GooList *names;
+ GooHashIter *iter;
+ GooString *name;
+ GooString *psName;
+
+ names = new GooList();
+ lockGlobalParams;
+ psResidentFonts->startIter(&iter);
+ while (psResidentFonts->getNext(&iter, &name, (void **)&psName)) {
+ names->append(psName->copy());
+ }
+ unlockGlobalParams;
+ return names;
+}
+
+PSFontParam16 *GlobalParams::getPSResidentFont16(GooString *fontName,
+ int wMode) {
+ PSFontParam16 *p;
+ int i;
+
+ lockGlobalParams;
+ p = NULL;
+ for (i = 0; i < psResidentFonts16->getLength(); ++i) {
+ p = (PSFontParam16 *)psResidentFonts16->get(i);
+ if (!(p->name->cmp(fontName)) && p->wMode == wMode) {
+ break;
+ }
+ p = NULL;
+ }
+ unlockGlobalParams;
+ return p;
+}
+
+PSFontParam16 *GlobalParams::getPSResidentFontCC(GooString *collection,
+ int wMode) {
+ PSFontParam16 *p;
+ int i;
+
+ lockGlobalParams;
+ p = NULL;
+ for (i = 0; i < psResidentFontsCC->getLength(); ++i) {
+ p = (PSFontParam16 *)psResidentFontsCC->get(i);
+ if (!(p->name->cmp(collection)) && p->wMode == wMode) {
+ break;
+ }
+ p = NULL;
+ }
+ unlockGlobalParams;
+ return p;
+}
+
+GooString *GlobalParams::getTextEncodingName() {
+ GooString *s;
+
+ lockGlobalParams;
+ s = textEncoding->copy();
+ unlockGlobalParams;
+ return s;
+}
+
+EndOfLineKind GlobalParams::getTextEOL() {
+ EndOfLineKind eol;
+
+ lockGlobalParams;
+ eol = textEOL;
+ unlockGlobalParams;
+ return eol;
+}
+
+GBool GlobalParams::getTextPageBreaks() {
+ GBool pageBreaks;
+
+ lockGlobalParams;
+ pageBreaks = textPageBreaks;
+ unlockGlobalParams;
+ return pageBreaks;
+}
+
+GBool GlobalParams::getTextKeepTinyChars() {
+ GBool tiny;
+
+ lockGlobalParams;
+ tiny = textKeepTinyChars;
+ unlockGlobalParams;
+ return tiny;
+}
+
+GBool GlobalParams::getEnableFreeType() {
+ GBool f;
+
+ lockGlobalParams;
+ f = enableFreeType;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getStrokeAdjust() {
+ GBool f;
+
+ lockGlobalParams;
+ f = strokeAdjust;
+ unlockGlobalParams;
+ return f;
+}
+
+ScreenType GlobalParams::getScreenType() {
+ ScreenType t;
+
+ lockGlobalParams;
+ t = screenType;
+ unlockGlobalParams;
+ return t;
+}
+
+int GlobalParams::getScreenSize() {
+ int size;
+
+ lockGlobalParams;
+ size = screenSize;
+ unlockGlobalParams;
+ return size;
+}
+
+int GlobalParams::getScreenDotRadius() {
+ int r;
+
+ lockGlobalParams;
+ r = screenDotRadius;
+ unlockGlobalParams;
+ return r;
+}
+
+double GlobalParams::getScreenGamma() {
+ double gamma;
+
+ lockGlobalParams;
+ gamma = screenGamma;
+ unlockGlobalParams;
+ return gamma;
+}
+
+double GlobalParams::getScreenBlackThreshold() {
+ double thresh;
+
+ lockGlobalParams;
+ thresh = screenBlackThreshold;
+ unlockGlobalParams;
+ return thresh;
+}
+
+double GlobalParams::getScreenWhiteThreshold() {
+ double thresh;
+
+ lockGlobalParams;
+ thresh = screenWhiteThreshold;
+ unlockGlobalParams;
+ return thresh;
+}
+
+double GlobalParams::getMinLineWidth() {
+ double minLineWidthA;
+
+ lockGlobalParams;
+ minLineWidthA = minLineWidth;
+ unlockGlobalParams;
+ return minLineWidthA;
+}
+
+GBool GlobalParams::getMapNumericCharNames() {
+ GBool map;
+
+ lockGlobalParams;
+ map = mapNumericCharNames;
+ unlockGlobalParams;
+ return map;
+}
+
+GBool GlobalParams::getMapUnknownCharNames() {
+ GBool map;
+
+ lockGlobalParams;
+ map = mapUnknownCharNames;
+ unlockGlobalParams;
+ return map;
+}
+
+GBool GlobalParams::getPrintCommands() {
+ GBool p;
+
+ lockGlobalParams;
+ p = printCommands;
+ unlockGlobalParams;
+ return p;
+}
+
+GBool GlobalParams::getProfileCommands() {
+ GBool p;
+
+ lockGlobalParams;
+ p = profileCommands;
+ unlockGlobalParams;
+ return p;
+}
+
+GBool GlobalParams::getErrQuiet() {
+ // no locking -- this function may get called from inside a locked
+ // section
+ return errQuiet;
+}
+
+CharCodeToUnicode *GlobalParams::getCIDToUnicode(GooString *collection) {
+ GooString *fileName;
+ CharCodeToUnicode *ctu;
+
+ lockGlobalParams;
+ if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) {
+ if ((fileName = (GooString *)cidToUnicodes->lookup(collection)) &&
+ (ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) {
+ cidToUnicodeCache->add(ctu);
+ }
+ }
+ unlockGlobalParams;
+ return ctu;
+}
+
+CharCodeToUnicode *GlobalParams::getUnicodeToUnicode(GooString *fontName) {
+ lockGlobalParams;
+ GooHashIter *iter;
+ unicodeToUnicodes->startIter(&iter);
+ GooString *fileName = NULL;
+ GooString *fontPattern;
+ void *val;
+ while (!fileName && unicodeToUnicodes->getNext(&iter, &fontPattern, &val)) {
+ if (strstr(fontName->getCString(), fontPattern->getCString())) {
+ unicodeToUnicodes->killIter(&iter);
+ fileName = (GooString*)val;
+ }
+ }
+ CharCodeToUnicode *ctu = NULL;
+ if (fileName) {
+ ctu = unicodeToUnicodeCache->getCharCodeToUnicode(fileName);
+ if (!ctu) {
+ ctu = CharCodeToUnicode::parseUnicodeToUnicode(fileName);
+ if (ctu)
+ unicodeToUnicodeCache->add(ctu);
+ }
+ }
+ unlockGlobalParams;
+ return ctu;
+}
+
+UnicodeMap *GlobalParams::getUnicodeMap(GooString *encodingName) {
+ return getUnicodeMap2(encodingName);
+}
+
+UnicodeMap *GlobalParams::getUnicodeMap2(GooString *encodingName) {
+ UnicodeMap *map;
+
+ if (!(map = getResidentUnicodeMap(encodingName))) {
+ lockUnicodeMapCache;
+ map = unicodeMapCache->getUnicodeMap(encodingName);
+ unlockUnicodeMapCache;
+ }
+ return map;
+}
+
+CMap *GlobalParams::getCMap(GooString *collection, GooString *cMapName, Stream *stream) {
+ CMap *cMap;
+
+ lockCMapCache;
+ cMap = cMapCache->getCMap(collection, cMapName, stream);
+ unlockCMapCache;
+ return cMap;
+}
+
+UnicodeMap *GlobalParams::getTextEncoding() {
+ return getUnicodeMap2(textEncoding);
+}
+
+GooList *GlobalParams::getEncodingNames()
+{
+ GooList *result = new GooList;
+ GooHashIter *iter;
+ GooString *key;
+ void *val;
+ residentUnicodeMaps->startIter(&iter);
+ while (residentUnicodeMaps->getNext(&iter, &key, &val)) {
+ result->append(key);
+ }
+ residentUnicodeMaps->killIter(&iter);
+ unicodeMaps->startIter(&iter);
+ while (unicodeMaps->getNext(&iter, &key, &val)) {
+ result->append(key);
+ }
+ unicodeMaps->killIter(&iter);
+ return result;
+}
+
+//------------------------------------------------------------------------
+// functions to set parameters
+//------------------------------------------------------------------------
+
+void GlobalParams::addFontFile(GooString *fontName, GooString *path) {
+ lockGlobalParams;
+ fontFiles->add(fontName, path);
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSFile(char *file) {
+ lockGlobalParams;
+ if (psFile) {
+ delete psFile;
+ }
+ psFile = new GooString(file);
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSExpandSmaller(GBool expand) {
+ lockGlobalParams;
+ psExpandSmaller = expand;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSShrinkLarger(GBool shrink) {
+ lockGlobalParams;
+ psShrinkLarger = shrink;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSCenter(GBool center) {
+ lockGlobalParams;
+ psCenter = center;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSLevel(PSLevel level) {
+ lockGlobalParams;
+ psLevel = level;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setTextEncoding(char *encodingName) {
+ lockGlobalParams;
+ delete textEncoding;
+ textEncoding = new GooString(encodingName);
+ unlockGlobalParams;
+}
+
+GBool GlobalParams::setTextEOL(char *s) {
+ lockGlobalParams;
+ if (!strcmp(s, "unix")) {
+ textEOL = eolUnix;
+ } else if (!strcmp(s, "dos")) {
+ textEOL = eolDOS;
+ } else if (!strcmp(s, "mac")) {
+ textEOL = eolMac;
+ } else {
+ unlockGlobalParams;
+ return gFalse;
+ }
+ unlockGlobalParams;
+ return gTrue;
+}
+
+void GlobalParams::setTextPageBreaks(GBool pageBreaks) {
+ lockGlobalParams;
+ textPageBreaks = pageBreaks;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setTextKeepTinyChars(GBool keep) {
+ lockGlobalParams;
+ textKeepTinyChars = keep;
+ unlockGlobalParams;
+}
+
+GBool GlobalParams::setEnableFreeType(char *s) {
+ GBool ok;
+
+ lockGlobalParams;
+ ok = parseYesNo2(s, &enableFreeType);
+ unlockGlobalParams;
+ return ok;
+}
+
+GBool GlobalParams::setDisableFreeTypeHinting(char *s) {
+ GBool ok;
+
+ lockGlobalParams;
+ ok = parseYesNo2(s, &disableFreeTypeHinting);
+ unlockGlobalParams;
+ return ok;
+}
+
+void GlobalParams::setStrokeAdjust(GBool adjust)
+{
+ lockGlobalParams;
+ strokeAdjust = adjust;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenType(ScreenType st)
+{
+ lockGlobalParams;
+ screenType = st;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenSize(int size)
+{
+ lockGlobalParams;
+ screenSize = size;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenDotRadius(int radius)
+{
+ lockGlobalParams;
+ screenDotRadius = radius;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenGamma(double gamma)
+{
+ lockGlobalParams;
+ screenGamma = gamma;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenBlackThreshold(double blackThreshold)
+{
+ lockGlobalParams;
+ screenBlackThreshold = blackThreshold;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenWhiteThreshold(double whiteThreshold)
+{
+ lockGlobalParams;
+ screenWhiteThreshold = whiteThreshold;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setMinLineWidth(double minLineWidthA)
+{
+ lockGlobalParams;
+ minLineWidth = minLineWidthA;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setOverprintPreview(GBool overprintPreviewA) {
+ lockGlobalParams;
+ overprintPreview = overprintPreviewA;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setMapNumericCharNames(GBool map) {
+ lockGlobalParams;
+ mapNumericCharNames = map;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setMapUnknownCharNames(GBool map) {
+ lockGlobalParams;
+ mapUnknownCharNames = map;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPrintCommands(GBool printCommandsA) {
+ lockGlobalParams;
+ printCommands = printCommandsA;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setProfileCommands(GBool profileCommandsA) {
+ lockGlobalParams;
+ profileCommands = profileCommandsA;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setErrQuiet(GBool errQuietA) {
+ lockGlobalParams;
+ errQuiet = errQuietA;
+ unlockGlobalParams;
+}
+
+void GlobalParams::addSecurityHandler(XpdfSecurityHandler *handler) {
+#ifdef ENABLE_PLUGINS
+ lockGlobalParams;
+ securityHandlers->append(handler);
+ unlockGlobalParams;
+#endif
+}
+
+XpdfSecurityHandler *GlobalParams::getSecurityHandler(char *name) {
+#ifdef ENABLE_PLUGINS
+ XpdfSecurityHandler *hdlr;
+ int i;
+
+ lockGlobalParams;
+ for (i = 0; i < securityHandlers->getLength(); ++i) {
+ hdlr = (XpdfSecurityHandler *)securityHandlers->get(i);
+ if (!strcasecmp(hdlr->name, name)) {
+ unlockGlobalParams;
+ return hdlr;
+ }
+ }
+ unlockGlobalParams;
+
+ if (!loadPlugin("security", name)) {
+ return NULL;
+ }
+
+ lockGlobalParams;
+ for (i = 0; i < securityHandlers->getLength(); ++i) {
+ hdlr = (XpdfSecurityHandler *)securityHandlers->get(i);
+ if (!strcmp(hdlr->name, name)) {
+ unlockGlobalParams;
+ return hdlr;
+ }
+ }
+ unlockGlobalParams;
+#else
+ (void)name;
+#endif
+
+ return NULL;
+}
+
+#ifdef ENABLE_PLUGINS
+//------------------------------------------------------------------------
+// plugins
+//------------------------------------------------------------------------
+
+GBool GlobalParams::loadPlugin(char *type, char *name) {
+ Plugin *plugin;
+
+ if (!(plugin = Plugin::load(type, name))) {
+ return gFalse;
+ }
+ lockGlobalParams;
+ plugins->append(plugin);
+ unlockGlobalParams;
+ return gTrue;
+}
+
+#endif // ENABLE_PLUGINS
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParams.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParams.h
new file mode 100644
index 00000000000..16d615ae6d9
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParams.h
@@ -0,0 +1,336 @@
+//========================================================================
+//
+// GlobalParams.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2007-2010, 2012, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2009 Jonathan Kew <jonathan_kew@sil.org>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2009, 2011, 2012, 2014, 2015 William Bader <williambader@hotmail.com>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2011 Pino Toscano <pino@kde.org>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Jason Crain <jason@aquaticape.us>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef GLOBALPARAMS_H
+#define GLOBALPARAMS_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <assert.h>
+#include "poppler-config.h"
+#include <stdio.h>
+#include "goo/gtypes.h"
+#include "CharTypes.h"
+
+#if MULTITHREADED
+#include "goo/GooMutex.h"
+#endif
+
+class GooString;
+class GooList;
+class GooHash;
+class NameToCharCode;
+class CharCodeToUnicode;
+class CharCodeToUnicodeCache;
+class UnicodeMap;
+class UnicodeMapCache;
+class CMap;
+class CMapCache;
+struct XpdfSecurityHandler;
+class GlobalParams;
+class GfxFont;
+class Stream;
+class SysFontList;
+
+//------------------------------------------------------------------------
+
+// The global parameters object.
+extern GlobalParams *globalParams;
+
+//------------------------------------------------------------------------
+
+enum SysFontType {
+ sysFontPFA,
+ sysFontPFB,
+ sysFontTTF,
+ sysFontTTC
+};
+
+//------------------------------------------------------------------------
+
+class PSFontParam16 {
+public:
+
+ GooString *name; // PDF font name for psResidentFont16;
+ // char collection name for psResidentFontCC
+ int wMode; // writing mode (0=horiz, 1=vert)
+ GooString *psFontName; // PostScript font name
+ GooString *encoding; // encoding
+
+ PSFontParam16(GooString *nameA, int wModeA,
+ GooString *psFontNameA, GooString *encodingA);
+ ~PSFontParam16();
+};
+
+//------------------------------------------------------------------------
+
+enum PSLevel {
+ psLevel1,
+ psLevel1Sep,
+ psLevel2,
+ psLevel2Sep,
+ psLevel3,
+ psLevel3Sep
+};
+
+//------------------------------------------------------------------------
+
+enum EndOfLineKind {
+ eolUnix, // LF
+ eolDOS, // CR+LF
+ eolMac // CR
+};
+
+//------------------------------------------------------------------------
+
+enum ScreenType {
+ screenUnset,
+ screenDispersed,
+ screenClustered,
+ screenStochasticClustered
+};
+
+//------------------------------------------------------------------------
+
+class GlobalParams {
+public:
+
+ // Initialize the global parameters by attempting to read a config
+ // file.
+ GlobalParams(const char *customPopplerDataDir = NULL);
+
+ ~GlobalParams();
+
+ void setupBaseFonts(char *dir);
+
+ //----- accessors
+
+ CharCode getMacRomanCharCode(char *charName);
+
+ // Return Unicode values for character names. Used for general text
+ // extraction.
+ Unicode mapNameToUnicodeText(const char *charName);
+
+ // Return Unicode values for character names. Used for glyph
+ // lookups or text extraction with ZapfDingbats fonts.
+ Unicode mapNameToUnicodeAll(const char *charName);
+
+ UnicodeMap *getResidentUnicodeMap(GooString *encodingName);
+ FILE *getUnicodeMapFile(GooString *encodingName);
+ FILE *findCMapFile(GooString *collection, GooString *cMapName);
+ FILE *findToUnicodeFile(GooString *name);
+ GooString *findFontFile(GooString *fontName);
+ GooString *findBase14FontFile(GooString *base14Name, GfxFont *font);
+ GooString *findSystemFontFile(GfxFont *font, SysFontType *type,
+ int *fontNum, GooString *substituteFontName = NULL,
+ GooString *base14Name = NULL);
+ GooString *findCCFontFile(GooString *collection);
+ GBool getPSExpandSmaller();
+ GBool getPSShrinkLarger();
+ GBool getPSCenter();
+ PSLevel getPSLevel();
+ GooString *getPSResidentFont(GooString *fontName);
+ GooList *getPSResidentFonts();
+ PSFontParam16 *getPSResidentFont16(GooString *fontName, int wMode);
+ PSFontParam16 *getPSResidentFontCC(GooString *collection, int wMode);
+ GooString *getTextEncodingName();
+ EndOfLineKind getTextEOL();
+ GBool getTextPageBreaks();
+ GBool getTextKeepTinyChars();
+ GBool getEnableFreeType();
+ GBool getStrokeAdjust();
+ ScreenType getScreenType();
+ int getScreenSize();
+ int getScreenDotRadius();
+ double getScreenGamma();
+ double getScreenBlackThreshold();
+ double getScreenWhiteThreshold();
+ double getMinLineWidth();
+ GBool getOverprintPreview() { return overprintPreview; }
+ GBool getMapNumericCharNames();
+ GBool getMapUnknownCharNames();
+ GBool getPrintCommands();
+ GBool getProfileCommands();
+ GBool getErrQuiet();
+
+ CharCodeToUnicode *getCIDToUnicode(GooString *collection);
+ CharCodeToUnicode *getUnicodeToUnicode(GooString *fontName);
+ UnicodeMap *getUnicodeMap(GooString *encodingName);
+ CMap *getCMap(GooString *collection, GooString *cMapName, Stream *stream = NULL);
+ UnicodeMap *getTextEncoding();
+#ifdef ENABLE_PLUGINS
+ GBool loadPlugin(char *type, char *name);
+#endif
+
+ GooList *getEncodingNames();
+
+ //----- functions to set parameters
+ void addFontFile(GooString *fontName, GooString *path);
+ void setPSFile(char *file);
+ void setPSExpandSmaller(GBool expand);
+ void setPSShrinkLarger(GBool shrink);
+ void setPSCenter(GBool center);
+ void setPSLevel(PSLevel level);
+ void setTextEncoding(char *encodingName);
+ GBool setTextEOL(char *s);
+ void setTextPageBreaks(GBool pageBreaks);
+ void setTextKeepTinyChars(GBool keep);
+ GBool setEnableFreeType(char *s);
+ GBool setDisableFreeTypeHinting(char *s);
+ void setStrokeAdjust(GBool strokeAdjust);
+ void setScreenType(ScreenType st);
+ void setScreenSize(int size);
+ void setScreenDotRadius(int radius);
+ void setScreenGamma(double gamma);
+ void setScreenBlackThreshold(double blackThreshold);
+ void setScreenWhiteThreshold(double whiteThreshold);
+ void setMinLineWidth(double minLineWidth);
+ void setOverprintPreview(GBool overprintPreviewA);
+ void setMapNumericCharNames(GBool map);
+ void setMapUnknownCharNames(GBool map);
+ void setPrintCommands(GBool printCommandsA);
+ void setProfileCommands(GBool profileCommandsA);
+ void setErrQuiet(GBool errQuietA);
+
+ static GBool parseYesNo2(const char *token, GBool *flag);
+
+ //----- security handlers
+
+ void addSecurityHandler(XpdfSecurityHandler *handler);
+ XpdfSecurityHandler *getSecurityHandler(char *name);
+
+private:
+
+ void parseNameToUnicode(GooString *name);
+ UnicodeMap *getUnicodeMap2(GooString *encodingName);
+
+ void scanEncodingDirs();
+ void addCIDToUnicode(GooString *collection, GooString *fileName);
+ void addUnicodeMap(GooString *encodingName, GooString *fileName);
+ void addCMapDir(GooString *collection, GooString *dir);
+
+ //----- static tables
+
+ NameToCharCode * // mapping from char name to
+ macRomanReverseMap; // MacRomanEncoding index
+
+ //----- user-modifiable settings
+
+ NameToCharCode * // mapping from char name to Unicode for ZapfDingbats
+ nameToUnicodeZapfDingbats;
+ NameToCharCode * // mapping from char name to Unicode for text
+ nameToUnicodeText; // extraction
+ GooHash *cidToUnicodes; // files for mappings from char collections
+ // to Unicode, indexed by collection name
+ // [GooString]
+ GooHash *unicodeToUnicodes; // files for Unicode-to-Unicode mappings,
+ // indexed by font name pattern [GooString]
+ GooHash *residentUnicodeMaps; // mappings from Unicode to char codes,
+ // indexed by encoding name [UnicodeMap]
+ GooHash *unicodeMaps; // files for mappings from Unicode to char
+ // codes, indexed by encoding name [GooString]
+ GooHash *cMapDirs; // list of CMap dirs, indexed by collection
+ // name [GooList[GooString]]
+ GooList *toUnicodeDirs; // list of ToUnicode CMap dirs [GooString]
+ GBool baseFontsInitialized;
+#ifdef _WIN32
+ GooHash *substFiles; // windows font substitutes (for CID fonts)
+#endif
+ GooHash *fontFiles; // font files: font name mapped to path
+ // [GString]
+ GooList *fontDirs; // list of font dirs [GString]
+ GooHash *ccFontFiles; // character collection font files:
+ // collection name mapped to path [GString]
+ SysFontList *sysFonts; // system fonts
+ GooString *psFile; // PostScript file or command (for xpdf)
+ GBool psExpandSmaller; // expand smaller pages to fill paper
+ GBool psShrinkLarger; // shrink larger pages to fit paper
+ GBool psCenter; // center pages on the paper
+ PSLevel psLevel; // PostScript level to generate
+ GooHash *psResidentFonts; // 8-bit fonts resident in printer:
+ // PDF font name mapped to PS font name
+ // [GString]
+ GooList *psResidentFonts16; // 16-bit fonts resident in printer:
+ // PDF font name mapped to font info
+ // [PSFontParam16]
+ GooList *psResidentFontsCC; // 16-bit character collection fonts
+ // resident in printer: collection name
+ // mapped to font info [PSFontParam16]
+ GooString *textEncoding; // encoding (unicodeMap) to use for text
+ // output
+ EndOfLineKind textEOL; // type of EOL marker to use for text
+ // output
+ GBool textPageBreaks; // insert end-of-page markers?
+ GBool textKeepTinyChars; // keep all characters in text output
+ GBool enableFreeType; // FreeType enable flag
+ GBool disableFreeTypeHinting; // FreeType disable hinting 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
+ double minLineWidth; // minimum line width
+ GBool overprintPreview; // enable overprint preview
+ GBool mapNumericCharNames; // map numeric char names (from font subsets)?
+ GBool mapUnknownCharNames; // map unknown char names?
+ GBool printCommands; // print the drawing commands
+ GBool profileCommands; // profile the drawing commands
+ GBool errQuiet; // suppress error messages?
+ double splashResolution; // resolution when rasterizing images
+
+ CharCodeToUnicodeCache *cidToUnicodeCache;
+ CharCodeToUnicodeCache *unicodeToUnicodeCache;
+ UnicodeMapCache *unicodeMapCache;
+ CMapCache *cMapCache;
+
+#ifdef ENABLE_PLUGINS
+ GooList *plugins; // list of plugins [Plugin]
+ GooList *securityHandlers; // list of loaded security handlers
+ // [XpdfSecurityHandler]
+#endif
+
+#if MULTITHREADED
+ GooMutex mutex;
+ GooMutex unicodeMapCacheMutex;
+ GooMutex cMapCacheMutex;
+#endif
+
+ const char *popplerDataDir;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParamsWin.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParamsWin.cc
new file mode 100644
index 00000000000..f9f40ef4e29
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/GlobalParamsWin.cc
@@ -0,0 +1,598 @@
+/* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
+ but mostly based on xpdf code.
+
+ // Copyright (C) 2010, 2012 Hib Eris <hib@hiberis.nl>
+ // Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+ // Copyright (C) 2012 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+ // Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+ // Copyright (C) 2012 Mark Brand <mabrand@mabrand.nl>
+ // Copyright (C) 2013 Adam Reichold <adamreichold@myopera.com>
+ // Copyright (C) 2013 Dmytro Morgun <lztoad@gmail.com>
+
+TODO: instead of a fixed mapping defined in displayFontTab, it could
+scan the whole fonts directory, parse TTF files and build font
+description for all fonts available in Windows. That's how MuPDF works.
+*/
+
+#ifndef PACKAGE_NAME
+#include <config.h>
+#endif
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <windows.h>
+#if !(_WIN32_IE >= 0x0500)
+#error "_WIN32_IE must be defined >= 0x0500 for SHGFP_TYPE_CURRENT from shlobj.h"
+#endif
+#include <shlobj.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "goo/GooList.h"
+#include "goo/GooHash.h"
+#include "goo/gfile.h"
+#include "Error.h"
+#include "NameToCharCode.h"
+#include "CharCodeToUnicode.h"
+#include "UnicodeMap.h"
+#include "CMap.h"
+#include "BuiltinFontTables.h"
+#include "FontEncodingTables.h"
+#include "GlobalParams.h"
+#include "GfxFont.h"
+#include <sys/stat.h>
+#include "Object.h"
+#include "Stream.h"
+#include "Lexer.h"
+#include "Parser.h"
+
+#if MULTITHREADED
+# define lockGlobalParams gLockMutex(&mutex)
+# define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex)
+# define lockCMapCache gLockMutex(&cMapCacheMutex)
+# define unlockGlobalParams gUnlockMutex(&mutex)
+# define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex)
+# define unlockCMapCache gUnlockMutex(&cMapCacheMutex)
+#else
+# define lockGlobalParams
+# define lockUnicodeMapCache
+# define lockCMapCache
+# define unlockGlobalParams
+# define unlockUnicodeMapCache
+# define unlockCMapCache
+#endif
+
+#define DEFAULT_SUBSTITUTE_FONT "Helvetica"
+#define DEFAULT_CID_FONT_AC1_MSWIN "MingLiU" /* Adobe-CNS1 for Taiwan, HongKong */
+#define DEFAULT_CID_FONT_AG1_MSWIN "SimSun" /* Adobe-GB1 for PRC, Singapore */
+#define DEFAULT_CID_FONT_AJ1_MSWIN "MS-Mincho" /* Adobe-Japan1 */
+#define DEFAULT_CID_FONT_AJ2_MSWIN "MS-Mincho" /* Adobe-Japan2 (legacy) */
+#define DEFAULT_CID_FONT_AK1_MSWIN "Batang" /* Adobe-Korea1 */
+#define DEFAULT_CID_FONT_MSWIN "ArialUnicode" /* Unknown */
+
+static struct {
+ const char *name;
+ const char *t1FileName;
+ const char *ttFileName;
+ GBool warnIfMissing;
+} displayFontTab[] = {
+ {"Courier", "n022003l.pfb", "cour.ttf", gTrue},
+ {"Courier-Bold", "n022004l.pfb", "courbd.ttf", gTrue},
+ {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf", gTrue},
+ {"Courier-Oblique", "n022023l.pfb", "couri.ttf", gTrue},
+ {"Helvetica", "n019003l.pfb", "arial.ttf", gTrue},
+ {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf", gTrue},
+ {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf", gTrue},
+ {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf", gTrue},
+ // TODO: not sure if "symbol.ttf" is right
+ {"Symbol", "s050000l.pfb", "symbol.ttf", gTrue},
+ {"Times-Bold", "n021004l.pfb", "timesbd.ttf", gTrue},
+ {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf", gTrue},
+ {"Times-Italic", "n021023l.pfb", "timesi.ttf", gTrue},
+ {"Times-Roman", "n021003l.pfb", "times.ttf", gTrue},
+ // TODO: not sure if "wingding.ttf" is right
+ {"ZapfDingbats", "d050000l.pfb", "wingding.ttf", gTrue},
+
+ // those seem to be frequently accessed by PDF files and I kind of guess
+ // which font file do the refer to
+ {"Palatino", NULL, "pala.ttf", gTrue},
+ {"Palatino-Roman", NULL, "pala.ttf", gTrue},
+ {"Palatino-Bold", NULL, "palab.ttf", gTrue},
+ {"Palatino-Italic", NULL, "palai.ttf", gTrue},
+ {"Palatino,Italic", NULL, "palai.ttf", gTrue},
+ {"Palatino-BoldItalic", NULL, "palabi.ttf", gTrue},
+
+ {"ArialBlack", NULL, "arialbd.ttf", gTrue},
+
+ {"ArialNarrow", NULL, "arialn.ttf", gTrue},
+ {"ArialNarrow,Bold", NULL, "arialnb.ttf", gTrue},
+ {"ArialNarrow,Italic", NULL, "arialni.ttf", gTrue},
+ {"ArialNarrow,BoldItalic", NULL, "arialnbi.ttf", gTrue},
+ {"ArialNarrow-Bold", NULL, "arialnb.ttf", gTrue},
+ {"ArialNarrow-Italic", NULL, "arialni.ttf", gTrue},
+ {"ArialNarrow-BoldItalic", NULL, "arialnbi.ttf", gTrue},
+
+ {"HelveticaNarrow", NULL, "arialn.ttf", gTrue},
+ {"HelveticaNarrow,Bold", NULL, "arialnb.ttf", gTrue},
+ {"HelveticaNarrow,Italic", NULL, "arialni.ttf", gTrue},
+ {"HelveticaNarrow,BoldItalic", NULL, "arialnbi.ttf", gTrue},
+ {"HelveticaNarrow-Bold", NULL, "arialnb.ttf", gTrue},
+ {"HelveticaNarrow-Italic", NULL, "arialni.ttf", gTrue},
+ {"HelveticaNarrow-BoldItalic", NULL, "arialnbi.ttf", gTrue},
+
+ {"BookAntiqua", NULL, "bkant.ttf", gTrue},
+ {"BookAntiqua,Bold", NULL, "bkant.ttf", gTrue},
+ {"BookAntiqua,Italic", NULL, "bkant.ttf", gTrue},
+ {"BookAntiqua,BoldItalic", NULL, "bkant.ttf", gTrue},
+ {"BookAntiqua-Bold", NULL, "bkant.ttf", gTrue},
+ {"BookAntiqua-Italic", NULL, "bkant.ttf", gTrue},
+ {"BookAntiqua-BoldItalic", NULL, "bkant.ttf", gTrue},
+
+ {"Verdana", NULL, "verdana.ttf", gTrue},
+ {"Verdana,Bold", NULL, "verdanab.ttf", gTrue},
+ {"Verdana,Italic", NULL, "verdanai.ttf", gTrue},
+ {"Verdana,BoldItalic", NULL, "verdanaz.ttf", gTrue},
+ {"Verdana-Bold", NULL, "verdanab.ttf", gTrue},
+ {"Verdana-Italic", NULL, "verdanai.ttf", gTrue},
+ {"Verdana-BoldItalic", NULL, "verdanaz.ttf", gTrue},
+
+ {"Tahoma", NULL, "tahoma.ttf", gTrue},
+ {"Tahoma,Bold", NULL, "tahomabd.ttf", gTrue},
+ {"Tahoma,Italic", NULL, "tahoma.ttf", gTrue},
+ {"Tahoma,BoldItalic", NULL, "tahomabd.ttf", gTrue},
+ {"Tahoma-Bold", NULL, "tahomabd.ttf", gTrue},
+ {"Tahoma-Italic", NULL, "tahoma.ttf", gTrue},
+ {"Tahoma-BoldItalic", NULL, "tahomabd.ttf", gTrue},
+
+ {"CCRIKH+Verdana", NULL, "verdana.ttf", gTrue},
+ {"CCRIKH+Verdana,Bold", NULL, "verdanab.ttf", gTrue},
+ {"CCRIKH+Verdana,Italic", NULL, "verdanai.ttf", gTrue},
+ {"CCRIKH+Verdana,BoldItalic", NULL, "verdanaz.ttf", gTrue},
+ {"CCRIKH+Verdana-Bold", NULL, "verdanab.ttf", gTrue},
+ {"CCRIKH+Verdana-Italic", NULL, "verdanai.ttf", gTrue},
+ {"CCRIKH+Verdana-BoldItalic", NULL, "verdanaz.ttf", gTrue},
+
+ {"Georgia", NULL, "georgia.ttf", gTrue},
+ {"Georgia,Bold", NULL, "georgiab.ttf", gTrue},
+ {"Georgia,Italic", NULL, "georgiai.ttf", gTrue},
+ {"Georgia,BoldItalic", NULL, "georgiaz.ttf", gTrue},
+ {"Georgia-Bold", NULL, "georgiab.ttf", gTrue},
+ {"Georgia-Italic", NULL, "georgiai.ttf", gTrue},
+ {"Georgia-BoldItalic", NULL, "georgiaz.ttf", gTrue},
+
+ // fallback for Adobe CID fonts:
+ {"MingLiU", NULL, "mingliu.ttf", gFalse},
+ {"SimSun", NULL, "simsun.ttf", gFalse},
+ {"MS-Mincho", NULL, "msmincho.ttf", gFalse},
+ {"Batang", NULL, "batang.ttf", gFalse},
+ {"ArialUnicode", NULL, "arialuni.ttf", gTrue},
+ {NULL}
+};
+
+#define FONTS_SUBDIR "\\fonts"
+
+static void GetWindowsFontDir(char *winFontDir, int cbWinFontDirLen)
+{
+ BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND hwndOwner,
+ LPTSTR lpszPath,
+ int nFolder,
+ BOOL fCreate);
+ HRESULT (__stdcall *SHGetFolderPathFunc)(HWND hwndOwner,
+ int nFolder,
+ HANDLE hToken,
+ DWORD dwFlags,
+ LPTSTR pszPath);
+
+ // SHGetSpecialFolderPath isn't available in older versions of shell32.dll (Win95 and
+ // WinNT4), so do a dynamic load of ANSI versions.
+ winFontDir[0] = '\0';
+
+ HMODULE hLib = LoadLibrary("shell32.dll");
+ if (hLib) {
+ SHGetFolderPathFunc = (HRESULT (__stdcall *)(HWND, int, HANDLE, DWORD, LPTSTR))
+ GetProcAddress(hLib, "SHGetFolderPathA");
+ if (SHGetFolderPathFunc)
+ (*SHGetFolderPathFunc)(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, winFontDir);
+
+ if (!winFontDir[0]) {
+ // Try an older function
+ SHGetSpecialFolderPathFunc = (BOOL (__stdcall *)(HWND, LPTSTR, int, BOOL))
+ GetProcAddress(hLib, "SHGetSpecialFolderPathA");
+ if (SHGetSpecialFolderPathFunc)
+ (*SHGetSpecialFolderPathFunc)(NULL, winFontDir, CSIDL_FONTS, FALSE);
+ }
+ FreeLibrary(hLib);
+ }
+ if (winFontDir[0])
+ return;
+
+ // Try older DLL
+ hLib = LoadLibrary("SHFolder.dll");
+ if (hLib) {
+ SHGetFolderPathFunc = (HRESULT (__stdcall *)(HWND, int, HANDLE, DWORD, LPTSTR))
+ GetProcAddress(hLib, "SHGetFolderPathA");
+ if (SHGetFolderPathFunc)
+ (*SHGetFolderPathFunc)(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, winFontDir);
+ FreeLibrary(hLib);
+ }
+ if (winFontDir[0])
+ return;
+
+ // Everything else failed so the standard fonts directory.
+ GetWindowsDirectory(winFontDir, cbWinFontDirLen);
+ if (winFontDir[0]) {
+ strncat(winFontDir, FONTS_SUBDIR, cbWinFontDirLen);
+ winFontDir[cbWinFontDirLen-1] = 0;
+ }
+}
+
+static bool FileExists(const char *path)
+{
+ FILE * f = fopen(path, "rb");
+ if (f) {
+ fclose(f);
+ return true;
+ }
+ return false;
+}
+
+void SysFontList::scanWindowsFonts(GooString *winFontDir) {
+ OSVERSIONINFO version;
+ const char *path;
+ DWORD idx, valNameLen, dataLen, type;
+ HKEY regKey;
+ char valName[1024], data[1024];
+ int n, fontNum;
+ char *p0, *p1;
+ GooString *fontPath;
+
+ version.dwOSVersionInfoSize = sizeof(version);
+ GetVersionEx(&version);
+ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
+ } else {
+ path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
+ }
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &regKey) == ERROR_SUCCESS) {
+ idx = 0;
+ while (1) {
+ valNameLen = sizeof(valName) - 1;
+ dataLen = sizeof(data) - 1;
+ if (RegEnumValue(regKey, idx, valName, &valNameLen, NULL,
+ &type, (LPBYTE)data, &dataLen) != ERROR_SUCCESS) {
+ break;
+ }
+ if (type == REG_SZ &&
+ valNameLen > 0 && valNameLen < sizeof(valName) &&
+ dataLen > 0 && dataLen < sizeof(data)) {
+ valName[valNameLen] = '\0';
+ data[dataLen] = '\0';
+ n = strlen(data);
+ if (!strcasecmp(data + n - 4, ".ttf") ||
+ !strcasecmp(data + n - 4, ".ttc") ||
+ !strcasecmp(data + n - 4, ".otf")) {
+ fontPath = new GooString(data);
+ if (!(dataLen >= 3 && data[1] == ':' && data[2] == '\\')) {
+ fontPath->insert(0, '\\');
+ fontPath->insert(0, winFontDir);
+ fontPath->append('\0');
+ }
+ p0 = valName;
+ fontNum = 0;
+ while (*p0) {
+ p1 = strstr(p0, " & ");
+ if (p1) {
+ *p1 = '\0';
+ p1 = p1 + 3;
+ } else {
+ p1 = p0 + strlen(p0);
+ }
+ fonts->append(makeWindowsFont(p0, fontNum,
+ fontPath->getCString()));
+ p0 = p1;
+ ++fontNum;
+ }
+ delete fontPath;
+ }
+ }
+ ++idx;
+ }
+ RegCloseKey(regKey);
+ }
+}
+
+SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum,
+ char *path) {
+ int n;
+ GBool bold, italic, oblique, fixedWidth;
+ GooString *s;
+ char c;
+ int i;
+ SysFontType type;
+ GooString substituteName;
+
+ n = strlen(name);
+ bold = italic = oblique = fixedWidth = gFalse;
+
+ // remove trailing ' (TrueType)'
+ if (n > 11 && !strncmp(name + n - 11, " (TrueType)", 11)) {
+ n -= 11;
+ }
+
+ // remove trailing ' (OpenType)'
+ if (n > 11 && !strncmp(name + n - 11, " (OpenType)", 11)) {
+ n -= 11;
+ }
+
+ // remove trailing ' Italic'
+ if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) {
+ n -= 7;
+ italic = gTrue;
+ }
+
+ // remove trailing ' Oblique'
+ if (n > 7 && !strncmp(name + n - 8, " Oblique", 8)) {
+ n -= 8;
+ oblique = gTrue;
+ }
+
+ // remove trailing ' Bold'
+ if (n > 5 && !strncmp(name + n - 5, " Bold", 5)) {
+ n -= 5;
+ bold = gTrue;
+ }
+
+ // remove trailing ' Regular'
+ if (n > 5 && !strncmp(name + n - 8, " Regular", 8)) {
+ n -= 8;
+ }
+
+ // the familyname cannot indicate whether a font is fixedWidth or not.
+ // some well-known fixedWidth typeface family names or keyword are checked.
+ if ( strstr(name, "Courier") ||
+ strstr(name, "Fixed") ||
+ (strstr(name, "Mono") && !strstr(name, "Monotype")) ||
+ strstr(name, "Typewriter") )
+ fixedWidth = gTrue;
+ else
+ fixedWidth = gFalse;
+
+
+ //----- normalize the font name
+ s = new GooString(name, n);
+ i = 0;
+ while (i < s->getLength()) {
+ c = s->getChar(i);
+ if (c == ' ' || c == ',' || c == '-') {
+ s->del(i);
+ } else {
+ ++i;
+ }
+ }
+
+ if (!strcasecmp(path + strlen(path) - 4, ".ttc")) {
+ type = sysFontTTC;
+ } else {
+ type = sysFontTTF;
+ }
+
+ return new SysFontInfo(s, bold, italic, oblique, fixedWidth,
+ new GooString(path), type, fontNum, substituteName.copy());
+}
+
+static GooString* replaceSuffix(GooString *path,
+ const char* suffixA, const char* suffixB)
+{
+ int suffLenA = strlen(suffixA);
+ int suffLenB = strlen(suffixB);
+ int baseLenA = path->getLength() - suffLenA;
+ int baseLenB = path->getLength() - suffLenB;
+
+ if (!strcasecmp(path->getCString()+baseLenA, suffixA)) {
+ path->del(baseLenA,suffLenA)->append(suffixB);
+ } else if (!strcasecmp(path->getCString()+baseLenB, suffixB)) {
+ path->del(baseLenB,suffLenB)->append(suffixA);
+ }
+
+ return path;
+}
+
+
+void GlobalParams::setupBaseFonts(char * dir)
+{
+ const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR;
+ GooString *fileName = NULL;
+ GooFile *file;
+
+ if (baseFontsInitialized)
+ return;
+ baseFontsInitialized = true;
+
+ char winFontDir[MAX_PATH];
+ GetWindowsFontDir(winFontDir, sizeof(winFontDir));
+
+ for (int i = 0; displayFontTab[i].name; ++i) {
+ GooString *fontName = new GooString(displayFontTab[i].name);
+ if (fontFiles->lookup(fontName))
+ continue;
+
+ if (dir) {
+ GooString *fontPath = appendToPath(new GooString(dir), displayFontTab[i].t1FileName);
+ if (FileExists(fontPath->getCString()) ||
+ FileExists(replaceSuffix(fontPath, ".pfb", ".pfa")->getCString())) {
+ addFontFile(fontName, fontPath);
+ continue;
+ }
+ delete fontPath;
+ }
+
+ if (winFontDir[0] && displayFontTab[i].ttFileName) {
+ GooString *fontPath = appendToPath(new GooString(winFontDir), displayFontTab[i].ttFileName);
+ if (FileExists(fontPath->getCString()) ||
+ FileExists(replaceSuffix(fontPath, ".ttc", ".ttf")->getCString())) {
+ addFontFile(fontName, fontPath);
+ continue;
+ }
+ delete fontPath;
+ }
+
+ if (displayFontTab[i].warnIfMissing) {
+ error(errSyntaxError, -1, "No display font for '{0:s}'", displayFontTab[i].name);
+ delete fontName;
+ }
+ }
+ if (winFontDir[0]) {
+ GooString gooWinFontsDir(winFontDir);
+ sysFonts->scanWindowsFonts(&gooWinFontsDir);
+ }
+
+ fileName = new GooString(dataRoot);
+ fileName->append("/cidfmap");
+
+ // try to open file
+ file = GooFile::open(fileName);
+
+ if (file != NULL) {
+ Parser *parser;
+ Object obj1, obj2;
+
+ obj1.initNull();
+ parser = new Parser(NULL,
+ new Lexer(NULL,
+ new FileStream(file, 0, gFalse, file->size(), &obj1)),
+ gTrue);
+ obj1.free();
+ parser->getObj(&obj1);
+ while (!obj1.isEOF()) {
+ parser->getObj(&obj2);
+ if (obj1.isName()) {
+ // Substitutions
+ if (obj2.isDict()) {
+ Object obj3;
+ obj2.getDict()->lookup("Path", &obj3);
+ if (obj3.isString())
+ addFontFile(new GooString(obj1.getName()), obj3.getString()->copy());
+ obj3.free();
+ // Aliases
+ } else if (obj2.isName()) {
+ substFiles->add(new GooString(obj1.getName()), new GooString(obj2.getName()));
+ }
+ }
+ obj2.free();
+ obj1.free();
+ parser->getObj(&obj1);
+ // skip trailing ';'
+ while (obj1.isCmd(";")) {
+ obj1.free();
+ parser->getObj(&obj1);
+ }
+ }
+ delete file;
+ delete parser;
+ }
+ else {
+ delete fileName;
+ }
+}
+
+static const char *findSubstituteName(GfxFont *font, GooHash *fontFiles,
+ GooHash *substFiles,
+ const char *origName)
+{
+ assert(origName);
+ if (!origName) return NULL;
+ GooString *name2 = new GooString(origName);
+ int n = strlen(origName);
+ // remove trailing "-Identity-H"
+ if (n > 11 && !strcmp(name2->getCString() + n - 11, "-Identity-H")) {
+ name2->del(n - 11, 11);
+ n -= 11;
+ }
+ // remove trailing "-Identity-V"
+ if (n > 11 && !strcmp(name2->getCString() + n - 11, "-Identity-V")) {
+ name2->del(n - 11, 11);
+ n -= 11;
+ }
+ GooString *substName = (GooString *)substFiles->lookup(name2);
+ if (substName != NULL) {
+ delete name2;
+ return substName->getCString();
+ }
+
+ /* TODO: try to at least guess bold/italic/bolditalic from the name */
+ delete name2;
+ if (font->isCIDFont()) {
+ GooString *collection = ((GfxCIDFont *)font)->getCollection();
+
+ const char* name3 = NULL;
+ if ( !collection->cmp("Adobe-CNS1") )
+ name3 = DEFAULT_CID_FONT_AC1_MSWIN;
+ else if ( !collection->cmp("Adobe-GB1") )
+ name3 = DEFAULT_CID_FONT_AG1_MSWIN;
+ else if ( !collection->cmp("Adobe-Japan1") )
+ name3 = DEFAULT_CID_FONT_AJ1_MSWIN;
+ else if ( !collection->cmp("Adobe-Japan2") )
+ name3 = DEFAULT_CID_FONT_AJ2_MSWIN;
+ else if ( !collection->cmp("Adobe-Korea1") )
+ name3 = DEFAULT_CID_FONT_AK1_MSWIN;
+
+ if (name3 && fontFiles->lookup(name3))
+ return name3;
+
+ if (fontFiles->lookup(DEFAULT_CID_FONT_MSWIN))
+ return DEFAULT_CID_FONT_MSWIN;
+ }
+ return DEFAULT_SUBSTITUTE_FONT;
+}
+
+/* Windows implementation of external font matching code */
+GooString *GlobalParams::findSystemFontFile(GfxFont *font,
+ SysFontType *type,
+ int *fontNum, GooString *substituteFontName,
+ GooString *base14Name) {
+ SysFontInfo *fi;
+ GooString *path = NULL;
+ GooString *fontName = font->getName();
+ if (!fontName) return NULL;
+ lockGlobalParams;
+ setupBaseFonts(NULL);
+
+ // TODO: base14Name should be changed?
+ // In the system using FontConfig, findSystemFontFile() uses
+ // base14Name only for the creation of query pattern.
+
+ if ((fi = sysFonts->find(fontName, gFalse, gFalse))) {
+ path = fi->path->copy();
+ *type = fi->type;
+ *fontNum = fi->fontNum;
+ if (substituteFontName)
+ substituteFontName->Set(fi->substituteName->getCString());
+ } else {
+ GooString *substFontName = new GooString(findSubstituteName(font, fontFiles,
+ substFiles,
+ fontName->getCString()));
+ GooString *path2 = NULL;
+ error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', subst is '{1:t}'", fontName, substFontName);
+ if ((path2 = (GooString *)fontFiles->lookup(substFontName))) {
+ path = new GooString(path2);
+ if (substituteFontName)
+ substituteFontName->Set(path->getCString());
+ if (!strcasecmp(path->getCString() + path->getLength() - 4, ".ttc")) {
+ *type = sysFontTTC;
+ } else {
+ *type = sysFontTTF;
+ }
+ *fontNum = 0;
+ }
+ }
+ unlockGlobalParams;
+ return path;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Hints.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Hints.cc
new file mode 100644
index 00000000000..bdd0d322612
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Hints.cc
@@ -0,0 +1,452 @@
+//========================================================================
+//
+// Hints.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010, 2012 Hib Eris <hib@hiberis.nl>
+// Copyright 2010, 2011, 2013, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright 2010, 2013 Pino Toscano <pino@kde.org>
+// Copyright 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright 2014 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "Hints.h"
+
+#include "Linearization.h"
+#include "Object.h"
+#include "Stream.h"
+#include "XRef.h"
+#include "Parser.h"
+#include "Lexer.h"
+#include "SecurityHandler.h"
+
+#include <limits.h>
+
+//------------------------------------------------------------------------
+// Hints
+//------------------------------------------------------------------------
+
+Hints::Hints(BaseStream *str, Linearization *linearization, XRef *xref, SecurityHandler *secHdlr)
+{
+ mainXRefEntriesOffset = linearization->getMainXRefEntriesOffset();
+ nPages = linearization->getNumPages();
+ pageFirst = linearization->getPageFirst();
+ pageEndFirst = linearization->getEndFirst();
+ pageObjectFirst = linearization->getObjectNumberFirst();
+ if (pageObjectFirst < 0 || pageObjectFirst >= xref->getNumObjects()) {
+ error(errSyntaxWarning, -1,
+ "Invalid reference for first page object ({0:d}) in linearization table ",
+ pageObjectFirst);
+ pageObjectFirst = 0;
+ }
+ pageOffsetFirst = xref->getEntry(pageObjectFirst)->offset;
+
+ if (nPages >= INT_MAX / (int)sizeof(Guint)) {
+ error(errSyntaxWarning, -1, "Invalid number of pages ({0:d}) for hints table", nPages);
+ nPages = 0;
+ }
+ nObjects = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
+ pageObjectNum = (int *) gmallocn_checkoverflow(nPages, sizeof(int));
+ xRefOffset = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
+ pageLength = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
+ pageOffset = (Goffset *) gmallocn_checkoverflow(nPages, sizeof(Goffset));
+ numSharedObject = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
+ sharedObjectId = (Guint **) gmallocn_checkoverflow(nPages, sizeof(Guint*));
+ if (!nObjects || !pageObjectNum || !xRefOffset || !pageLength || !pageOffset ||
+ !numSharedObject || !sharedObjectId) {
+ error(errSyntaxWarning, -1, "Failed to allocate memory for hints table");
+ nPages = 0;
+ }
+
+ memset(pageLength, 0, nPages * sizeof(Guint));
+ memset(pageOffset, 0, nPages * sizeof(Guint));
+ memset(numSharedObject, 0, nPages * sizeof(Guint));
+ memset(pageObjectNum, 0, nPages * sizeof(int));
+
+ nSharedGroups = 0;
+ groupLength = NULL;
+ groupOffset = NULL;
+ groupHasSignature = NULL;
+ groupNumObjects = NULL;
+ groupXRefOffset = NULL;
+
+ readTables(str, linearization, xref, secHdlr);
+}
+
+Hints::~Hints()
+{
+ gfree(nObjects);
+ gfree(pageObjectNum);
+ gfree(xRefOffset);
+ gfree(pageLength);
+ gfree(pageOffset);
+ for (int i=0; i< nPages; i++) {
+ if (numSharedObject[i]) {
+ gfree(sharedObjectId[i]);
+ }
+ }
+ gfree(sharedObjectId);
+ gfree(numSharedObject);
+
+ gfree(groupLength);
+ gfree(groupOffset);
+ gfree(groupHasSignature);
+ gfree(groupNumObjects);
+ gfree(groupXRefOffset);
+}
+
+void Hints::readTables(BaseStream *str, Linearization *linearization, XRef *xref, SecurityHandler *secHdlr)
+{
+ hintsOffset = linearization->getHintsOffset();
+ hintsLength = linearization->getHintsLength();
+ hintsOffset2 = linearization->getHintsOffset2();
+ hintsLength2 = linearization->getHintsLength2();
+
+ Parser *parser;
+ Object obj;
+
+ int bufLength = hintsLength + hintsLength2;
+
+ std::vector<char> buf(bufLength);
+ char *p = &buf[0];
+
+ obj.initNull();
+ Stream *s = str->makeSubStream(hintsOffset, gFalse, hintsLength, &obj);
+ s->reset();
+ for (Guint i=0; i < hintsLength; i++) { *p++ = s->getChar(); }
+ delete s;
+
+ if (hintsOffset2 && hintsLength2) {
+ obj.initNull();
+ s = str->makeSubStream(hintsOffset2, gFalse, hintsLength2, &obj);
+ s->reset();
+ for (Guint i=0; i < hintsLength2; i++) { *p++ = s->getChar(); }
+ delete s;
+ }
+
+ obj.initNull();
+ MemStream *memStream = new MemStream (&buf[0], 0, bufLength, &obj);
+
+ obj.initNull();
+ parser = new Parser(xref, new Lexer(xref, memStream), gTrue);
+
+ int num, gen;
+ if (parser->getObj(&obj)->isInt() &&
+ (num = obj.getInt(), obj.free(), parser->getObj(&obj)->isInt()) &&
+ (gen = obj.getInt(), obj.free(), parser->getObj(&obj)->isCmd("obj")) &&
+ (obj.free(), parser->getObj(&obj, gFalse,
+ secHdlr ? secHdlr->getFileKey() : (Guchar *)NULL,
+ secHdlr ? secHdlr->getEncAlgorithm() : cryptRC4,
+ secHdlr ? secHdlr->getFileKeyLength() : 0,
+ num, gen, 0, gTrue)->isStream())) {
+ Stream *hintsStream = obj.getStream();
+ Dict *hintsDict = obj.streamGetDict();
+
+ int sharedStreamOffset = 0;
+ if (hintsDict->lookupInt("S", NULL, &sharedStreamOffset) &&
+ sharedStreamOffset > 0) {
+
+ hintsStream->reset();
+ readPageOffsetTable(hintsStream);
+
+ hintsStream->reset();
+ for (int i=0; i<sharedStreamOffset; i++) hintsStream->getChar();
+ readSharedObjectsTable(hintsStream);
+ } else {
+ error(errSyntaxWarning, -1, "Invalid shared object hint table offset");
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Failed parsing hints table object");
+ }
+ obj.free();
+
+ delete parser;
+}
+
+void Hints::readPageOffsetTable(Stream *str)
+{
+ if (nPages < 1) {
+ error(errSyntaxWarning, -1, "Invalid number of pages reading page offset hints table");
+ return;
+ }
+
+ inputBits = 0; // reset on byte boundary.
+
+ nObjectLeast = readBits(32, str);
+ if (nObjectLeast < 1) {
+ error(errSyntaxWarning, -1, "Invalid least number of objects reading page offset hints table");
+ nPages = 0;
+ return;
+ }
+
+ objectOffsetFirst = readBits(32, str);
+ if (objectOffsetFirst >= hintsOffset) objectOffsetFirst += hintsLength;
+
+ nBitsDiffObjects = readBits(16, str);
+
+ pageLengthLeast = readBits(32, str);
+
+ nBitsDiffPageLength = readBits(16, str);
+
+ OffsetStreamLeast = readBits(32, str);
+
+ nBitsOffsetStream = readBits(16, str);
+
+ lengthStreamLeast = readBits(32, str);
+
+ nBitsLengthStream = readBits(16, str);
+
+ nBitsNumShared = readBits(16, str);
+
+ nBitsShared = readBits(16, str);
+
+ nBitsNumerator = readBits(16, str);
+
+ denominator = readBits(16, str);
+
+ for (int i=0; i<nPages; i++) {
+ nObjects[i] = nObjectLeast + readBits(nBitsDiffObjects, str);
+ }
+
+ nObjects[0] = 0;
+ xRefOffset[0] = mainXRefEntriesOffset + 20;
+ for (int i=1; i<nPages; i++) {
+ xRefOffset[i] = xRefOffset[i-1] + 20*nObjects[i-1];
+ }
+
+ pageObjectNum[0] = 1;
+ for (int i=1; i<nPages; i++) {
+ pageObjectNum[i] = pageObjectNum[i-1] + nObjects[i-1];
+ }
+ pageObjectNum[0] = pageObjectFirst;
+
+ inputBits = 0; // reset on byte boundary. Not in specs!
+ for (int i=0; i<nPages; i++) {
+ pageLength[i] = pageLengthLeast + readBits(nBitsDiffPageLength, str);
+ }
+
+ inputBits = 0; // reset on byte boundary. Not in specs!
+ numSharedObject[0] = readBits(nBitsNumShared, str);
+ numSharedObject[0] = 0; // Do not trust the read value to be 0.
+ sharedObjectId[0] = NULL;
+ for (int i=1; i<nPages; i++) {
+ numSharedObject[i] = readBits(nBitsNumShared, str);
+ if (numSharedObject[i] >= INT_MAX / (int)sizeof(Guint)) {
+ error(errSyntaxWarning, -1, "Invalid number of shared objects");
+ numSharedObject[i] = 0;
+ return;
+ }
+ sharedObjectId[i] = (Guint *) gmallocn_checkoverflow(numSharedObject[i], sizeof(Guint));
+ if (numSharedObject[i] && !sharedObjectId[i]) {
+ error(errSyntaxWarning, -1, "Failed to allocate memory for shared object IDs");
+ numSharedObject[i] = 0;
+ return;
+ }
+ }
+
+ inputBits = 0; // reset on byte boundary. Not in specs!
+ for (int i=1; i<nPages; i++) {
+ for (Guint j=0; j < numSharedObject[i]; j++) {
+ sharedObjectId[i][j] = readBits(nBitsShared, str);
+ }
+ }
+
+ pageOffset[0] = pageOffsetFirst;
+ // find pageOffsets.
+ for (int i=1; i<nPages; i++) {
+ pageOffset[i] = pageOffset[i-1] + pageLength[i-1];
+ }
+
+}
+
+void Hints::readSharedObjectsTable(Stream *str)
+{
+ inputBits = 0; // reset on byte boundary.
+
+ Guint firstSharedObjectNumber = readBits(32, str);
+
+ Guint firstSharedObjectOffset = readBits(32, str);
+ firstSharedObjectOffset += hintsLength;
+
+ Guint nSharedGroupsFirst = readBits(32, str);
+
+ Guint nSharedGroups = readBits(32, str);
+
+ Guint nBitsNumObjects = readBits(16, str);
+
+ Guint groupLengthLeast = readBits(32, str);
+
+ Guint nBitsDiffGroupLength = readBits(16, str);
+
+ if ((!nSharedGroups) || (nSharedGroups >= INT_MAX / (int)sizeof(Guint))) {
+ error(errSyntaxWarning, -1, "Invalid number of shared object groups");
+ nSharedGroups = 0;
+ return;
+ }
+ if ((!nSharedGroupsFirst) || (nSharedGroupsFirst > nSharedGroups)) {
+ error(errSyntaxWarning, -1, "Invalid number of first page shared object groups");
+ nSharedGroups = 0;
+ return;
+ }
+
+ groupLength = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
+ groupOffset = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
+ groupHasSignature = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
+ groupNumObjects = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
+ groupXRefOffset = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
+ if (!groupLength || !groupOffset || !groupHasSignature ||
+ !groupNumObjects || !groupXRefOffset) {
+ error(errSyntaxWarning, -1, "Failed to allocate memory for shared object groups");
+ nSharedGroups = 0;
+ return;
+ }
+
+ inputBits = 0; // reset on byte boundary. Not in specs!
+ for (Guint i=0; i<nSharedGroups; i++) {
+ groupLength[i] = groupLengthLeast + readBits(nBitsDiffGroupLength, str);
+ }
+
+ groupOffset[0] = objectOffsetFirst;
+ for (Guint i=1; i<nSharedGroupsFirst; i++) {
+ groupOffset[i] = groupOffset[i-1] + groupLength[i-1];
+ }
+ if (nSharedGroups > nSharedGroupsFirst ) {
+ groupOffset[nSharedGroupsFirst] = firstSharedObjectOffset;
+ for (Guint i=nSharedGroupsFirst+1; i<nSharedGroups; i++) {
+ groupOffset[i] = groupOffset[i-1] + groupLength[i-1];
+ }
+ }
+
+ inputBits = 0; // reset on byte boundary. Not in specs!
+ for (Guint i=0; i<nSharedGroups; i++) {
+ groupHasSignature[i] = readBits(1, str);
+ }
+
+ inputBits = 0; // reset on byte boundary. Not in specs!
+ for (Guint i=0; i<nSharedGroups; i++) {
+ if (groupHasSignature[i]) {
+ readBits(128, str);
+ }
+ }
+
+ inputBits = 0; // reset on byte boundary. Not in specs!
+ for (Guint i=0; i<nSharedGroups; i++) {
+ groupNumObjects[i] =
+ nBitsNumObjects ? 1 + readBits(nBitsNumObjects, str) : 1;
+ }
+
+ for (Guint i=0; i<nSharedGroupsFirst; i++) {
+ groupNumObjects[i] = 0;
+ groupXRefOffset[i] = 0;
+ }
+ if (nSharedGroups > nSharedGroupsFirst ) {
+ groupXRefOffset[nSharedGroupsFirst] =
+ mainXRefEntriesOffset + 20*firstSharedObjectNumber;
+ for (Guint i=nSharedGroupsFirst+1; i<nSharedGroups; i++) {
+ groupXRefOffset[i] = groupXRefOffset[i-1] + 20*groupNumObjects[i-1];
+ }
+ }
+}
+
+Goffset Hints::getPageOffset(int page)
+{
+ if ((page < 1) || (page > nPages)) return 0;
+
+ if (page-1 > pageFirst)
+ return pageOffset[page-1];
+ else if (page-1 < pageFirst)
+ return pageOffset[page];
+ else
+ return pageOffset[0];
+}
+
+std::vector<ByteRange>* Hints::getPageRanges(int page)
+{
+ if ((page < 1) || (page > nPages)) return NULL;
+
+ int idx;
+ if (page-1 > pageFirst)
+ idx = page-1;
+ else if (page-1 < pageFirst)
+ idx = page;
+ else
+ idx = 0;
+
+ ByteRange pageRange;
+ std::vector<ByteRange> *v = new std::vector<ByteRange>;
+
+ pageRange.offset = pageOffset[idx];
+ pageRange.length = pageLength[idx];
+ v->push_back(pageRange);
+
+ pageRange.offset = xRefOffset[idx];
+ pageRange.length = 20*nObjects[idx];
+ v->push_back(pageRange);
+
+ for (Guint j=0; j<numSharedObject[idx]; j++) {
+ Guint k = sharedObjectId[idx][j];
+
+ pageRange.offset = groupOffset[k];
+ pageRange.length = groupLength[k];
+ v->push_back(pageRange);
+
+ pageRange.offset = groupXRefOffset[k];
+ pageRange.length = 20*groupNumObjects[k];
+ v->push_back(pageRange);
+ }
+
+ return v;
+}
+
+Guint Hints::readBit(Stream *str)
+{
+ Guint bit;
+ int c;
+
+ if (inputBits == 0) {
+ if ((c = str->getChar()) == EOF) {
+ return (Guint) -1;
+ }
+ bitsBuffer = c;
+ inputBits = 8;
+ }
+ bit = (bitsBuffer >> (inputBits - 1)) & 1;
+ --inputBits;
+ return bit;
+}
+
+Guint Hints::readBits(int n, Stream *str)
+{
+ Guint bit, bits;
+
+ if (n < 0) return -1;
+ if (n == 0) return 0;
+
+ if (n == 1)
+ return readBit(str);
+
+ bit = (readBit(str) << (n-1));
+ if (bit == (Guint) -1)
+ return -1;
+
+ bits = readBits(n-1, str);
+ if (bits == (Guint) -1)
+ return -1;
+
+ return bit | bits;
+}
+
+int Hints::getPageObjectNum(int page) {
+ if ((page < 1) || (page > nPages)) return 0;
+
+ if (page-1 > pageFirst)
+ return pageObjectNum[page-1];
+ else if (page-1 < pageFirst)
+ return pageObjectNum[page];
+ else
+ return pageObjectNum[0];
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Hints.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Hints.h
new file mode 100644
index 00000000000..f46c07f673b
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Hints.h
@@ -0,0 +1,95 @@
+//========================================================================
+//
+// Hints.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright 2013 Adrian Johnson <ajohnson@redneon.com>
+//
+//========================================================================
+
+#ifndef HINTS_H
+#define HINTS_H
+
+#include <string.h>
+#include "goo/gtypes.h"
+#include <vector>
+#include "PDFDoc.h"
+
+class Stream;
+class BaseStream;
+class Linearization;
+class XRef;
+
+//------------------------------------------------------------------------
+// Hints
+//------------------------------------------------------------------------
+
+class Hints {
+public:
+
+ Hints(BaseStream *str, Linearization *linearization, XRef *xref, SecurityHandler *secHdlr);
+ ~Hints();
+
+ int getPageObjectNum(int page);
+ Goffset getPageOffset(int page);
+ std::vector<ByteRange>* getPageRanges(int page);
+
+private:
+
+ void readTables(BaseStream *str, Linearization *linearization, XRef *xref, SecurityHandler *secHdlr);
+ void readPageOffsetTable(Stream *str);
+ void readSharedObjectsTable(Stream *str);
+
+ Guint readBit(Stream *str);
+ Guint readBits(int n, Stream *str);
+
+ Guint hintsOffset;
+ Guint hintsLength;
+ Guint hintsOffset2;
+ Guint hintsLength2;
+ Guint mainXRefEntriesOffset;
+
+ int nPages;
+ int pageFirst;
+ int pageObjectFirst;
+ Goffset pageOffsetFirst;
+ Guint pageEndFirst;
+
+ Guint nObjectLeast;
+ Guint objectOffsetFirst;
+ Guint nBitsDiffObjects;
+ Guint pageLengthLeast;
+ Guint nBitsDiffPageLength;
+ Guint OffsetStreamLeast;
+ Guint nBitsOffsetStream;
+ Guint lengthStreamLeast;
+ Guint nBitsLengthStream;
+ Guint nBitsNumShared;
+ Guint nBitsShared;
+ Guint nBitsNumerator;
+ Guint denominator;
+
+ Guint *nObjects;
+ int *pageObjectNum;
+ Guint *xRefOffset;
+ Guint *pageLength;
+ Goffset *pageOffset;
+ Guint *numSharedObject;
+ Guint **sharedObjectId;
+
+ Guint nSharedGroups;
+ Guint *groupLength;
+ Guint *groupOffset;
+ Guint *groupHasSignature;
+ Guint *groupNumObjects;
+ Guint *groupXRefOffset;
+
+ int inputBits;
+ char bitsBuffer;
+
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/JArithmeticDecoder.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/JArithmeticDecoder.cc
new file mode 100644
index 00000000000..d23f7ea3887
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/JArithmeticDecoder.cc
@@ -0,0 +1,355 @@
+//========================================================================
+//
+// JArithmeticDecoder.cc
+//
+// Copyright 2002-2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "Object.h"
+#include "Stream.h"
+#include "JArithmeticDecoder.h"
+
+//------------------------------------------------------------------------
+// JArithmeticDecoderStates
+//------------------------------------------------------------------------
+
+JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) {
+ contextSize = contextSizeA;
+ cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar));
+ reset();
+}
+
+JArithmeticDecoderStats::~JArithmeticDecoderStats() {
+ gfree(cxTab);
+}
+
+JArithmeticDecoderStats *JArithmeticDecoderStats::copy() {
+ JArithmeticDecoderStats *stats;
+
+ stats = new JArithmeticDecoderStats(contextSize);
+ memcpy(stats->cxTab, cxTab, contextSize);
+ return stats;
+}
+
+void JArithmeticDecoderStats::reset() {
+ memset(cxTab, 0, contextSize);
+}
+
+void JArithmeticDecoderStats::copyFrom(JArithmeticDecoderStats *stats) {
+ memcpy(cxTab, stats->cxTab, contextSize);
+}
+
+void JArithmeticDecoderStats::setEntry(Guint cx, int i, int mps) {
+ cxTab[cx] = (i << 1) + mps;
+}
+
+//------------------------------------------------------------------------
+// JArithmeticDecoder
+//------------------------------------------------------------------------
+
+Guint JArithmeticDecoder::qeTab[47] = {
+ 0x56010000, 0x34010000, 0x18010000, 0x0AC10000,
+ 0x05210000, 0x02210000, 0x56010000, 0x54010000,
+ 0x48010000, 0x38010000, 0x30010000, 0x24010000,
+ 0x1C010000, 0x16010000, 0x56010000, 0x54010000,
+ 0x51010000, 0x48010000, 0x38010000, 0x34010000,
+ 0x30010000, 0x28010000, 0x24010000, 0x22010000,
+ 0x1C010000, 0x18010000, 0x16010000, 0x14010000,
+ 0x12010000, 0x11010000, 0x0AC10000, 0x09C10000,
+ 0x08A10000, 0x05210000, 0x04410000, 0x02A10000,
+ 0x02210000, 0x01410000, 0x01110000, 0x00850000,
+ 0x00490000, 0x00250000, 0x00150000, 0x00090000,
+ 0x00050000, 0x00010000, 0x56010000
+};
+
+int JArithmeticDecoder::nmpsTab[47] = {
+ 1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46
+};
+
+int JArithmeticDecoder::nlpsTab[47] = {
+ 1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14,
+ 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46
+};
+
+int JArithmeticDecoder::switchTab[47] = {
+ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+JArithmeticDecoder::JArithmeticDecoder() {
+ str = NULL;
+ dataLen = 0;
+ limitStream = gFalse;
+ nBytesRead = 0;
+}
+
+inline Guint JArithmeticDecoder::readByte() {
+ if (limitStream) {
+ --dataLen;
+ if (dataLen < 0) {
+ return 0xff;
+ }
+ }
+ ++nBytesRead;
+ return (Guint)str->getChar() & 0xff;
+}
+
+JArithmeticDecoder::~JArithmeticDecoder() {
+ cleanup();
+}
+
+void JArithmeticDecoder::start() {
+ buf0 = readByte();
+ buf1 = readByte();
+
+ // INITDEC
+ c = (buf0 ^ 0xff) << 16;
+ byteIn();
+ c <<= 7;
+ ct -= 7;
+ a = 0x80000000;
+}
+
+void JArithmeticDecoder::restart(int dataLenA) {
+ Guint cAdd;
+ GBool prevFF;
+ int k, nBits;
+
+ if (dataLen >= 0) {
+ dataLen = dataLenA;
+ } else if (dataLen == -1) {
+ dataLen = dataLenA;
+ buf1 = readByte();
+ } else {
+ k = (-dataLen - 1) * 8 - ct;
+ dataLen = dataLenA;
+ cAdd = 0;
+ prevFF = gFalse;
+ while (k > 0) {
+ buf0 = readByte();
+ if (prevFF) {
+ cAdd += 0xfe00 - (buf0 << 9);
+ nBits = 7;
+ } else {
+ cAdd += 0xff00 - (buf0 << 8);
+ nBits = 8;
+ }
+ prevFF = buf0 == 0xff;
+ if (k > nBits) {
+ cAdd <<= nBits;
+ k -= nBits;
+ } else {
+ cAdd <<= k;
+ ct = nBits - k;
+ k = 0;
+ }
+ }
+ c += cAdd;
+ buf1 = readByte();
+ }
+}
+
+void JArithmeticDecoder::cleanup() {
+ if (limitStream) {
+ while (dataLen > 0) {
+ buf0 = buf1;
+ buf1 = readByte();
+ }
+ }
+}
+
+int JArithmeticDecoder::decodeBit(Guint context,
+ JArithmeticDecoderStats *stats) {
+ int bit;
+ Guint qe;
+ int iCX, mpsCX;
+
+ iCX = stats->cxTab[context] >> 1;
+ mpsCX = stats->cxTab[context] & 1;
+ qe = qeTab[iCX];
+ a -= qe;
+ if (c < a) {
+ if (a & 0x80000000) {
+ bit = mpsCX;
+ } else {
+ // MPS_EXCHANGE
+ if (a < qe) {
+ bit = 1 - mpsCX;
+ if (switchTab[iCX]) {
+ stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX);
+ } else {
+ stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX;
+ }
+ } else {
+ bit = mpsCX;
+ stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX;
+ }
+ // RENORMD
+ do {
+ if (ct == 0) {
+ byteIn();
+ }
+ a <<= 1;
+ c <<= 1;
+ --ct;
+ } while (!(a & 0x80000000));
+ }
+ } else {
+ c -= a;
+ // LPS_EXCHANGE
+ if (a < qe) {
+ bit = mpsCX;
+ stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX;
+ } else {
+ bit = 1 - mpsCX;
+ if (switchTab[iCX]) {
+ stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX);
+ } else {
+ stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX;
+ }
+ }
+ a = qe;
+ // RENORMD
+ do {
+ if (ct == 0) {
+ byteIn();
+ }
+ a <<= 1;
+ c <<= 1;
+ --ct;
+ } while (!(a & 0x80000000));
+ }
+ return bit;
+}
+
+int JArithmeticDecoder::decodeByte(Guint context,
+ JArithmeticDecoderStats *stats) {
+ int byte;
+ int i;
+
+ byte = 0;
+ for (i = 0; i < 8; ++i) {
+ byte = (byte << 1) | decodeBit(context, stats);
+ }
+ return byte;
+}
+
+GBool JArithmeticDecoder::decodeInt(int *x, JArithmeticDecoderStats *stats) {
+ int s;
+ Guint v;
+ int i;
+
+ prev = 1;
+ s = decodeIntBit(stats);
+ if (decodeIntBit(stats)) {
+ if (decodeIntBit(stats)) {
+ if (decodeIntBit(stats)) {
+ if (decodeIntBit(stats)) {
+ if (decodeIntBit(stats)) {
+ v = 0;
+ for (i = 0; i < 32; ++i) {
+ v = (v << 1) | decodeIntBit(stats);
+ }
+ v += 4436;
+ } else {
+ v = 0;
+ for (i = 0; i < 12; ++i) {
+ v = (v << 1) | decodeIntBit(stats);
+ }
+ v += 340;
+ }
+ } else {
+ v = 0;
+ for (i = 0; i < 8; ++i) {
+ v = (v << 1) | decodeIntBit(stats);
+ }
+ v += 84;
+ }
+ } else {
+ v = 0;
+ for (i = 0; i < 6; ++i) {
+ v = (v << 1) | decodeIntBit(stats);
+ }
+ v += 20;
+ }
+ } else {
+ v = decodeIntBit(stats);
+ v = (v << 1) | decodeIntBit(stats);
+ v = (v << 1) | decodeIntBit(stats);
+ v = (v << 1) | decodeIntBit(stats);
+ v += 4;
+ }
+ } else {
+ v = decodeIntBit(stats);
+ v = (v << 1) | decodeIntBit(stats);
+ }
+
+ if (s) {
+ if (v == 0) {
+ return gFalse;
+ }
+ *x = -(int)v;
+ } else {
+ *x = (int)v;
+ }
+ return gTrue;
+}
+
+int JArithmeticDecoder::decodeIntBit(JArithmeticDecoderStats *stats) {
+ int bit;
+
+ bit = decodeBit(prev, stats);
+ if (prev < 0x100) {
+ prev = (prev << 1) | bit;
+ } else {
+ prev = (((prev << 1) | bit) & 0x1ff) | 0x100;
+ }
+ return bit;
+}
+
+Guint JArithmeticDecoder::decodeIAID(Guint codeLen,
+ JArithmeticDecoderStats *stats) {
+ Guint i;
+ int bit;
+
+ prev = 1;
+ for (i = 0; i < codeLen; ++i) {
+ bit = decodeBit(prev, stats);
+ prev = (prev << 1) | bit;
+ }
+ return prev - (1 << codeLen);
+}
+
+void JArithmeticDecoder::byteIn() {
+ if (buf0 == 0xff) {
+ if (buf1 > 0x8f) {
+ if (limitStream) {
+ buf0 = buf1;
+ buf1 = readByte();
+ c = c + 0xff00 - (buf0 << 8);
+ }
+ ct = 8;
+ } else {
+ buf0 = buf1;
+ buf1 = readByte();
+ c = c + 0xfe00 - (buf0 << 9);
+ ct = 7;
+ }
+ } else {
+ buf0 = buf1;
+ buf1 = readByte();
+ c = c + 0xff00 - (buf0 << 8);
+ ct = 8;
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/JArithmeticDecoder.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/JArithmeticDecoder.h
new file mode 100644
index 00000000000..3c3e6fed0e5
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/JArithmeticDecoder.h
@@ -0,0 +1,111 @@
+//========================================================================
+//
+// JArithmeticDecoder.h
+//
+// Arithmetic decoder used by the JBIG2 and JPEG2000 decoders.
+//
+// Copyright 2002-2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef JARITHMETICDECODER_H
+#define JARITHMETICDECODER_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+
+class Stream;
+
+//------------------------------------------------------------------------
+// JArithmeticDecoderStats
+//------------------------------------------------------------------------
+
+class JArithmeticDecoderStats {
+public:
+
+ JArithmeticDecoderStats(int contextSizeA);
+ ~JArithmeticDecoderStats();
+ JArithmeticDecoderStats *copy();
+ void reset();
+ int getContextSize() { return contextSize; }
+ void copyFrom(JArithmeticDecoderStats *stats);
+ void setEntry(Guint cx, int i, int mps);
+
+private:
+
+ Guchar *cxTab; // cxTab[cx] = (i[cx] << 1) + mps[cx]
+ int contextSize;
+
+ friend class JArithmeticDecoder;
+};
+
+//------------------------------------------------------------------------
+// JArithmeticDecoder
+//------------------------------------------------------------------------
+
+class JArithmeticDecoder {
+public:
+
+ JArithmeticDecoder();
+ ~JArithmeticDecoder();
+
+ void setStream(Stream *strA)
+ { str = strA; dataLen = 0; limitStream = gFalse; }
+ void setStream(Stream *strA, int dataLenA)
+ { str = strA; dataLen = dataLenA; limitStream = gTrue; }
+
+ // Start decoding on a new stream. This fills the byte buffers and
+ // runs INITDEC.
+ void start();
+
+ // Restart decoding on an interrupted stream. This refills the
+ // buffers if needed, but does not run INITDEC. (This is used in
+ // JPEG 2000 streams when codeblock data is split across multiple
+ // packets/layers.)
+ void restart(int dataLenA);
+
+ // Read any leftover data in the stream.
+ void cleanup();
+
+ // Decode one bit.
+ int decodeBit(Guint context, JArithmeticDecoderStats *stats);
+
+ // Decode eight bits.
+ int decodeByte(Guint context, JArithmeticDecoderStats *stats);
+
+ // Returns false for OOB, otherwise sets *<x> and returns true.
+ GBool decodeInt(int *x, JArithmeticDecoderStats *stats);
+
+ Guint decodeIAID(Guint codeLen,
+ JArithmeticDecoderStats *stats);
+
+ void resetByteCounter() { nBytesRead = 0; }
+ Guint getByteCounter() { return nBytesRead; }
+
+private:
+
+ Guint readByte();
+ int decodeIntBit(JArithmeticDecoderStats *stats);
+ void byteIn();
+
+ static Guint qeTab[47];
+ static int nmpsTab[47];
+ static int nlpsTab[47];
+ static int switchTab[47];
+
+ Guint buf0, buf1;
+ Guint c, a;
+ int ct;
+
+ Guint prev; // for the integer decoder
+
+ Stream *str;
+ Guint nBytesRead;
+ int dataLen;
+ GBool limitStream;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/JBIG2Stream.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/JBIG2Stream.cc
new file mode 100644
index 00000000000..66c1d2505e8
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/JBIG2Stream.cc
@@ -0,0 +1,4292 @@
+//========================================================================
+//
+// JBIG2Stream.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Raj Kumar <rkumar@archive.org>
+// Copyright (C) 2006 Paul Walmsley <paul@booyaka.com>
+// Copyright (C) 2006-2010, 2012, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2011 Edward Jiang <ejiang@google.com>
+// Copyright (C) 2012 William Bader <williambader@hotmail.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013, 2014 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2015 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+#include "goo/GooList.h"
+#include "Error.h"
+#include "JArithmeticDecoder.h"
+#include "JBIG2Stream.h"
+
+//~ share these tables
+#include "Stream-CCITT.h"
+
+//------------------------------------------------------------------------
+
+static const int contextSize[4] = { 16, 13, 10, 10 };
+static const int refContextSize[2] = { 13, 10 };
+
+//------------------------------------------------------------------------
+// JBIG2HuffmanTable
+//------------------------------------------------------------------------
+
+#define jbig2HuffmanLOW 0xfffffffd
+#define jbig2HuffmanOOB 0xfffffffe
+#define jbig2HuffmanEOT 0xffffffff
+
+struct JBIG2HuffmanTable {
+ int val;
+ Guint prefixLen;
+ Guint rangeLen; // can also be LOW, OOB, or EOT
+ Guint prefix;
+};
+
+static JBIG2HuffmanTable huffTableA[] = {
+ { 0, 1, 4, 0x000 },
+ { 16, 2, 8, 0x002 },
+ { 272, 3, 16, 0x006 },
+ { 65808, 3, 32, 0x007 },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableB[] = {
+ { 0, 1, 0, 0x000 },
+ { 1, 2, 0, 0x002 },
+ { 2, 3, 0, 0x006 },
+ { 3, 4, 3, 0x00e },
+ { 11, 5, 6, 0x01e },
+ { 75, 6, 32, 0x03e },
+ { 0, 6, jbig2HuffmanOOB, 0x03f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableC[] = {
+ { 0, 1, 0, 0x000 },
+ { 1, 2, 0, 0x002 },
+ { 2, 3, 0, 0x006 },
+ { 3, 4, 3, 0x00e },
+ { 11, 5, 6, 0x01e },
+ { 0, 6, jbig2HuffmanOOB, 0x03e },
+ { 75, 7, 32, 0x0fe },
+ { -256, 8, 8, 0x0fe },
+ { -257, 8, jbig2HuffmanLOW, 0x0ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableD[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 2, 0, 0x002 },
+ { 3, 3, 0, 0x006 },
+ { 4, 4, 3, 0x00e },
+ { 12, 5, 6, 0x01e },
+ { 76, 5, 32, 0x01f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableE[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 2, 0, 0x002 },
+ { 3, 3, 0, 0x006 },
+ { 4, 4, 3, 0x00e },
+ { 12, 5, 6, 0x01e },
+ { 76, 6, 32, 0x03e },
+ { -255, 7, 8, 0x07e },
+ { -256, 7, jbig2HuffmanLOW, 0x07f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableF[] = {
+ { 0, 2, 7, 0x000 },
+ { 128, 3, 7, 0x002 },
+ { 256, 3, 8, 0x003 },
+ { -1024, 4, 9, 0x008 },
+ { -512, 4, 8, 0x009 },
+ { -256, 4, 7, 0x00a },
+ { -32, 4, 5, 0x00b },
+ { 512, 4, 9, 0x00c },
+ { 1024, 4, 10, 0x00d },
+ { -2048, 5, 10, 0x01c },
+ { -128, 5, 6, 0x01d },
+ { -64, 5, 5, 0x01e },
+ { -2049, 6, jbig2HuffmanLOW, 0x03e },
+ { 2048, 6, 32, 0x03f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableG[] = {
+ { -512, 3, 8, 0x000 },
+ { 256, 3, 8, 0x001 },
+ { 512, 3, 9, 0x002 },
+ { 1024, 3, 10, 0x003 },
+ { -1024, 4, 9, 0x008 },
+ { -256, 4, 7, 0x009 },
+ { -32, 4, 5, 0x00a },
+ { 0, 4, 5, 0x00b },
+ { 128, 4, 7, 0x00c },
+ { -128, 5, 6, 0x01a },
+ { -64, 5, 5, 0x01b },
+ { 32, 5, 5, 0x01c },
+ { 64, 5, 6, 0x01d },
+ { -1025, 5, jbig2HuffmanLOW, 0x01e },
+ { 2048, 5, 32, 0x01f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableH[] = {
+ { 0, 2, 1, 0x000 },
+ { 0, 2, jbig2HuffmanOOB, 0x001 },
+ { 4, 3, 4, 0x004 },
+ { -1, 4, 0, 0x00a },
+ { 22, 4, 4, 0x00b },
+ { 38, 4, 5, 0x00c },
+ { 2, 5, 0, 0x01a },
+ { 70, 5, 6, 0x01b },
+ { 134, 5, 7, 0x01c },
+ { 3, 6, 0, 0x03a },
+ { 20, 6, 1, 0x03b },
+ { 262, 6, 7, 0x03c },
+ { 646, 6, 10, 0x03d },
+ { -2, 7, 0, 0x07c },
+ { 390, 7, 8, 0x07d },
+ { -15, 8, 3, 0x0fc },
+ { -5, 8, 1, 0x0fd },
+ { -7, 9, 1, 0x1fc },
+ { -3, 9, 0, 0x1fd },
+ { -16, 9, jbig2HuffmanLOW, 0x1fe },
+ { 1670, 9, 32, 0x1ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableI[] = {
+ { 0, 2, jbig2HuffmanOOB, 0x000 },
+ { -1, 3, 1, 0x002 },
+ { 1, 3, 1, 0x003 },
+ { 7, 3, 5, 0x004 },
+ { -3, 4, 1, 0x00a },
+ { 43, 4, 5, 0x00b },
+ { 75, 4, 6, 0x00c },
+ { 3, 5, 1, 0x01a },
+ { 139, 5, 7, 0x01b },
+ { 267, 5, 8, 0x01c },
+ { 5, 6, 1, 0x03a },
+ { 39, 6, 2, 0x03b },
+ { 523, 6, 8, 0x03c },
+ { 1291, 6, 11, 0x03d },
+ { -5, 7, 1, 0x07c },
+ { 779, 7, 9, 0x07d },
+ { -31, 8, 4, 0x0fc },
+ { -11, 8, 2, 0x0fd },
+ { -15, 9, 2, 0x1fc },
+ { -7, 9, 1, 0x1fd },
+ { -32, 9, jbig2HuffmanLOW, 0x1fe },
+ { 3339, 9, 32, 0x1ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableJ[] = {
+ { -2, 2, 2, 0x000 },
+ { 6, 2, 6, 0x001 },
+ { 0, 2, jbig2HuffmanOOB, 0x002 },
+ { -3, 5, 0, 0x018 },
+ { 2, 5, 0, 0x019 },
+ { 70, 5, 5, 0x01a },
+ { 3, 6, 0, 0x036 },
+ { 102, 6, 5, 0x037 },
+ { 134, 6, 6, 0x038 },
+ { 198, 6, 7, 0x039 },
+ { 326, 6, 8, 0x03a },
+ { 582, 6, 9, 0x03b },
+ { 1094, 6, 10, 0x03c },
+ { -21, 7, 4, 0x07a },
+ { -4, 7, 0, 0x07b },
+ { 4, 7, 0, 0x07c },
+ { 2118, 7, 11, 0x07d },
+ { -5, 8, 0, 0x0fc },
+ { 5, 8, 0, 0x0fd },
+ { -22, 8, jbig2HuffmanLOW, 0x0fe },
+ { 4166, 8, 32, 0x0ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableK[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 2, 1, 0x002 },
+ { 4, 4, 0, 0x00c },
+ { 5, 4, 1, 0x00d },
+ { 7, 5, 1, 0x01c },
+ { 9, 5, 2, 0x01d },
+ { 13, 6, 2, 0x03c },
+ { 17, 7, 2, 0x07a },
+ { 21, 7, 3, 0x07b },
+ { 29, 7, 4, 0x07c },
+ { 45, 7, 5, 0x07d },
+ { 77, 7, 6, 0x07e },
+ { 141, 7, 32, 0x07f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableL[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 2, 0, 0x002 },
+ { 3, 3, 1, 0x006 },
+ { 5, 5, 0, 0x01c },
+ { 6, 5, 1, 0x01d },
+ { 8, 6, 1, 0x03c },
+ { 10, 7, 0, 0x07a },
+ { 11, 7, 1, 0x07b },
+ { 13, 7, 2, 0x07c },
+ { 17, 7, 3, 0x07d },
+ { 25, 7, 4, 0x07e },
+ { 41, 8, 5, 0x0fe },
+ { 73, 8, 32, 0x0ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableM[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 3, 0, 0x004 },
+ { 7, 3, 3, 0x005 },
+ { 3, 4, 0, 0x00c },
+ { 5, 4, 1, 0x00d },
+ { 4, 5, 0, 0x01c },
+ { 15, 6, 1, 0x03a },
+ { 17, 6, 2, 0x03b },
+ { 21, 6, 3, 0x03c },
+ { 29, 6, 4, 0x03d },
+ { 45, 6, 5, 0x03e },
+ { 77, 7, 6, 0x07e },
+ { 141, 7, 32, 0x07f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableN[] = {
+ { 0, 1, 0, 0x000 },
+ { -2, 3, 0, 0x004 },
+ { -1, 3, 0, 0x005 },
+ { 1, 3, 0, 0x006 },
+ { 2, 3, 0, 0x007 },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+static JBIG2HuffmanTable huffTableO[] = {
+ { 0, 1, 0, 0x000 },
+ { -1, 3, 0, 0x004 },
+ { 1, 3, 0, 0x005 },
+ { -2, 4, 0, 0x00c },
+ { 2, 4, 0, 0x00d },
+ { -4, 5, 1, 0x01c },
+ { 3, 5, 1, 0x01d },
+ { -8, 6, 2, 0x03c },
+ { 5, 6, 2, 0x03d },
+ { -24, 7, 4, 0x07c },
+ { 9, 7, 4, 0x07d },
+ { -25, 7, jbig2HuffmanLOW, 0x07e },
+ { 25, 7, 32, 0x07f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+//------------------------------------------------------------------------
+// JBIG2HuffmanDecoder
+//------------------------------------------------------------------------
+
+class JBIG2HuffmanDecoder {
+public:
+
+ JBIG2HuffmanDecoder();
+ ~JBIG2HuffmanDecoder();
+ void setStream(Stream *strA) { str = strA; }
+
+ void reset();
+
+ // Returns false for OOB, otherwise sets *<x> and returns true.
+ GBool decodeInt(int *x, JBIG2HuffmanTable *table);
+
+ Guint readBits(Guint n);
+ Guint readBit();
+
+ // Sort the table by prefix length and assign prefix values.
+ void buildTable(JBIG2HuffmanTable *table, Guint len);
+
+private:
+
+ Stream *str;
+ Guint buf;
+ Guint bufLen;
+};
+
+JBIG2HuffmanDecoder::JBIG2HuffmanDecoder() {
+ str = NULL;
+ reset();
+}
+
+JBIG2HuffmanDecoder::~JBIG2HuffmanDecoder() {
+}
+
+void JBIG2HuffmanDecoder::reset() {
+ buf = 0;
+ bufLen = 0;
+}
+
+//~ optimize this
+GBool JBIG2HuffmanDecoder::decodeInt(int *x, JBIG2HuffmanTable *table) {
+ Guint i, len, prefix;
+
+ i = 0;
+ len = 0;
+ prefix = 0;
+ while (table[i].rangeLen != jbig2HuffmanEOT) {
+ while (len < table[i].prefixLen) {
+ prefix = (prefix << 1) | readBit();
+ ++len;
+ }
+ if (prefix == table[i].prefix) {
+ if (table[i].rangeLen == jbig2HuffmanOOB) {
+ return gFalse;
+ }
+ if (table[i].rangeLen == jbig2HuffmanLOW) {
+ *x = table[i].val - readBits(32);
+ } else if (table[i].rangeLen > 0) {
+ *x = table[i].val + readBits(table[i].rangeLen);
+ } else {
+ *x = table[i].val;
+ }
+ return gTrue;
+ }
+ ++i;
+ }
+ return gFalse;
+}
+
+Guint JBIG2HuffmanDecoder::readBits(Guint n) {
+ Guint x, mask, nLeft;
+
+ mask = (n == 32) ? 0xffffffff : ((1 << n) - 1);
+ if (bufLen >= n) {
+ x = (buf >> (bufLen - n)) & mask;
+ bufLen -= n;
+ } else {
+ x = buf & ((1 << bufLen) - 1);
+ nLeft = n - bufLen;
+ bufLen = 0;
+ while (nLeft >= 8) {
+ x = (x << 8) | (str->getChar() & 0xff);
+ nLeft -= 8;
+ }
+ if (nLeft > 0) {
+ buf = str->getChar();
+ bufLen = 8 - nLeft;
+ x = (x << nLeft) | ((buf >> bufLen) & ((1 << nLeft) - 1));
+ }
+ }
+ return x;
+}
+
+Guint JBIG2HuffmanDecoder::readBit() {
+ if (bufLen == 0) {
+ buf = str->getChar();
+ bufLen = 8;
+ }
+ --bufLen;
+ return (buf >> bufLen) & 1;
+}
+
+void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) {
+ Guint i, j, k, prefix;
+ JBIG2HuffmanTable tab;
+
+ // stable selection sort:
+ // - entries with prefixLen > 0, in ascending prefixLen order
+ // - entry with prefixLen = 0, rangeLen = EOT
+ // - all other entries with prefixLen = 0
+ // (on entry, table[len] has prefixLen = 0, rangeLen = EOT)
+ for (i = 0; i < len; ++i) {
+ for (j = i; j < len && table[j].prefixLen == 0; ++j) ;
+ if (j == len) {
+ break;
+ }
+ for (k = j + 1; k < len; ++k) {
+ if (table[k].prefixLen > 0 &&
+ table[k].prefixLen < table[j].prefixLen) {
+ j = k;
+ }
+ }
+ if (j != i) {
+ tab = table[j];
+ for (k = j; k > i; --k) {
+ table[k] = table[k - 1];
+ }
+ table[i] = tab;
+ }
+ }
+ table[i] = table[len];
+
+ // assign prefixes
+ if (table[0].rangeLen != jbig2HuffmanEOT) {
+ i = 0;
+ prefix = 0;
+ table[i++].prefix = prefix++;
+ for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) {
+ prefix <<= table[i].prefixLen - table[i-1].prefixLen;
+ table[i].prefix = prefix++;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// JBIG2MMRDecoder
+//------------------------------------------------------------------------
+
+class JBIG2MMRDecoder {
+public:
+
+ JBIG2MMRDecoder();
+ ~JBIG2MMRDecoder();
+ void setStream(Stream *strA) { str = strA; }
+ void reset();
+ int get2DCode();
+ int getBlackCode();
+ int getWhiteCode();
+ Guint get24Bits();
+ void skipTo(Guint length);
+
+private:
+
+ Stream *str;
+ Guint buf;
+ Guint bufLen;
+ Guint nBytesRead;
+};
+
+JBIG2MMRDecoder::JBIG2MMRDecoder() {
+ str = NULL;
+ reset();
+}
+
+JBIG2MMRDecoder::~JBIG2MMRDecoder() {
+}
+
+void JBIG2MMRDecoder::reset() {
+ buf = 0;
+ bufLen = 0;
+ nBytesRead = 0;
+}
+
+int JBIG2MMRDecoder::get2DCode() {
+ const CCITTCode *p;
+
+ if (bufLen == 0) {
+ buf = str->getChar() & 0xff;
+ bufLen = 8;
+ ++nBytesRead;
+ p = &twoDimTab1[(buf >> 1) & 0x7f];
+ } else if (bufLen == 8) {
+ p = &twoDimTab1[(buf >> 1) & 0x7f];
+ } else {
+ p = &twoDimTab1[(buf << (7 - bufLen)) & 0x7f];
+ if (p->bits < 0 || p->bits > (int)bufLen) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bufLen += 8;
+ ++nBytesRead;
+ p = &twoDimTab1[(buf >> (bufLen - 7)) & 0x7f];
+ }
+ }
+ if (p->bits < 0) {
+ error(errSyntaxError, str->getPos(), "Bad two dim code in JBIG2 MMR stream");
+ return EOF;
+ }
+ bufLen -= p->bits;
+ return p->n;
+}
+
+int JBIG2MMRDecoder::getWhiteCode() {
+ const CCITTCode *p;
+ Guint code;
+
+ if (bufLen == 0) {
+ buf = str->getChar() & 0xff;
+ bufLen = 8;
+ ++nBytesRead;
+ }
+ while (1) {
+ if (bufLen >= 11 && ((buf >> (bufLen - 7)) & 0x7f) == 0) {
+ if (bufLen <= 12) {
+ code = buf << (12 - bufLen);
+ } else {
+ code = buf >> (bufLen - 12);
+ }
+ p = &whiteTab1[code & 0x1f];
+ } else {
+ if (bufLen <= 9) {
+ code = buf << (9 - bufLen);
+ } else {
+ code = buf >> (bufLen - 9);
+ }
+ p = &whiteTab2[code & 0x1ff];
+ }
+ if (p->bits > 0 && p->bits <= (int)bufLen) {
+ bufLen -= p->bits;
+ return p->n;
+ }
+ if (bufLen >= 12) {
+ break;
+ }
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bufLen += 8;
+ ++nBytesRead;
+ }
+ error(errSyntaxError, str->getPos(), "Bad white code in JBIG2 MMR stream");
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ --bufLen;
+ return 1;
+}
+
+int JBIG2MMRDecoder::getBlackCode() {
+ const CCITTCode *p;
+ Guint code;
+
+ if (bufLen == 0) {
+ buf = str->getChar() & 0xff;
+ bufLen = 8;
+ ++nBytesRead;
+ }
+ while (1) {
+ if (bufLen >= 10 && ((buf >> (bufLen - 6)) & 0x3f) == 0) {
+ if (bufLen <= 13) {
+ code = buf << (13 - bufLen);
+ } else {
+ code = buf >> (bufLen - 13);
+ }
+ p = &blackTab1[code & 0x7f];
+ } else if (bufLen >= 7 && ((buf >> (bufLen - 4)) & 0x0f) == 0 &&
+ ((buf >> (bufLen - 6)) & 0x03) != 0) {
+ if (bufLen <= 12) {
+ code = buf << (12 - bufLen);
+ } else {
+ code = buf >> (bufLen - 12);
+ }
+ if (unlikely((code & 0xff) < 64)) {
+ break;
+ }
+ p = &blackTab2[(code & 0xff) - 64];
+ } else {
+ if (bufLen <= 6) {
+ code = buf << (6 - bufLen);
+ } else {
+ code = buf >> (bufLen - 6);
+ }
+ p = &blackTab3[code & 0x3f];
+ }
+ if (p->bits > 0 && p->bits <= (int)bufLen) {
+ bufLen -= p->bits;
+ return p->n;
+ }
+ if (bufLen >= 13) {
+ break;
+ }
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bufLen += 8;
+ ++nBytesRead;
+ }
+ error(errSyntaxError, str->getPos(), "Bad black code in JBIG2 MMR stream");
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ --bufLen;
+ return 1;
+}
+
+Guint JBIG2MMRDecoder::get24Bits() {
+ while (bufLen < 24) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bufLen += 8;
+ ++nBytesRead;
+ }
+ return (buf >> (bufLen - 24)) & 0xffffff;
+}
+
+void JBIG2MMRDecoder::skipTo(Guint length) {
+ while (nBytesRead < length) {
+ str->getChar();
+ ++nBytesRead;
+ }
+}
+
+//------------------------------------------------------------------------
+// JBIG2Segment
+//------------------------------------------------------------------------
+
+enum JBIG2SegmentType {
+ jbig2SegBitmap,
+ jbig2SegSymbolDict,
+ jbig2SegPatternDict,
+ jbig2SegCodeTable
+};
+
+class JBIG2Segment {
+public:
+
+ JBIG2Segment(Guint segNumA) { segNum = segNumA; }
+ virtual ~JBIG2Segment() {}
+ void setSegNum(Guint segNumA) { segNum = segNumA; }
+ Guint getSegNum() { return segNum; }
+ virtual JBIG2SegmentType getType() = 0;
+
+private:
+
+ Guint segNum;
+};
+
+//------------------------------------------------------------------------
+// JBIG2Bitmap
+//------------------------------------------------------------------------
+
+struct JBIG2BitmapPtr {
+ Guchar *p;
+ int shift;
+ int x;
+};
+
+class JBIG2Bitmap: public JBIG2Segment {
+public:
+
+ JBIG2Bitmap(Guint segNumA, int wA, int hA);
+ virtual ~JBIG2Bitmap();
+ virtual JBIG2SegmentType getType() { return jbig2SegBitmap; }
+ JBIG2Bitmap *copy() { return new JBIG2Bitmap(0, this); }
+ JBIG2Bitmap *getSlice(Guint x, Guint y, Guint wA, Guint hA);
+ void expand(int newH, Guint pixel);
+ void clearToZero();
+ void clearToOne();
+ int getWidth() { return w; }
+ int getHeight() { return h; }
+ int getLineSize() { return line; }
+ int getPixel(int x, int y)
+ { return (x < 0 || x >= w || y < 0 || y >= h) ? 0 :
+ (data[y * line + (x >> 3)] >> (7 - (x & 7))) & 1; }
+ void setPixel(int x, int y)
+ { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); }
+ void clearPixel(int x, int y)
+ { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); }
+ void getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr);
+ int nextPixel(JBIG2BitmapPtr *ptr);
+ void duplicateRow(int yDest, int ySrc);
+ void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp);
+ Guchar *getDataPtr() { return data; }
+ int getDataSize() { return h * line; }
+ GBool isOk() { return data != NULL; }
+
+private:
+
+ JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap);
+
+ int w, h, line;
+ Guchar *data;
+};
+
+JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA):
+ JBIG2Segment(segNumA)
+{
+ w = wA;
+ h = hA;
+ line = (wA + 7) >> 3;
+
+ if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) {
+ error(errSyntaxError, -1, "invalid width/height");
+ data = NULL;
+ return;
+ }
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)gmalloc_checkoverflow(h * line + 1);
+ if (data != NULL) {
+ data[h * line] = 0;
+ }
+}
+
+JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap):
+ JBIG2Segment(segNumA)
+{
+ if (unlikely(bitmap == NULL)) {
+ error(errSyntaxError, -1, "NULL bitmap in JBIG2Bitmap");
+ w = h = line = 0;
+ data = NULL;
+ return;
+ }
+
+ w = bitmap->w;
+ h = bitmap->h;
+ line = bitmap->line;
+
+ if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) {
+ error(errSyntaxError, -1, "invalid width/height");
+ data = NULL;
+ return;
+ }
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)gmalloc(h * line + 1);
+ memcpy(data, bitmap->data, h * line);
+ data[h * line] = 0;
+}
+
+JBIG2Bitmap::~JBIG2Bitmap() {
+ gfree(data);
+}
+
+//~ optimize this
+JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) {
+ JBIG2Bitmap *slice;
+ Guint xx, yy;
+
+ slice = new JBIG2Bitmap(0, wA, hA);
+ if (slice->isOk()) {
+ slice->clearToZero();
+ for (yy = 0; yy < hA; ++yy) {
+ for (xx = 0; xx < wA; ++xx) {
+ if (getPixel(x + xx, y + yy)) {
+ slice->setPixel(xx, yy);
+ }
+ }
+ }
+ } else {
+ delete slice;
+ slice = NULL;
+ }
+ return slice;
+}
+
+void JBIG2Bitmap::expand(int newH, Guint pixel) {
+ if (newH <= h || line <= 0 || newH >= (INT_MAX - 1) / line) {
+ error(errSyntaxError, -1, "invalid width/height");
+ gfree(data);
+ data = NULL;
+ return;
+ }
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)grealloc(data, newH * line + 1);
+ if (pixel) {
+ memset(data + h * line, 0xff, (newH - h) * line);
+ } else {
+ memset(data + h * line, 0x00, (newH - h) * line);
+ }
+ h = newH;
+ data[h * line] = 0;
+}
+
+void JBIG2Bitmap::clearToZero() {
+ memset(data, 0, h * line);
+}
+
+void JBIG2Bitmap::clearToOne() {
+ memset(data, 0xff, h * line);
+}
+
+inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) {
+ if (y < 0 || y >= h || x >= w) {
+ ptr->p = NULL;
+ ptr->shift = 0; // make gcc happy
+ ptr->x = 0; // make gcc happy
+ } else if (x < 0) {
+ ptr->p = &data[y * line];
+ ptr->shift = 7;
+ ptr->x = x;
+ } else {
+ ptr->p = &data[y * line + (x >> 3)];
+ ptr->shift = 7 - (x & 7);
+ ptr->x = x;
+ }
+}
+
+inline int JBIG2Bitmap::nextPixel(JBIG2BitmapPtr *ptr) {
+ int pix;
+
+ if (!ptr->p) {
+ pix = 0;
+ } else if (ptr->x < 0) {
+ ++ptr->x;
+ pix = 0;
+ } else {
+ pix = (*ptr->p >> ptr->shift) & 1;
+ if (++ptr->x == w) {
+ ptr->p = NULL;
+ } else if (ptr->shift == 0) {
+ ++ptr->p;
+ ptr->shift = 7;
+ } else {
+ --ptr->shift;
+ }
+ }
+ return pix;
+}
+
+void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) {
+ memcpy(data + yDest * line, data + ySrc * line, line);
+}
+
+void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y,
+ Guint combOp) {
+ int x0, x1, y0, y1, xx, yy;
+ Guchar *srcPtr, *destPtr;
+ Guint src0, src1, src, dest, s1, s2, m1, m2, m3;
+ GBool oneByte;
+
+ // check for the pathological case where y = -2^31
+ if (y < -0x7fffffff) {
+ return;
+ }
+ if (y < 0) {
+ y0 = -y;
+ } else {
+ y0 = 0;
+ }
+ if (y + bitmap->h > h) {
+ y1 = h - y;
+ } else {
+ y1 = bitmap->h;
+ }
+ if (y0 >= y1) {
+ return;
+ }
+
+ if (x >= 0) {
+ x0 = x & ~7;
+ } else {
+ x0 = 0;
+ }
+ x1 = x + bitmap->w;
+ if (x1 > w) {
+ x1 = w;
+ }
+ if (x0 >= x1) {
+ return;
+ }
+
+ s1 = x & 7;
+ s2 = 8 - s1;
+ m1 = 0xff >> (x1 & 7);
+ m2 = 0xff << (((x1 & 7) == 0) ? 0 : 8 - (x1 & 7));
+ m3 = (0xff >> s1) & m2;
+
+ oneByte = x0 == ((x1 - 1) & ~7);
+
+ for (yy = y0; yy < y1; ++yy) {
+
+ // one byte per line -- need to mask both left and right side
+ if (oneByte) {
+ if (x >= 0) {
+ destPtr = data + (y + yy) * line + (x >> 3);
+ srcPtr = bitmap->data + yy * bitmap->line;
+ dest = *destPtr;
+ src1 = *srcPtr;
+ switch (combOp) {
+ case 0: // or
+ dest |= (src1 >> s1) & m2;
+ break;
+ case 1: // and
+ dest &= ((0xff00 | src1) >> s1) | m1;
+ break;
+ case 2: // xor
+ dest ^= (src1 >> s1) & m2;
+ break;
+ case 3: // xnor
+ dest ^= ((src1 ^ 0xff) >> s1) & m2;
+ break;
+ case 4: // replace
+ dest = (dest & ~m3) | ((src1 >> s1) & m3);
+ break;
+ }
+ *destPtr = dest;
+ } else {
+ destPtr = data + (y + yy) * line;
+ srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3);
+ dest = *destPtr;
+ src1 = *srcPtr;
+ switch (combOp) {
+ case 0: // or
+ dest |= src1 & m2;
+ break;
+ case 1: // and
+ dest &= src1 | m1;
+ break;
+ case 2: // xor
+ dest ^= src1 & m2;
+ break;
+ case 3: // xnor
+ dest ^= (src1 ^ 0xff) & m2;
+ break;
+ case 4: // replace
+ dest = (src1 & m2) | (dest & m1);
+ break;
+ }
+ *destPtr = dest;
+ }
+
+ // multiple bytes per line -- need to mask left side of left-most
+ // byte and right side of right-most byte
+ } else {
+
+ // left-most byte
+ if (x >= 0) {
+ destPtr = data + (y + yy) * line + (x >> 3);
+ srcPtr = bitmap->data + yy * bitmap->line;
+ src1 = *srcPtr++;
+ dest = *destPtr;
+ switch (combOp) {
+ case 0: // or
+ dest |= src1 >> s1;
+ break;
+ case 1: // and
+ dest &= (0xff00 | src1) >> s1;
+ break;
+ case 2: // xor
+ dest ^= src1 >> s1;
+ break;
+ case 3: // xnor
+ dest ^= (src1 ^ 0xff) >> s1;
+ break;
+ case 4: // replace
+ dest = (dest & (0xff << s2)) | (src1 >> s1);
+ break;
+ }
+ *destPtr++ = dest;
+ xx = x0 + 8;
+ } else {
+ destPtr = data + (y + yy) * line;
+ srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3);
+ src1 = *srcPtr++;
+ xx = x0;
+ }
+
+ // middle bytes
+ for (; xx < x1 - 8; xx += 8) {
+ dest = *destPtr;
+ src0 = src1;
+ src1 = *srcPtr++;
+ src = (((src0 << 8) | src1) >> s1) & 0xff;
+ switch (combOp) {
+ case 0: // or
+ dest |= src;
+ break;
+ case 1: // and
+ dest &= src;
+ break;
+ case 2: // xor
+ dest ^= src;
+ break;
+ case 3: // xnor
+ dest ^= src ^ 0xff;
+ break;
+ case 4: // replace
+ dest = src;
+ break;
+ }
+ *destPtr++ = dest;
+ }
+
+ // right-most byte
+ // note: this last byte (src1) may not actually be used, depending
+ // on the values of s1, m1, and m2 - and in fact, it may be off
+ // the edge of the source bitmap, which means we need to allocate
+ // one extra guard byte at the end of each bitmap
+ dest = *destPtr;
+ src0 = src1;
+ src1 = *srcPtr++;
+ src = (((src0 << 8) | src1) >> s1) & 0xff;
+ switch (combOp) {
+ case 0: // or
+ dest |= src & m2;
+ break;
+ case 1: // and
+ dest &= src | m1;
+ break;
+ case 2: // xor
+ dest ^= src & m2;
+ break;
+ case 3: // xnor
+ dest ^= (src ^ 0xff) & m2;
+ break;
+ case 4: // replace
+ dest = (src & m2) | (dest & m1);
+ break;
+ }
+ *destPtr = dest;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// JBIG2SymbolDict
+//------------------------------------------------------------------------
+
+class JBIG2SymbolDict: public JBIG2Segment {
+public:
+
+ JBIG2SymbolDict(Guint segNumA, Guint sizeA);
+ virtual ~JBIG2SymbolDict();
+ virtual JBIG2SegmentType getType() { return jbig2SegSymbolDict; }
+ Guint getSize() { return size; }
+ void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; }
+ JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; }
+ GBool isOk() { return bitmaps != NULL; }
+ void setGenericRegionStats(JArithmeticDecoderStats *stats)
+ { genericRegionStats = stats; }
+ void setRefinementRegionStats(JArithmeticDecoderStats *stats)
+ { refinementRegionStats = stats; }
+ JArithmeticDecoderStats *getGenericRegionStats()
+ { return genericRegionStats; }
+ JArithmeticDecoderStats *getRefinementRegionStats()
+ { return refinementRegionStats; }
+
+private:
+
+ Guint size;
+ JBIG2Bitmap **bitmaps;
+ JArithmeticDecoderStats *genericRegionStats;
+ JArithmeticDecoderStats *refinementRegionStats;
+};
+
+JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA):
+ JBIG2Segment(segNumA)
+{
+ Guint i;
+
+ size = sizeA;
+ bitmaps = (JBIG2Bitmap **)gmallocn_checkoverflow(size, sizeof(JBIG2Bitmap *));
+ if (!bitmaps) size = 0;
+ for (i = 0; i < size; ++i) {
+ bitmaps[i] = NULL;
+ }
+ genericRegionStats = NULL;
+ refinementRegionStats = NULL;
+}
+
+JBIG2SymbolDict::~JBIG2SymbolDict() {
+ Guint i;
+
+ for (i = 0; i < size; ++i) {
+ delete bitmaps[i];
+ }
+ gfree(bitmaps);
+ if (genericRegionStats) {
+ delete genericRegionStats;
+ }
+ if (refinementRegionStats) {
+ delete refinementRegionStats;
+ }
+}
+
+//------------------------------------------------------------------------
+// JBIG2PatternDict
+//------------------------------------------------------------------------
+
+class JBIG2PatternDict: public JBIG2Segment {
+public:
+
+ JBIG2PatternDict(Guint segNumA, Guint sizeA);
+ virtual ~JBIG2PatternDict();
+ virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; }
+ Guint getSize() { return size; }
+ void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { if (likely(idx < size)) bitmaps[idx] = bitmap; }
+ JBIG2Bitmap *getBitmap(Guint idx) { return (idx < size) ? bitmaps[idx] : NULL; }
+
+private:
+
+ Guint size;
+ JBIG2Bitmap **bitmaps;
+};
+
+JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA):
+ JBIG2Segment(segNumA)
+{
+ bitmaps = (JBIG2Bitmap **)gmallocn_checkoverflow(sizeA, sizeof(JBIG2Bitmap *));
+ if (bitmaps) {
+ size = sizeA;
+ } else {
+ size = 0;
+ error(errSyntaxError, -1, "JBIG2PatternDict: can't allocate bitmaps");
+ }
+}
+
+JBIG2PatternDict::~JBIG2PatternDict() {
+ Guint i;
+
+ for (i = 0; i < size; ++i) {
+ delete bitmaps[i];
+ }
+ gfree(bitmaps);
+}
+
+//------------------------------------------------------------------------
+// JBIG2CodeTable
+//------------------------------------------------------------------------
+
+class JBIG2CodeTable: public JBIG2Segment {
+public:
+
+ JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA);
+ virtual ~JBIG2CodeTable();
+ virtual JBIG2SegmentType getType() { return jbig2SegCodeTable; }
+ JBIG2HuffmanTable *getHuffTable() { return table; }
+
+private:
+
+ JBIG2HuffmanTable *table;
+};
+
+JBIG2CodeTable::JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA):
+ JBIG2Segment(segNumA)
+{
+ table = tableA;
+}
+
+JBIG2CodeTable::~JBIG2CodeTable() {
+ gfree(table);
+}
+
+//------------------------------------------------------------------------
+// JBIG2Stream
+//------------------------------------------------------------------------
+
+JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA, Object *globalsStreamRefA):
+ FilterStream(strA)
+{
+ pageBitmap = NULL;
+
+ arithDecoder = new JArithmeticDecoder();
+ genericRegionStats = new JArithmeticDecoderStats(1 << 1);
+ refinementRegionStats = new JArithmeticDecoderStats(1 << 1);
+ iadhStats = new JArithmeticDecoderStats(1 << 9);
+ iadwStats = new JArithmeticDecoderStats(1 << 9);
+ iaexStats = new JArithmeticDecoderStats(1 << 9);
+ iaaiStats = new JArithmeticDecoderStats(1 << 9);
+ iadtStats = new JArithmeticDecoderStats(1 << 9);
+ iaitStats = new JArithmeticDecoderStats(1 << 9);
+ iafsStats = new JArithmeticDecoderStats(1 << 9);
+ iadsStats = new JArithmeticDecoderStats(1 << 9);
+ iardxStats = new JArithmeticDecoderStats(1 << 9);
+ iardyStats = new JArithmeticDecoderStats(1 << 9);
+ iardwStats = new JArithmeticDecoderStats(1 << 9);
+ iardhStats = new JArithmeticDecoderStats(1 << 9);
+ iariStats = new JArithmeticDecoderStats(1 << 9);
+ iaidStats = new JArithmeticDecoderStats(1 << 1);
+ huffDecoder = new JBIG2HuffmanDecoder();
+ mmrDecoder = new JBIG2MMRDecoder();
+
+ if (globalsStreamA->isStream()) {
+ globalsStreamA->copy(&globalsStream);
+ if (globalsStreamRefA->isRef())
+ globalsStreamRef = globalsStreamRefA->getRef();
+ }
+
+ segments = globalSegments = NULL;
+ curStr = NULL;
+ dataPtr = dataEnd = NULL;
+}
+
+JBIG2Stream::~JBIG2Stream() {
+ close();
+ globalsStream.free();
+ delete arithDecoder;
+ delete genericRegionStats;
+ delete refinementRegionStats;
+ delete iadhStats;
+ delete iadwStats;
+ delete iaexStats;
+ delete iaaiStats;
+ delete iadtStats;
+ delete iaitStats;
+ delete iafsStats;
+ delete iadsStats;
+ delete iardxStats;
+ delete iardyStats;
+ delete iardwStats;
+ delete iardhStats;
+ delete iariStats;
+ delete iaidStats;
+ delete huffDecoder;
+ delete mmrDecoder;
+ delete str;
+}
+
+void JBIG2Stream::reset() {
+ // read the globals stream
+ globalSegments = new GooList();
+ if (globalsStream.isStream()) {
+ segments = globalSegments;
+ curStr = globalsStream.getStream();
+ curStr->reset();
+ arithDecoder->setStream(curStr);
+ huffDecoder->setStream(curStr);
+ mmrDecoder->setStream(curStr);
+ readSegments();
+ curStr->close();
+ }
+
+ // read the main stream
+ segments = new GooList();
+ curStr = str;
+ curStr->reset();
+ arithDecoder->setStream(curStr);
+ huffDecoder->setStream(curStr);
+ mmrDecoder->setStream(curStr);
+ readSegments();
+
+ if (pageBitmap) {
+ dataPtr = pageBitmap->getDataPtr();
+ dataEnd = dataPtr + pageBitmap->getDataSize();
+ } else {
+ dataPtr = dataEnd = NULL;
+ }
+}
+
+void JBIG2Stream::close() {
+ if (pageBitmap) {
+ delete pageBitmap;
+ pageBitmap = NULL;
+ }
+ if (segments) {
+ deleteGooList(segments, JBIG2Segment);
+ segments = NULL;
+ }
+ if (globalSegments) {
+ deleteGooList(globalSegments, JBIG2Segment);
+ globalSegments = NULL;
+ }
+ dataPtr = dataEnd = NULL;
+ FilterStream::close();
+}
+
+int JBIG2Stream::getChar() {
+ if (dataPtr && dataPtr < dataEnd) {
+ return (*dataPtr++ ^ 0xff) & 0xff;
+ }
+ return EOF;
+}
+
+int JBIG2Stream::lookChar() {
+ if (dataPtr && dataPtr < dataEnd) {
+ return (*dataPtr ^ 0xff) & 0xff;
+ }
+ return EOF;
+}
+
+Goffset JBIG2Stream::getPos() {
+ if (pageBitmap == NULL) {
+ return 0;
+ }
+ return dataPtr - pageBitmap->getDataPtr();
+}
+
+int JBIG2Stream::getChars(int nChars, Guchar *buffer) {
+ int n, i;
+
+ if (nChars <= 0) {
+ return 0;
+ }
+ if (dataEnd - dataPtr < nChars) {
+ n = (int)(dataEnd - dataPtr);
+ } else {
+ n = nChars;
+ }
+ for (i = 0; i < n; ++i) {
+ buffer[i] = *dataPtr++ ^ 0xff;
+ }
+ return n;
+}
+
+GooString *JBIG2Stream::getPSFilter(int psLevel, const char *indent) {
+ return NULL;
+}
+
+GBool JBIG2Stream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+void JBIG2Stream::readSegments() {
+ Guint segNum, segFlags, segType, page, segLength;
+ Guint refFlags, nRefSegs;
+ Guint *refSegs;
+ Goffset segDataPos;
+ int c1, c2, c3;
+ Guint i;
+
+ while (readULong(&segNum)) {
+
+ // segment header flags
+ if (!readUByte(&segFlags)) {
+ goto eofError1;
+ }
+ segType = segFlags & 0x3f;
+
+ // referred-to segment count and retention flags
+ if (!readUByte(&refFlags)) {
+ goto eofError1;
+ }
+ nRefSegs = refFlags >> 5;
+ if (nRefSegs == 7) {
+ if ((c1 = curStr->getChar()) == EOF ||
+ (c2 = curStr->getChar()) == EOF ||
+ (c3 = curStr->getChar()) == EOF) {
+ goto eofError1;
+ }
+ refFlags = (refFlags << 24) | (c1 << 16) | (c2 << 8) | c3;
+ nRefSegs = refFlags & 0x1fffffff;
+ for (i = 0; i < (nRefSegs + 9) >> 3; ++i) {
+ if ((c1 = curStr->getChar()) == EOF) {
+ goto eofError1;
+ }
+ }
+ }
+
+ // referred-to segment numbers
+ refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint));
+ if (segNum <= 256) {
+ for (i = 0; i < nRefSegs; ++i) {
+ if (!readUByte(&refSegs[i])) {
+ goto eofError2;
+ }
+ }
+ } else if (segNum <= 65536) {
+ for (i = 0; i < nRefSegs; ++i) {
+ if (!readUWord(&refSegs[i])) {
+ goto eofError2;
+ }
+ }
+ } else {
+ for (i = 0; i < nRefSegs; ++i) {
+ if (!readULong(&refSegs[i])) {
+ goto eofError2;
+ }
+ }
+ }
+
+ // segment page association
+ if (segFlags & 0x40) {
+ if (!readULong(&page)) {
+ goto eofError2;
+ }
+ } else {
+ if (!readUByte(&page)) {
+ goto eofError2;
+ }
+ }
+
+ // segment data length
+ if (!readULong(&segLength)) {
+ goto eofError2;
+ }
+
+ // keep track of the start of the segment data
+ segDataPos = curStr->getPos();
+
+ // check for missing page information segment
+ if (!pageBitmap && ((segType >= 4 && segType <= 7) ||
+ (segType >= 20 && segType <= 43))) {
+ error(errSyntaxError, curStr->getPos(), "First JBIG2 segment associated with a page must be a page information segment");
+ goto syntaxError;
+ }
+
+ // read the segment data
+ switch (segType) {
+ case 0:
+ if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) {
+ goto syntaxError;
+ }
+ break;
+ case 4:
+ readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs);
+ break;
+ case 6:
+ readTextRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs);
+ break;
+ case 7:
+ readTextRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs);
+ break;
+ case 16:
+ readPatternDictSeg(segNum, segLength);
+ break;
+ case 20:
+ readHalftoneRegionSeg(segNum, gFalse, gFalse, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 22:
+ readHalftoneRegionSeg(segNum, gTrue, gFalse, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 23:
+ readHalftoneRegionSeg(segNum, gTrue, gTrue, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 36:
+ readGenericRegionSeg(segNum, gFalse, gFalse, segLength);
+ break;
+ case 38:
+ readGenericRegionSeg(segNum, gTrue, gFalse, segLength);
+ break;
+ case 39:
+ readGenericRegionSeg(segNum, gTrue, gTrue, segLength);
+ break;
+ case 40:
+ readGenericRefinementRegionSeg(segNum, gFalse, gFalse, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 42:
+ readGenericRefinementRegionSeg(segNum, gTrue, gFalse, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 43:
+ readGenericRefinementRegionSeg(segNum, gTrue, gTrue, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 48:
+ readPageInfoSeg(segLength);
+ break;
+ case 50:
+ readEndOfStripeSeg(segLength);
+ break;
+ case 52:
+ readProfilesSeg(segLength);
+ break;
+ case 53:
+ readCodeTableSeg(segNum, segLength);
+ break;
+ case 62:
+ readExtensionSeg(segLength);
+ break;
+ default:
+ error(errSyntaxError, curStr->getPos(), "Unknown segment type in JBIG2 stream");
+ for (i = 0; i < segLength; ++i) {
+ if ((c1 = curStr->getChar()) == EOF) {
+ goto eofError2;
+ }
+ }
+ break;
+ }
+
+ // Make sure the segment handler read all of the bytes in the
+ // segment data, unless this segment is marked as having an
+ // unknown length (section 7.2.7 of the JBIG2 Final Committee Draft)
+
+ if (segLength != 0xffffffff) {
+
+ Goffset segExtraBytes = segDataPos + segLength - curStr->getPos();
+ if (segExtraBytes > 0) {
+
+ // If we didn't read all of the bytes in the segment data,
+ // indicate an error, and throw away the rest of the data.
+
+ // v.3.1.01.13 of the LuraTech PDF Compressor Server will
+ // sometimes generate an extraneous NULL byte at the end of
+ // arithmetic-coded symbol dictionary segments when numNewSyms
+ // == 0. Segments like this often occur for blank pages.
+
+ error(errSyntaxError, curStr->getPos(), "{0:lld} extraneous byte{1:s} after segment",
+ segExtraBytes, (segExtraBytes > 1) ? "s" : "");
+
+ // Burn through the remaining bytes -- inefficient, but
+ // hopefully we're not doing this much
+
+ int trash;
+ for (Goffset i = segExtraBytes; i > 0; i--) {
+ readByte(&trash);
+ }
+
+ } else if (segExtraBytes < 0) {
+
+ // If we read more bytes than we should have, according to the
+ // segment length field, note an error.
+
+ error(errSyntaxError, curStr->getPos(), "Previous segment handler read too many bytes");
+
+ }
+
+ }
+
+ gfree(refSegs);
+ }
+
+ return;
+
+ syntaxError:
+ gfree(refSegs);
+ return;
+
+ eofError2:
+ gfree(refSegs);
+ eofError1:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
+ Guint *refSegs, Guint nRefSegs) {
+ JBIG2SymbolDict *symbolDict;
+ JBIG2HuffmanTable *huffDHTable, *huffDWTable;
+ JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable;
+ JBIG2Segment *seg;
+ GooList *codeTables;
+ JBIG2SymbolDict *inputSymbolDict;
+ Guint flags, sdTemplate, sdrTemplate, huff, refAgg;
+ Guint huffDH, huffDW, huffBMSize, huffAggInst;
+ Guint contextUsed, contextRetained;
+ int sdATX[4], sdATY[4], sdrATX[2], sdrATY[2];
+ Guint numExSyms, numNewSyms, numInputSyms, symCodeLen;
+ JBIG2Bitmap **bitmaps;
+ JBIG2Bitmap *collBitmap, *refBitmap;
+ Guint *symWidths;
+ Guint symHeight, symWidth, totalWidth, x, symID;
+ int dh, dw, refAggNum, refDX, refDY, bmSize;
+ GBool ex;
+ int run, cnt, c;
+ Guint i, j, k;
+ Guchar *p;
+
+ symWidths = NULL;
+
+ // symbol dictionary flags
+ if (!readUWord(&flags)) {
+ goto eofError;
+ }
+ sdTemplate = (flags >> 10) & 3;
+ sdrTemplate = (flags >> 12) & 1;
+ huff = flags & 1;
+ refAgg = (flags >> 1) & 1;
+ huffDH = (flags >> 2) & 3;
+ huffDW = (flags >> 4) & 3;
+ huffBMSize = (flags >> 6) & 1;
+ huffAggInst = (flags >> 7) & 1;
+ contextUsed = (flags >> 8) & 1;
+ contextRetained = (flags >> 9) & 1;
+
+ // symbol dictionary AT flags
+ if (!huff) {
+ if (sdTemplate == 0) {
+ if (!readByte(&sdATX[0]) ||
+ !readByte(&sdATY[0]) ||
+ !readByte(&sdATX[1]) ||
+ !readByte(&sdATY[1]) ||
+ !readByte(&sdATX[2]) ||
+ !readByte(&sdATY[2]) ||
+ !readByte(&sdATX[3]) ||
+ !readByte(&sdATY[3])) {
+ goto eofError;
+ }
+ } else {
+ if (!readByte(&sdATX[0]) ||
+ !readByte(&sdATY[0])) {
+ goto eofError;
+ }
+ }
+ }
+
+ // symbol dictionary refinement AT flags
+ if (refAgg && !sdrTemplate) {
+ if (!readByte(&sdrATX[0]) ||
+ !readByte(&sdrATY[0]) ||
+ !readByte(&sdrATX[1]) ||
+ !readByte(&sdrATY[1])) {
+ goto eofError;
+ }
+ }
+
+ // SDNUMEXSYMS and SDNUMNEWSYMS
+ if (!readULong(&numExSyms) || !readULong(&numNewSyms)) {
+ goto eofError;
+ }
+
+ // get referenced segments: input symbol dictionaries and code tables
+ codeTables = new GooList();
+ numInputSyms = 0;
+ for (i = 0; i < nRefSegs; ++i) {
+ // This is need by bug 12014, returning gFalse makes it not crash
+ // but we end up with a empty page while acroread is able to render
+ // part of it
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ j = ((JBIG2SymbolDict *)seg)->getSize();
+ if (numInputSyms > UINT_MAX - j) {
+ error(errSyntaxError, curStr->getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+ delete codeTables;
+ goto eofError;
+ }
+ numInputSyms += j;
+ } else if (seg->getType() == jbig2SegCodeTable) {
+ codeTables->append(seg);
+ }
+ } else {
+ delete codeTables;
+ return gFalse;
+ }
+ }
+ if (numInputSyms > UINT_MAX - numNewSyms) {
+ error(errSyntaxError, curStr->getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+ delete codeTables;
+ goto eofError;
+ }
+
+ // compute symbol code length, per 6.5.8.2.3
+ // symCodeLen = ceil( log2( numInputSyms + numNewSyms ) )
+ i = numInputSyms + numNewSyms;
+ if (i <= 1) {
+ symCodeLen = huff ? 1 : 0;
+ } else {
+ --i;
+ symCodeLen = 0;
+ // i = floor((numSyms-1) / 2^symCodeLen)
+ while (i > 0) {
+ ++symCodeLen;
+ i >>= 1;
+ }
+ }
+
+ // get the input symbol bitmaps
+ bitmaps = (JBIG2Bitmap **)gmallocn_checkoverflow(numInputSyms + numNewSyms,
+ sizeof(JBIG2Bitmap *));
+ if (!bitmaps && (numInputSyms + numNewSyms > 0)) {
+ error(errSyntaxError, curStr->getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+ delete codeTables;
+ goto eofError;
+ }
+ for (i = 0; i < numInputSyms + numNewSyms; ++i) {
+ bitmaps[i] = NULL;
+ }
+ k = 0;
+ inputSymbolDict = NULL;
+ for (i = 0; i < nRefSegs; ++i) {
+ seg = findSegment(refSegs[i]);
+ if (seg != NULL && seg->getType() == jbig2SegSymbolDict) {
+ inputSymbolDict = (JBIG2SymbolDict *)seg;
+ for (j = 0; j < inputSymbolDict->getSize(); ++j) {
+ bitmaps[k++] = inputSymbolDict->getBitmap(j);
+ }
+ }
+ }
+
+ // get the Huffman tables
+ huffDHTable = huffDWTable = NULL; // make gcc happy
+ huffBMSizeTable = huffAggInstTable = NULL; // make gcc happy
+ i = 0;
+ if (huff) {
+ if (huffDH == 0) {
+ huffDHTable = huffTableD;
+ } else if (huffDH == 1) {
+ huffDHTable = huffTableE;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffDW == 0) {
+ huffDWTable = huffTableB;
+ } else if (huffDW == 1) {
+ huffDWTable = huffTableC;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffBMSize == 0) {
+ huffBMSizeTable = huffTableA;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffBMSizeTable =
+ ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffAggInst == 0) {
+ huffAggInstTable = huffTableA;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffAggInstTable =
+ ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ }
+ delete codeTables;
+
+ // set up the Huffman decoder
+ if (huff) {
+ huffDecoder->reset();
+
+ // set up the arithmetic decoder
+ } else {
+ if (contextUsed && inputSymbolDict) {
+ resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats());
+ } else {
+ resetGenericStats(sdTemplate, NULL);
+ }
+ resetIntStats(symCodeLen);
+ arithDecoder->start();
+ }
+
+ // set up the arithmetic decoder for refinement/aggregation
+ if (refAgg) {
+ if (contextUsed && inputSymbolDict) {
+ resetRefinementStats(sdrTemplate,
+ inputSymbolDict->getRefinementRegionStats());
+ } else {
+ resetRefinementStats(sdrTemplate, NULL);
+ }
+ }
+
+ // allocate symbol widths storage
+ if (huff && !refAgg) {
+ symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint));
+ }
+
+ symHeight = 0;
+ i = 0;
+ while (i < numNewSyms) {
+
+ // read the height class delta height
+ if (huff) {
+ huffDecoder->decodeInt(&dh, huffDHTable);
+ } else {
+ arithDecoder->decodeInt(&dh, iadhStats);
+ }
+ if (dh < 0 && (Guint)-dh >= symHeight) {
+ error(errSyntaxError, curStr->getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+ symHeight += dh;
+ if (unlikely(symHeight > 0x40000000)) {
+ error(errSyntaxError, curStr->getPos(), "Bad height value in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+ symWidth = 0;
+ totalWidth = 0;
+ j = i;
+
+ // read the symbols in this height class
+ while (1) {
+
+ // read the delta width
+ if (huff) {
+ if (!huffDecoder->decodeInt(&dw, huffDWTable)) {
+ break;
+ }
+ } else {
+ if (!arithDecoder->decodeInt(&dw, iadwStats)) {
+ break;
+ }
+ }
+ if (dw < 0 && (Guint)-dw >= symWidth) {
+ error(errSyntaxError, curStr->getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+ symWidth += dw;
+ if (i >= numNewSyms) {
+ error(errSyntaxError, curStr->getPos(), "Too many symbols in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+
+ // using a collective bitmap, so don't read a bitmap here
+ if (huff && !refAgg) {
+ symWidths[i] = symWidth;
+ totalWidth += symWidth;
+
+ // refinement/aggregate coding
+ } else if (refAgg) {
+ if (huff) {
+ if (!huffDecoder->decodeInt(&refAggNum, huffAggInstTable)) {
+ break;
+ }
+ } else {
+ if (!arithDecoder->decodeInt(&refAggNum, iaaiStats)) {
+ break;
+ }
+ }
+#if 0 //~ This special case was added about a year before the final draft
+ //~ of the JBIG2 spec was released. I have encountered some old
+ //~ JBIG2 images that predate it.
+ if (0) {
+#else
+ if (refAggNum == 1) {
+#endif
+ if (huff) {
+ symID = huffDecoder->readBits(symCodeLen);
+ huffDecoder->decodeInt(&refDX, huffTableO);
+ huffDecoder->decodeInt(&refDY, huffTableO);
+ huffDecoder->decodeInt(&bmSize, huffTableA);
+ huffDecoder->reset();
+ arithDecoder->start();
+ } else {
+ symID = arithDecoder->decodeIAID(symCodeLen, iaidStats);
+ arithDecoder->decodeInt(&refDX, iardxStats);
+ arithDecoder->decodeInt(&refDY, iardyStats);
+ }
+ if (symID >= numInputSyms + i) {
+ error(errSyntaxError, curStr->getPos(), "Invalid symbol ID in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+ refBitmap = bitmaps[symID];
+ if (unlikely(refBitmap == NULL)) {
+ error(errSyntaxError, curStr->getPos(), "Invalid ref bitmap for symbol ID {0:ud} in JBIG2 symbol dictionary", symID);
+ goto syntaxError;
+ }
+ bitmaps[numInputSyms + i] =
+ readGenericRefinementRegion(symWidth, symHeight,
+ sdrTemplate, gFalse,
+ refBitmap, refDX, refDY,
+ sdrATX, sdrATY);
+ //~ do we need to use the bmSize value here (in Huffman mode)?
+ } else {
+ bitmaps[numInputSyms + i] =
+ readTextRegion(huff, gTrue, symWidth, symHeight,
+ refAggNum, 0, numInputSyms + i, NULL,
+ symCodeLen, bitmaps, 0, 0, 0, 1, 0,
+ huffTableF, huffTableH, huffTableK, huffTableO,
+ huffTableO, huffTableO, huffTableO, huffTableA,
+ sdrTemplate, sdrATX, sdrATY);
+ }
+
+ // non-ref/agg coding
+ } else {
+ bitmaps[numInputSyms + i] =
+ readGenericBitmap(gFalse, symWidth, symHeight,
+ sdTemplate, gFalse, gFalse, NULL,
+ sdATX, sdATY, 0);
+ }
+
+ ++i;
+ }
+
+ // read the collective bitmap
+ if (huff && !refAgg) {
+ huffDecoder->decodeInt(&bmSize, huffBMSizeTable);
+ huffDecoder->reset();
+ if (bmSize == 0) {
+ collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight);
+ bmSize = symHeight * ((totalWidth + 7) >> 3);
+ p = collBitmap->getDataPtr();
+ if (unlikely(p == NULL)) {
+ delete collBitmap;
+ goto syntaxError;
+ }
+ for (k = 0; k < (Guint)bmSize; ++k) {
+ if ((c = curStr->getChar()) == EOF) {
+ break;
+ }
+ *p++ = (Guchar)c;
+ }
+ } else {
+ collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight,
+ 0, gFalse, gFalse, NULL, NULL, NULL,
+ bmSize);
+ }
+ if (likely(collBitmap != NULL)) {
+ x = 0;
+ for (; j < i; ++j) {
+ bitmaps[numInputSyms + j] =
+ collBitmap->getSlice(x, 0, symWidths[j], symHeight);
+ x += symWidths[j];
+ }
+ delete collBitmap;
+ } else {
+ error(errSyntaxError, curStr->getPos(), "collBitmap was null");
+ goto syntaxError;
+ }
+ }
+ }
+
+ // create the symbol dict object
+ symbolDict = new JBIG2SymbolDict(segNum, numExSyms);
+ if (!symbolDict->isOk()) {
+ delete symbolDict;
+ goto syntaxError;
+ }
+
+ // exported symbol list
+ i = j = 0;
+ ex = gFalse;
+ while (i < numInputSyms + numNewSyms) {
+ if (huff) {
+ huffDecoder->decodeInt(&run, huffTableA);
+ } else {
+ arithDecoder->decodeInt(&run, iaexStats);
+ }
+ if (i + run > numInputSyms + numNewSyms ||
+ (ex && j + run > numExSyms)) {
+ error(errSyntaxError, curStr->getPos(), "Too many exported symbols in JBIG2 symbol dictionary");
+ for ( ; j < numExSyms; ++j) symbolDict->setBitmap(j, NULL);
+ delete symbolDict;
+ goto syntaxError;
+ }
+ if (ex) {
+ for (cnt = 0; cnt < run; ++cnt) {
+ symbolDict->setBitmap(j++, bitmaps[i++]->copy());
+ }
+ } else {
+ i += run;
+ }
+ ex = !ex;
+ }
+ if (j != numExSyms) {
+ error(errSyntaxError, curStr->getPos(), "Too few symbols in JBIG2 symbol dictionary");
+ for ( ; j < numExSyms; ++j) symbolDict->setBitmap(j, NULL);
+ delete symbolDict;
+ goto syntaxError;
+ }
+
+ for (i = 0; i < numNewSyms; ++i) {
+ delete bitmaps[numInputSyms + i];
+ }
+ gfree(bitmaps);
+ if (symWidths) {
+ gfree(symWidths);
+ }
+
+ // save the arithmetic decoder stats
+ if (!huff && contextRetained) {
+ symbolDict->setGenericRegionStats(genericRegionStats->copy());
+ if (refAgg) {
+ symbolDict->setRefinementRegionStats(refinementRegionStats->copy());
+ }
+ }
+
+ // store the new symbol dict
+ segments->append(symbolDict);
+
+ return gTrue;
+
+ codeTableError:
+ error(errSyntaxError, curStr->getPos(), "Missing code table in JBIG2 symbol dictionary");
+ delete codeTables;
+
+ syntaxError:
+ for (i = 0; i < numNewSyms; ++i) {
+ if (bitmaps[numInputSyms + i]) {
+ delete bitmaps[numInputSyms + i];
+ }
+ }
+ gfree(bitmaps);
+ if (symWidths) {
+ gfree(symWidths);
+ }
+ return gFalse;
+
+ eofError:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+ return gFalse;
+}
+
+void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs, Guint nRefSegs) {
+ JBIG2Bitmap *bitmap;
+ JBIG2HuffmanTable runLengthTab[36];
+ JBIG2HuffmanTable *symCodeTab;
+ JBIG2HuffmanTable *huffFSTable, *huffDSTable, *huffDTTable;
+ JBIG2HuffmanTable *huffRDWTable, *huffRDHTable;
+ JBIG2HuffmanTable *huffRDXTable, *huffRDYTable, *huffRSizeTable;
+ JBIG2Segment *seg;
+ GooList *codeTables;
+ JBIG2SymbolDict *symbolDict;
+ JBIG2Bitmap **syms;
+ Guint w, h, x, y, segInfoFlags, extCombOp;
+ Guint flags, huff, refine, logStrips, refCorner, transposed;
+ Guint combOp, defPixel, templ;
+ int sOffset;
+ Guint huffFlags, huffFS, huffDS, huffDT;
+ Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize;
+ Guint numInstances, numSyms, symCodeLen;
+ int atx[2], aty[2];
+ Guint i, k, kk;
+ int j;
+
+ // region segment info field
+ if (!readULong(&w) || !readULong(&h) ||
+ !readULong(&x) || !readULong(&y) ||
+ !readUByte(&segInfoFlags)) {
+ goto eofError;
+ }
+ extCombOp = segInfoFlags & 7;
+
+ // rest of the text region header
+ if (!readUWord(&flags)) {
+ goto eofError;
+ }
+ huff = flags & 1;
+ refine = (flags >> 1) & 1;
+ logStrips = (flags >> 2) & 3;
+ refCorner = (flags >> 4) & 3;
+ transposed = (flags >> 6) & 1;
+ combOp = (flags >> 7) & 3;
+ defPixel = (flags >> 9) & 1;
+ sOffset = (flags >> 10) & 0x1f;
+ if (sOffset & 0x10) {
+ sOffset |= -1 - 0x0f;
+ }
+ templ = (flags >> 15) & 1;
+ huffFS = huffDS = huffDT = 0; // make gcc happy
+ huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy
+ if (huff) {
+ if (!readUWord(&huffFlags)) {
+ goto eofError;
+ }
+ huffFS = huffFlags & 3;
+ huffDS = (huffFlags >> 2) & 3;
+ huffDT = (huffFlags >> 4) & 3;
+ huffRDW = (huffFlags >> 6) & 3;
+ huffRDH = (huffFlags >> 8) & 3;
+ huffRDX = (huffFlags >> 10) & 3;
+ huffRDY = (huffFlags >> 12) & 3;
+ huffRSize = (huffFlags >> 14) & 1;
+ }
+ if (refine && templ == 0) {
+ if (!readByte(&atx[0]) || !readByte(&aty[0]) ||
+ !readByte(&atx[1]) || !readByte(&aty[1])) {
+ goto eofError;
+ }
+ }
+ if (!readULong(&numInstances)) {
+ goto eofError;
+ }
+
+ // get symbol dictionaries and tables
+ codeTables = new GooList();
+ numSyms = 0;
+ for (i = 0; i < nRefSegs; ++i) {
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ numSyms += ((JBIG2SymbolDict *)seg)->getSize();
+ } else if (seg->getType() == jbig2SegCodeTable) {
+ codeTables->append(seg);
+ }
+ } else {
+ error(errSyntaxError, curStr->getPos(), "Invalid segment reference in JBIG2 text region");
+ delete codeTables;
+ return;
+ }
+ }
+ i = numSyms;
+ if (i <= 1) {
+ symCodeLen = huff ? 1 : 0;
+ } else {
+ --i;
+ symCodeLen = 0;
+ // i = floor((numSyms-1) / 2^symCodeLen)
+ while (i > 0) {
+ ++symCodeLen;
+ i >>= 1;
+ }
+ }
+
+ // get the symbol bitmaps
+ syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *));
+ kk = 0;
+ for (i = 0; i < nRefSegs; ++i) {
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ symbolDict = (JBIG2SymbolDict *)seg;
+ for (k = 0; k < symbolDict->getSize(); ++k) {
+ syms[kk++] = symbolDict->getBitmap(k);
+ }
+ }
+ }
+ }
+
+ // get the Huffman tables
+ huffFSTable = huffDSTable = huffDTTable = NULL; // make gcc happy
+ huffRDWTable = huffRDHTable = NULL; // make gcc happy
+ huffRDXTable = huffRDYTable = huffRSizeTable = NULL; // make gcc happy
+ i = 0;
+ if (huff) {
+ if (huffFS == 0) {
+ huffFSTable = huffTableF;
+ } else if (huffFS == 1) {
+ huffFSTable = huffTableG;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffFSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffDS == 0) {
+ huffDSTable = huffTableH;
+ } else if (huffDS == 1) {
+ huffDSTable = huffTableI;
+ } else if (huffDS == 2) {
+ huffDSTable = huffTableJ;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffDSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffDT == 0) {
+ huffDTTable = huffTableK;
+ } else if (huffDT == 1) {
+ huffDTTable = huffTableL;
+ } else if (huffDT == 2) {
+ huffDTTable = huffTableM;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffDTTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRDW == 0) {
+ huffRDWTable = huffTableN;
+ } else if (huffRDW == 1) {
+ huffRDWTable = huffTableO;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRDH == 0) {
+ huffRDHTable = huffTableN;
+ } else if (huffRDH == 1) {
+ huffRDHTable = huffTableO;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRDX == 0) {
+ huffRDXTable = huffTableN;
+ } else if (huffRDX == 1) {
+ huffRDXTable = huffTableO;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRDXTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRDY == 0) {
+ huffRDYTable = huffTableN;
+ } else if (huffRDY == 1) {
+ huffRDYTable = huffTableO;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRDYTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRSize == 0) {
+ huffRSizeTable = huffTableA;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRSizeTable =
+ ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ }
+ delete codeTables;
+
+ // symbol ID Huffman decoding table
+ if (huff) {
+ huffDecoder->reset();
+ for (i = 0; i < 32; ++i) {
+ runLengthTab[i].val = i;
+ runLengthTab[i].prefixLen = huffDecoder->readBits(4);
+ runLengthTab[i].rangeLen = 0;
+ }
+ runLengthTab[32].val = 0x103;
+ runLengthTab[32].prefixLen = huffDecoder->readBits(4);
+ runLengthTab[32].rangeLen = 2;
+ runLengthTab[33].val = 0x203;
+ runLengthTab[33].prefixLen = huffDecoder->readBits(4);
+ runLengthTab[33].rangeLen = 3;
+ runLengthTab[34].val = 0x20b;
+ runLengthTab[34].prefixLen = huffDecoder->readBits(4);
+ runLengthTab[34].rangeLen = 7;
+ runLengthTab[35].prefixLen = 0;
+ runLengthTab[35].rangeLen = jbig2HuffmanEOT;
+ huffDecoder->buildTable(runLengthTab, 35);
+ symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1,
+ sizeof(JBIG2HuffmanTable));
+ for (i = 0; i < numSyms; ++i) {
+ symCodeTab[i].val = i;
+ symCodeTab[i].rangeLen = 0;
+ }
+ i = 0;
+ while (i < numSyms) {
+ huffDecoder->decodeInt(&j, runLengthTab);
+ if (j > 0x200) {
+ for (j -= 0x200; j && i < numSyms; --j) {
+ symCodeTab[i++].prefixLen = 0;
+ }
+ } else if (j > 0x100) {
+ if (unlikely(i == 0)) ++i;
+ for (j -= 0x100; j && i < numSyms; --j) {
+ symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen;
+ ++i;
+ }
+ } else {
+ symCodeTab[i++].prefixLen = j;
+ }
+ }
+ symCodeTab[numSyms].prefixLen = 0;
+ symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT;
+ huffDecoder->buildTable(symCodeTab, numSyms);
+ huffDecoder->reset();
+
+ // set up the arithmetic decoder
+ } else {
+ symCodeTab = NULL;
+ resetIntStats(symCodeLen);
+ arithDecoder->start();
+ }
+ if (refine) {
+ resetRefinementStats(templ, NULL);
+ }
+
+ bitmap = readTextRegion(huff, refine, w, h, numInstances,
+ logStrips, numSyms, symCodeTab, symCodeLen, syms,
+ defPixel, combOp, transposed, refCorner, sOffset,
+ huffFSTable, huffDSTable, huffDTTable,
+ huffRDWTable, huffRDHTable,
+ huffRDXTable, huffRDYTable, huffRSizeTable,
+ templ, atx, aty);
+
+ gfree(syms);
+
+ if (bitmap) {
+ // combine the region bitmap into the page bitmap
+ if (imm) {
+ if (pageH == 0xffffffff && y + h > curPageH) {
+ pageBitmap->expand(y + h, pageDefPixel);
+ }
+ pageBitmap->combine(bitmap, x, y, extCombOp);
+ delete bitmap;
+
+ // store the region bitmap
+ } else {
+ bitmap->setSegNum(segNum);
+ segments->append(bitmap);
+ }
+ }
+
+ // clean up the Huffman decoder
+ if (huff) {
+ gfree(symCodeTab);
+ }
+
+ return;
+
+ codeTableError:
+ error(errSyntaxError, curStr->getPos(), "Missing code table in JBIG2 text region");
+ delete codeTables;
+ gfree(syms);
+ return;
+
+ eofError:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+ return;
+}
+
+JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
+ int w, int h,
+ Guint numInstances,
+ Guint logStrips,
+ int numSyms,
+ JBIG2HuffmanTable *symCodeTab,
+ Guint symCodeLen,
+ JBIG2Bitmap **syms,
+ Guint defPixel, Guint combOp,
+ Guint transposed, Guint refCorner,
+ int sOffset,
+ JBIG2HuffmanTable *huffFSTable,
+ JBIG2HuffmanTable *huffDSTable,
+ JBIG2HuffmanTable *huffDTTable,
+ JBIG2HuffmanTable *huffRDWTable,
+ JBIG2HuffmanTable *huffRDHTable,
+ JBIG2HuffmanTable *huffRDXTable,
+ JBIG2HuffmanTable *huffRDYTable,
+ JBIG2HuffmanTable *huffRSizeTable,
+ Guint templ,
+ int *atx, int *aty) {
+ JBIG2Bitmap *bitmap;
+ JBIG2Bitmap *symbolBitmap;
+ Guint strips;
+ int t, dt, tt, s, ds, sFirst, j;
+ int rdw, rdh, rdx, rdy, ri, refDX, refDY, bmSize;
+ Guint symID, inst, bw, bh;
+
+ strips = 1 << logStrips;
+
+ // allocate the bitmap
+ bitmap = new JBIG2Bitmap(0, w, h);
+ if (!bitmap->isOk()) {
+ delete bitmap;
+ return NULL;
+ }
+ if (defPixel) {
+ bitmap->clearToOne();
+ } else {
+ bitmap->clearToZero();
+ }
+
+ // decode initial T value
+ if (huff) {
+ huffDecoder->decodeInt(&t, huffDTTable);
+ } else {
+ arithDecoder->decodeInt(&t, iadtStats);
+ }
+ t *= -(int)strips;
+
+ inst = 0;
+ sFirst = 0;
+ while (inst < numInstances) {
+
+ // decode delta-T
+ if (huff) {
+ huffDecoder->decodeInt(&dt, huffDTTable);
+ } else {
+ arithDecoder->decodeInt(&dt, iadtStats);
+ }
+ t += dt * strips;
+
+ // first S value
+ if (huff) {
+ huffDecoder->decodeInt(&ds, huffFSTable);
+ } else {
+ arithDecoder->decodeInt(&ds, iafsStats);
+ }
+ sFirst += ds;
+ s = sFirst;
+
+ // read the instances
+ // (this loop test is here to avoid an infinite loop with damaged
+ // JBIG2 streams where the normal loop exit doesn't get triggered)
+ while (inst < numInstances) {
+
+ // T value
+ if (strips == 1) {
+ dt = 0;
+ } else if (huff) {
+ dt = huffDecoder->readBits(logStrips);
+ } else {
+ arithDecoder->decodeInt(&dt, iaitStats);
+ }
+ tt = t + dt;
+
+ // symbol ID
+ if (huff) {
+ if (symCodeTab) {
+ huffDecoder->decodeInt(&j, symCodeTab);
+ symID = (Guint)j;
+ } else {
+ symID = huffDecoder->readBits(symCodeLen);
+ }
+ } else {
+ symID = arithDecoder->decodeIAID(symCodeLen, iaidStats);
+ }
+
+ if (symID >= (Guint)numSyms) {
+ error(errSyntaxError, curStr->getPos(), "Invalid symbol number in JBIG2 text region");
+ if (unlikely(numInstances - inst > 0x800)) {
+ // don't loop too often with damaged JBIg2 streams
+ delete bitmap;
+ return NULL;
+ }
+ } else {
+
+ // get the symbol bitmap
+ symbolBitmap = NULL;
+ if (refine) {
+ if (huff) {
+ ri = (int)huffDecoder->readBit();
+ } else {
+ arithDecoder->decodeInt(&ri, iariStats);
+ }
+ } else {
+ ri = 0;
+ }
+ if (ri) {
+ GBool decodeSuccess;
+ if (huff) {
+ decodeSuccess = huffDecoder->decodeInt(&rdw, huffRDWTable);
+ decodeSuccess = decodeSuccess && huffDecoder->decodeInt(&rdh, huffRDHTable);
+ decodeSuccess = decodeSuccess && huffDecoder->decodeInt(&rdx, huffRDXTable);
+ decodeSuccess = decodeSuccess && huffDecoder->decodeInt(&rdy, huffRDYTable);
+ decodeSuccess = decodeSuccess && huffDecoder->decodeInt(&bmSize, huffRSizeTable);
+ huffDecoder->reset();
+ arithDecoder->start();
+ } else {
+ decodeSuccess = arithDecoder->decodeInt(&rdw, iardwStats);
+ decodeSuccess = decodeSuccess && arithDecoder->decodeInt(&rdh, iardhStats);
+ decodeSuccess = decodeSuccess && arithDecoder->decodeInt(&rdx, iardxStats);
+ decodeSuccess = decodeSuccess && arithDecoder->decodeInt(&rdy, iardyStats);
+ }
+
+ if (decodeSuccess && syms[symID])
+ {
+ refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx;
+ refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy;
+
+ symbolBitmap =
+ readGenericRefinementRegion(rdw + syms[symID]->getWidth(),
+ rdh + syms[symID]->getHeight(),
+ templ, gFalse, syms[symID],
+ refDX, refDY, atx, aty);
+ }
+ //~ do we need to use the bmSize value here (in Huffman mode)?
+ } else {
+ symbolBitmap = syms[symID];
+ }
+
+ if (symbolBitmap) {
+ // combine the symbol bitmap into the region bitmap
+ //~ something is wrong here - refCorner shouldn't degenerate into
+ //~ two cases
+ bw = symbolBitmap->getWidth() - 1;
+ if (unlikely(symbolBitmap->getHeight() == 0)) {
+ error(errSyntaxError, curStr->getPos(), "Invalid symbol bitmap height");
+ if (ri) {
+ delete symbolBitmap;
+ }
+ delete bitmap;
+ return NULL;
+ }
+ bh = symbolBitmap->getHeight() - 1;
+ if (transposed) {
+ if (unlikely(s > 2 * bitmap->getHeight())) {
+ error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine");
+ if (ri) {
+ delete symbolBitmap;
+ }
+ delete bitmap;
+ return NULL;
+ }
+ switch (refCorner) {
+ case 0: // bottom left
+ bitmap->combine(symbolBitmap, tt, s, combOp);
+ break;
+ case 1: // top left
+ bitmap->combine(symbolBitmap, tt, s, combOp);
+ break;
+ case 2: // bottom right
+ bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+ break;
+ case 3: // top right
+ bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+ break;
+ }
+ s += bh;
+ } else {
+ switch (refCorner) {
+ case 0: // bottom left
+ if (unlikely(tt - (int) bh > 2 * bitmap->getHeight())) {
+ error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine");
+ if (ri) {
+ delete symbolBitmap;
+ }
+ delete bitmap;
+ return NULL;
+ }
+ bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+ break;
+ case 1: // top left
+ if (unlikely(tt > 2 * bitmap->getHeight())) {
+ error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine");
+ if (ri) {
+ delete symbolBitmap;
+ }
+ delete bitmap;
+ return NULL;
+ }
+ bitmap->combine(symbolBitmap, s, tt, combOp);
+ break;
+ case 2: // bottom right
+ if (unlikely(tt - (int) bh > 2 * bitmap->getHeight())) {
+ error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine");
+ if (ri) {
+ delete symbolBitmap;
+ }
+ delete bitmap;
+ return NULL;
+ }
+ bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+ break;
+ case 3: // top right
+ if (unlikely(tt > 2 * bitmap->getHeight())) {
+ error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine");
+ if (ri) {
+ delete symbolBitmap;
+ }
+ delete bitmap;
+ return NULL;
+ }
+ bitmap->combine(symbolBitmap, s, tt, combOp);
+ break;
+ }
+ s += bw;
+ }
+ if (ri) {
+ delete symbolBitmap;
+ }
+ } else {
+ // NULL symbolBitmap only happens on error
+ delete bitmap;
+ return NULL;
+ }
+ }
+
+ // next instance
+ ++inst;
+
+ // next S value
+ if (huff) {
+ if (!huffDecoder->decodeInt(&ds, huffDSTable)) {
+ break;
+ }
+ } else {
+ if (!arithDecoder->decodeInt(&ds, iadsStats)) {
+ break;
+ }
+ }
+ s += sOffset + ds;
+ }
+ }
+
+ return bitmap;
+}
+
+void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) {
+ JBIG2PatternDict *patternDict;
+ JBIG2Bitmap *bitmap;
+ Guint flags, patternW, patternH, grayMax, templ, mmr;
+ int atx[4], aty[4];
+ Guint i, x;
+
+ // halftone dictionary flags, pattern width and height, max gray value
+ if (!readUByte(&flags) ||
+ !readUByte(&patternW) ||
+ !readUByte(&patternH) ||
+ !readULong(&grayMax)) {
+ goto eofError;
+ }
+ templ = (flags >> 1) & 3;
+ mmr = flags & 1;
+
+ // set up the arithmetic decoder
+ if (!mmr) {
+ resetGenericStats(templ, NULL);
+ arithDecoder->start();
+ }
+
+ // read the bitmap
+ atx[0] = -(int)patternW; aty[0] = 0;
+ atx[1] = -3; aty[1] = -1;
+ atx[2] = 2; aty[2] = -2;
+ atx[3] = -2; aty[3] = -2;
+ bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH,
+ templ, gFalse, gFalse, NULL,
+ atx, aty, length - 7);
+
+ if (!bitmap)
+ return;
+
+ // create the pattern dict object
+ patternDict = new JBIG2PatternDict(segNum, grayMax + 1);
+
+ // split up the bitmap
+ x = 0;
+ for (i = 0; i <= grayMax && i < patternDict->getSize(); ++i) {
+ patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH));
+ x += patternW;
+ }
+
+ // free memory
+ delete bitmap;
+
+ // store the new pattern dict
+ segments->append(patternDict);
+
+ return;
+
+ eofError:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs, Guint nRefSegs) {
+ JBIG2Bitmap *bitmap;
+ JBIG2Segment *seg;
+ JBIG2PatternDict *patternDict;
+ JBIG2Bitmap *skipBitmap;
+ Guint *grayImg;
+ JBIG2Bitmap *grayBitmap;
+ JBIG2Bitmap *patternBitmap;
+ Guint w, h, x, y, segInfoFlags, extCombOp;
+ Guint flags, mmr, templ, enableSkip, combOp;
+ Guint gridW, gridH, stepX, stepY, patW, patH;
+ int atx[4], aty[4];
+ int gridX, gridY, xx, yy, bit, j;
+ Guint bpp, m, n, i;
+
+ // region segment info field
+ if (!readULong(&w) || !readULong(&h) ||
+ !readULong(&x) || !readULong(&y) ||
+ !readUByte(&segInfoFlags)) {
+ goto eofError;
+ }
+ extCombOp = segInfoFlags & 7;
+
+ // rest of the halftone region header
+ if (!readUByte(&flags)) {
+ goto eofError;
+ }
+ mmr = flags & 1;
+ templ = (flags >> 1) & 3;
+ enableSkip = (flags >> 3) & 1;
+ combOp = (flags >> 4) & 7;
+ if (!readULong(&gridW) || !readULong(&gridH) ||
+ !readLong(&gridX) || !readLong(&gridY) ||
+ !readUWord(&stepX) || !readUWord(&stepY)) {
+ goto eofError;
+ }
+ if (w == 0 || h == 0 || w >= INT_MAX / h) {
+ error(errSyntaxError, curStr->getPos(), "Bad bitmap size in JBIG2 halftone segment");
+ return;
+ }
+ if (gridH == 0 || gridW >= INT_MAX / gridH) {
+ error(errSyntaxError, curStr->getPos(), "Bad grid size in JBIG2 halftone segment");
+ return;
+ }
+
+ // get pattern dictionary
+ if (nRefSegs != 1) {
+ error(errSyntaxError, curStr->getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
+ return;
+ }
+ seg = findSegment(refSegs[0]);
+ if (seg == NULL || seg->getType() != jbig2SegPatternDict) {
+ error(errSyntaxError, curStr->getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
+ return;
+ }
+
+ patternDict = (JBIG2PatternDict *)seg;
+ i = patternDict->getSize();
+ if (i <= 1) {
+ bpp = 0;
+ } else {
+ --i;
+ bpp = 0;
+ // i = floor((size-1) / 2^bpp)
+ while (i > 0) {
+ ++bpp;
+ i >>= 1;
+ }
+ }
+ patW = patternDict->getBitmap(0)->getWidth();
+ patH = patternDict->getBitmap(0)->getHeight();
+
+ // set up the arithmetic decoder
+ if (!mmr) {
+ resetGenericStats(templ, NULL);
+ arithDecoder->start();
+ }
+
+ // allocate the bitmap
+ bitmap = new JBIG2Bitmap(segNum, w, h);
+ if (flags & 0x80) { // HDEFPIXEL
+ bitmap->clearToOne();
+ } else {
+ bitmap->clearToZero();
+ }
+
+ // compute the skip bitmap
+ skipBitmap = NULL;
+ if (enableSkip) {
+ skipBitmap = new JBIG2Bitmap(0, gridW, gridH);
+ skipBitmap->clearToZero();
+ for (m = 0; m < gridH; ++m) {
+ for (n = 0; n < gridW; ++n) {
+ xx = gridX + m * stepY + n * stepX;
+ yy = gridY + m * stepX - n * stepY;
+ if (((xx + (int)patW) >> 8) <= 0 || (xx >> 8) >= (int)w ||
+ ((yy + (int)patH) >> 8) <= 0 || (yy >> 8) >= (int)h) {
+ skipBitmap->setPixel(n, m);
+ }
+ }
+ }
+ }
+
+ // read the gray-scale image
+ grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint));
+ memset(grayImg, 0, gridW * gridH * sizeof(Guint));
+ atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1;
+ atx[1] = -3; aty[1] = -1;
+ atx[2] = 2; aty[2] = -2;
+ atx[3] = -2; aty[3] = -2;
+ for (j = bpp - 1; j >= 0; --j) {
+ grayBitmap = readGenericBitmap(mmr, gridW, gridH, templ, gFalse,
+ enableSkip, skipBitmap, atx, aty, -1);
+ i = 0;
+ for (m = 0; m < gridH; ++m) {
+ for (n = 0; n < gridW; ++n) {
+ bit = grayBitmap->getPixel(n, m) ^ (grayImg[i] & 1);
+ grayImg[i] = (grayImg[i] << 1) | bit;
+ ++i;
+ }
+ }
+ delete grayBitmap;
+ }
+
+ // decode the image
+ i = 0;
+ for (m = 0; m < gridH; ++m) {
+ xx = gridX + m * stepY;
+ yy = gridY + m * stepX;
+ for (n = 0; n < gridW; ++n) {
+ if (!(enableSkip && skipBitmap->getPixel(n, m))) {
+ patternBitmap = patternDict->getBitmap(grayImg[i]);
+ if (unlikely(patternBitmap == NULL)) {
+ error(errSyntaxError, curStr->getPos(), "Bad pattern bitmap");
+ return;
+ }
+ bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp);
+ }
+ xx += stepX;
+ yy -= stepY;
+ ++i;
+ }
+ }
+
+ gfree(grayImg);
+ if (skipBitmap) {
+ delete skipBitmap;
+ }
+
+ // combine the region bitmap into the page bitmap
+ if (imm) {
+ if (pageH == 0xffffffff && y + h > curPageH) {
+ pageBitmap->expand(y + h, pageDefPixel);
+ }
+ pageBitmap->combine(bitmap, x, y, extCombOp);
+ delete bitmap;
+
+ // store the region bitmap
+ } else {
+ segments->append(bitmap);
+ }
+
+ return;
+
+ eofError:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length) {
+ JBIG2Bitmap *bitmap;
+ Guint w, h, x, y, segInfoFlags, extCombOp, rowCount;
+ Guint flags, mmr, templ, tpgdOn;
+ int atx[4], aty[4];
+
+ // region segment info field
+ if (!readULong(&w) || !readULong(&h) ||
+ !readULong(&x) || !readULong(&y) ||
+ !readUByte(&segInfoFlags)) {
+ goto eofError;
+ }
+ extCombOp = segInfoFlags & 7;
+
+ // rest of the generic region segment header
+ if (!readUByte(&flags)) {
+ goto eofError;
+ }
+ mmr = flags & 1;
+ templ = (flags >> 1) & 3;
+ tpgdOn = (flags >> 3) & 1;
+
+ // AT flags
+ if (!mmr) {
+ if (templ == 0) {
+ if (!readByte(&atx[0]) ||
+ !readByte(&aty[0]) ||
+ !readByte(&atx[1]) ||
+ !readByte(&aty[1]) ||
+ !readByte(&atx[2]) ||
+ !readByte(&aty[2]) ||
+ !readByte(&atx[3]) ||
+ !readByte(&aty[3])) {
+ goto eofError;
+ }
+ } else {
+ if (!readByte(&atx[0]) ||
+ !readByte(&aty[0])) {
+ goto eofError;
+ }
+ }
+ }
+
+ // set up the arithmetic decoder
+ if (!mmr) {
+ resetGenericStats(templ, NULL);
+ arithDecoder->start();
+ }
+
+ // read the bitmap
+ bitmap = readGenericBitmap(mmr, w, h, templ, tpgdOn, gFalse,
+ NULL, atx, aty, mmr ? length - 18 : 0);
+ if (!bitmap)
+ return;
+
+ // combine the region bitmap into the page bitmap
+ if (imm) {
+ if (pageH == 0xffffffff && y + h > curPageH) {
+ pageBitmap->expand(y + h, pageDefPixel);
+ }
+ pageBitmap->combine(bitmap, x, y, extCombOp);
+ delete bitmap;
+
+ // store the region bitmap
+ } else {
+ bitmap->setSegNum(segNum);
+ segments->append(bitmap);
+ }
+
+ // immediate generic segments can have an unspecified length, in
+ // which case, a row count is stored at the end of the segment
+ if (imm && length == 0xffffffff) {
+ readULong(&rowCount);
+ }
+
+ return;
+
+ eofError:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+inline void JBIG2Stream::mmrAddPixels(int a1, int blackPixels,
+ int *codingLine, int *a0i, int w) {
+ if (a1 > codingLine[*a0i]) {
+ if (a1 > w) {
+ error(errSyntaxError, curStr->getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1);
+ a1 = w;
+ }
+ if ((*a0i & 1) ^ blackPixels) {
+ ++*a0i;
+ }
+ codingLine[*a0i] = a1;
+ }
+}
+
+inline void JBIG2Stream::mmrAddPixelsNeg(int a1, int blackPixels,
+ int *codingLine, int *a0i, int w) {
+ if (a1 > codingLine[*a0i]) {
+ if (a1 > w) {
+ error(errSyntaxError, curStr->getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1);
+ a1 = w;
+ }
+ if ((*a0i & 1) ^ blackPixels) {
+ ++*a0i;
+ }
+ codingLine[*a0i] = a1;
+ } else if (a1 < codingLine[*a0i]) {
+ if (a1 < 0) {
+ error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 MMR code");
+ a1 = 0;
+ }
+ while (*a0i > 0 && a1 <= codingLine[*a0i - 1]) {
+ --*a0i;
+ }
+ codingLine[*a0i] = a1;
+ }
+}
+
+JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
+ int templ, GBool tpgdOn,
+ GBool useSkip, JBIG2Bitmap *skip,
+ int *atx, int *aty,
+ int mmrDataLength) {
+ JBIG2Bitmap *bitmap;
+ GBool ltp;
+ Guint ltpCX, cx, cx0, cx1, cx2;
+ int *refLine, *codingLine;
+ int code1, code2, code3;
+ Guchar *p0, *p1, *p2, *pp;
+ Guchar *atP0, *atP1, *atP2, *atP3;
+ Guint buf0, buf1, buf2;
+ Guint atBuf0, atBuf1, atBuf2, atBuf3;
+ int atShift0, atShift1, atShift2, atShift3;
+ Guchar mask;
+ int x, y, x0, x1, a0i, b1i, blackPixels, pix, i;
+
+ bitmap = new JBIG2Bitmap(0, w, h);
+ if (!bitmap->isOk()) {
+ delete bitmap;
+ return NULL;
+ }
+ bitmap->clearToZero();
+
+ //----- MMR decode
+
+ if (mmr) {
+
+ mmrDecoder->reset();
+ if (w > INT_MAX - 2) {
+ error(errSyntaxError, curStr->getPos(), "Bad width in JBIG2 generic bitmap");
+ // force a call to gmalloc(-1), which will throw an exception
+ w = -3;
+ }
+ // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = w
+ // ---> max codingLine size = w + 1
+ // refLine has one extra guard entry at the end
+ // ---> max refLine size = w + 2
+ codingLine = (int *)gmallocn(w + 1, sizeof(int));
+ refLine = (int *)gmallocn(w + 2, sizeof(int));
+ memset(refLine, 0, (w + 2) * sizeof(int));
+ for (i = 0; i < w + 1; ++i) codingLine[i] = w;
+
+ for (y = 0; y < h; ++y) {
+
+ // copy coding line to ref line
+ for (i = 0; codingLine[i] < w; ++i) {
+ refLine[i] = codingLine[i];
+ }
+ refLine[i++] = w;
+ refLine[i] = w;
+
+ // decode a line
+ codingLine[0] = 0;
+ a0i = 0;
+ b1i = 0;
+ blackPixels = 0;
+ // invariant:
+ // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1] <= w
+ // exception at left edge:
+ // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible
+ // exception at right edge:
+ // refLine[b1i] = refLine[b1i+1] = w is possible
+ while (codingLine[a0i] < w) {
+ code1 = mmrDecoder->get2DCode();
+ switch (code1) {
+ case twoDimPass:
+ if (unlikely(b1i + 1 >= w + 2)) {
+ break;
+ }
+ mmrAddPixels(refLine[b1i + 1], blackPixels, codingLine, &a0i, w);
+ if (refLine[b1i + 1] < w) {
+ b1i += 2;
+ }
+ break;
+ case twoDimHoriz:
+ code1 = code2 = 0;
+ if (blackPixels) {
+ do {
+ code1 += code3 = mmrDecoder->getBlackCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = mmrDecoder->getWhiteCode();
+ } while (code3 >= 64);
+ } else {
+ do {
+ code1 += code3 = mmrDecoder->getWhiteCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = mmrDecoder->getBlackCode();
+ } while (code3 >= 64);
+ }
+ mmrAddPixels(codingLine[a0i] + code1, blackPixels,
+ codingLine, &a0i, w);
+ if (codingLine[a0i] < w) {
+ mmrAddPixels(codingLine[a0i] + code2, blackPixels ^ 1,
+ codingLine, &a0i, w);
+ }
+ while (likely(b1i < w + 2) && refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ break;
+ case twoDimVertR3:
+ if (unlikely(b1i >= w + 2)) {
+ break;
+ }
+ mmrAddPixels(refLine[b1i] + 3, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ ++b1i;
+ while (likely(b1i < w + 2) && refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertR2:
+ if (unlikely(b1i >= w + 2)) {
+ break;
+ }
+ mmrAddPixels(refLine[b1i] + 2, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ ++b1i;
+ while (likely(b1i < w + 2) && refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertR1:
+ if (unlikely(b1i >= w + 2)) {
+ break;
+ }
+ mmrAddPixels(refLine[b1i] + 1, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ ++b1i;
+ while (likely(b1i < w + 2) && refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVert0:
+ if (unlikely(b1i >= w + 2)) {
+ break;
+ }
+ mmrAddPixels(refLine[b1i], blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ ++b1i;
+ while (likely(b1i < w + 2) && refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL3:
+ if (unlikely(b1i >= w + 2)) {
+ break;
+ }
+ mmrAddPixelsNeg(refLine[b1i] - 3, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (likely(b1i < w + 2) && refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL2:
+ if (unlikely(b1i >= w + 2)) {
+ break;
+ }
+ mmrAddPixelsNeg(refLine[b1i] - 2, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (likely(b1i < w + 2) && refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL1:
+ if (unlikely(b1i >= w + 2)) {
+ break;
+ }
+ mmrAddPixelsNeg(refLine[b1i] - 1, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (likely(b1i < w + 2) && refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case EOF:
+ mmrAddPixels(w, 0, codingLine, &a0i, w);
+ break;
+ default:
+ error(errSyntaxError, curStr->getPos(), "Illegal code in JBIG2 MMR bitmap data");
+ mmrAddPixels(w, 0, codingLine, &a0i, w);
+ break;
+ }
+ }
+
+ // convert the run lengths to a bitmap line
+ i = 0;
+ while (1) {
+ for (x = codingLine[i]; x < codingLine[i+1]; ++x) {
+ bitmap->setPixel(x, y);
+ }
+ if (codingLine[i+1] >= w || codingLine[i+2] >= w) {
+ break;
+ }
+ i += 2;
+ }
+ }
+
+ if (mmrDataLength >= 0) {
+ mmrDecoder->skipTo(mmrDataLength);
+ } else {
+ if (mmrDecoder->get24Bits() != 0x001001) {
+ error(errSyntaxError, curStr->getPos(), "Missing EOFB in JBIG2 MMR bitmap data");
+ }
+ }
+
+ gfree(refLine);
+ gfree(codingLine);
+
+ //----- arithmetic decode
+
+ } else {
+ // set up the typical row context
+ ltpCX = 0; // make gcc happy
+ if (tpgdOn) {
+ switch (templ) {
+ case 0:
+ ltpCX = 0x3953; // 001 11001 0101 0011
+ break;
+ case 1:
+ ltpCX = 0x079a; // 0011 11001 101 0
+ break;
+ case 2:
+ ltpCX = 0x0e3; // 001 1100 01 1
+ break;
+ case 3:
+ ltpCX = 0x18a; // 01100 0101 1
+ break;
+ }
+ }
+
+ ltp = 0;
+ cx = cx0 = cx1 = cx2 = 0; // make gcc happy
+ for (y = 0; y < h; ++y) {
+
+ // check for a "typical" (duplicate) row
+ if (tpgdOn) {
+ if (arithDecoder->decodeBit(ltpCX, genericRegionStats)) {
+ ltp = !ltp;
+ }
+ if (ltp) {
+ if (y > 0) {
+ bitmap->duplicateRow(y, y-1);
+ }
+ continue;
+ }
+ }
+
+ switch (templ) {
+ case 0:
+
+ // set up the context
+ p2 = pp = bitmap->getDataPtr() + y * bitmap->getLineSize();
+ buf2 = *p2++ << 8;
+ if (y >= 1) {
+ p1 = bitmap->getDataPtr() + (y - 1) * bitmap->getLineSize();
+ buf1 = *p1++ << 8;
+ if (y >= 2) {
+ p0 = bitmap->getDataPtr() + (y - 2) * bitmap->getLineSize();
+ buf0 = *p0++ << 8;
+ } else {
+ p0 = NULL;
+ buf0 = 0;
+ }
+ } else {
+ p1 = p0 = NULL;
+ buf1 = buf0 = 0;
+ }
+
+ if (atx[0] >= -8 && atx[0] <= 8 &&
+ atx[1] >= -8 && atx[1] <= 8 &&
+ atx[2] >= -8 && atx[2] <= 8 &&
+ atx[3] >= -8 && atx[3] <= 8) {
+ // set up the adaptive context
+ if (y + aty[0] >= 0 && y + aty[0] < bitmap->getHeight()) {
+ atP0 = bitmap->getDataPtr() + (y + aty[0]) * bitmap->getLineSize();
+ atBuf0 = *atP0++ << 8;
+ } else {
+ atP0 = NULL;
+ atBuf0 = 0;
+ }
+ atShift0 = 15 - atx[0];
+ if (y + aty[1] >= 0 && y + aty[1] < bitmap->getHeight()) {
+ atP1 = bitmap->getDataPtr() + (y + aty[1]) * bitmap->getLineSize();
+ atBuf1 = *atP1++ << 8;
+ } else {
+ atP1 = NULL;
+ atBuf1 = 0;
+ }
+ atShift1 = 15 - atx[1];
+ if (y + aty[2] >= 0 && y + aty[2] < bitmap->getHeight()) {
+ atP2 = bitmap->getDataPtr() + (y + aty[2]) * bitmap->getLineSize();
+ atBuf2 = *atP2++ << 8;
+ } else {
+ atP2 = NULL;
+ atBuf2 = 0;
+ }
+ atShift2 = 15 - atx[2];
+ if (y + aty[3] >= 0 && y + aty[3] < bitmap->getHeight()) {
+ atP3 = bitmap->getDataPtr() + (y + aty[3]) * bitmap->getLineSize();
+ atBuf3 = *atP3++ << 8;
+ } else {
+ atP3 = NULL;
+ atBuf3 = 0;
+ }
+ atShift3 = 15 - atx[3];
+
+ // decode the row
+ for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) {
+ if (x0 + 8 < w) {
+ if (p0) {
+ buf0 |= *p0++;
+ }
+ if (p1) {
+ buf1 |= *p1++;
+ }
+ buf2 |= *p2++;
+ if (atP0) {
+ atBuf0 |= *atP0++;
+ }
+ if (atP1) {
+ atBuf1 |= *atP1++;
+ }
+ if (atP2) {
+ atBuf2 |= *atP2++;
+ }
+ if (atP3) {
+ atBuf3 |= *atP3++;
+ }
+ }
+ for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) {
+
+ // build the context
+ cx0 = (buf0 >> 14) & 0x07;
+ cx1 = (buf1 >> 13) & 0x1f;
+ cx2 = (buf2 >> 16) & 0x0f;
+ cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) |
+ (((atBuf0 >> atShift0) & 1) << 3) |
+ (((atBuf1 >> atShift1) & 1) << 2) |
+ (((atBuf2 >> atShift2) & 1) << 1) |
+ ((atBuf3 >> atShift3) & 1);
+
+ // check for a skipped pixel
+ if (!(useSkip && skip->getPixel(x, y))) {
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ *pp |= mask;
+ buf2 |= 0x8000;
+ if (aty[0] == 0) {
+ atBuf0 |= 0x8000;
+ }
+ if (aty[1] == 0) {
+ atBuf1 |= 0x8000;
+ }
+ if (aty[2] == 0) {
+ atBuf2 |= 0x8000;
+ }
+ if (aty[3] == 0) {
+ atBuf3 |= 0x8000;
+ }
+ }
+ }
+
+ // update the context
+ buf0 <<= 1;
+ buf1 <<= 1;
+ buf2 <<= 1;
+ atBuf0 <<= 1;
+ atBuf1 <<= 1;
+ atBuf2 <<= 1;
+ atBuf3 <<= 1;
+ }
+ }
+
+ } else {
+ // decode the row
+ for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) {
+ if (x0 + 8 < w) {
+ if (p0) {
+ buf0 |= *p0++;
+ }
+ if (p1) {
+ buf1 |= *p1++;
+ }
+ buf2 |= *p2++;
+ }
+ for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) {
+
+ // build the context
+ cx0 = (buf0 >> 14) & 0x07;
+ cx1 = (buf1 >> 13) & 0x1f;
+ cx2 = (buf2 >> 16) & 0x0f;
+ cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) |
+ (bitmap->getPixel(x + atx[0], y + aty[0]) << 3) |
+ (bitmap->getPixel(x + atx[1], y + aty[1]) << 2) |
+ (bitmap->getPixel(x + atx[2], y + aty[2]) << 1) |
+ bitmap->getPixel(x + atx[3], y + aty[3]);
+
+ // check for a skipped pixel
+ if (!(useSkip && skip->getPixel(x, y))) {
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ *pp |= mask;
+ buf2 |= 0x8000;
+ }
+ }
+
+ // update the context
+ buf0 <<= 1;
+ buf1 <<= 1;
+ buf2 <<= 1;
+ }
+ }
+ }
+ break;
+
+ case 1:
+
+ // set up the context
+ p2 = pp = bitmap->getDataPtr() + y * bitmap->getLineSize();
+ buf2 = *p2++ << 8;
+ if (y >= 1) {
+ p1 = bitmap->getDataPtr() + (y - 1) * bitmap->getLineSize();
+ buf1 = *p1++ << 8;
+ if (y >= 2) {
+ p0 = bitmap->getDataPtr() + (y - 2) * bitmap->getLineSize();
+ buf0 = *p0++ << 8;
+ } else {
+ p0 = NULL;
+ buf0 = 0;
+ }
+ } else {
+ p1 = p0 = NULL;
+ buf1 = buf0 = 0;
+ }
+
+ if (atx[0] >= -8 && atx[0] <= 8) {
+ // set up the adaptive context
+ const int atY = y + aty[0];
+ if ((atY >= 0) && (atY < bitmap->getHeight())) {
+ atP0 = bitmap->getDataPtr() + atY * bitmap->getLineSize();
+ atBuf0 = *atP0++ << 8;
+ } else {
+ atP0 = NULL;
+ atBuf0 = 0;
+ }
+ atShift0 = 15 - atx[0];
+
+ // decode the row
+ for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) {
+ if (x0 + 8 < w) {
+ if (p0) {
+ buf0 |= *p0++;
+ }
+ if (p1) {
+ buf1 |= *p1++;
+ }
+ buf2 |= *p2++;
+ if (atP0) {
+ atBuf0 |= *atP0++;
+ }
+ }
+ for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) {
+
+ // build the context
+ cx0 = (buf0 >> 13) & 0x0f;
+ cx1 = (buf1 >> 13) & 0x1f;
+ cx2 = (buf2 >> 16) & 0x07;
+ cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) |
+ ((atBuf0 >> atShift0) & 1);
+
+ // check for a skipped pixel
+ if (!(useSkip && skip->getPixel(x, y))) {
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ *pp |= mask;
+ buf2 |= 0x8000;
+ if (aty[0] == 0) {
+ atBuf0 |= 0x8000;
+ }
+ }
+ }
+
+ // update the context
+ buf0 <<= 1;
+ buf1 <<= 1;
+ buf2 <<= 1;
+ atBuf0 <<= 1;
+ }
+ }
+
+ } else {
+ // decode the row
+ for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) {
+ if (x0 + 8 < w) {
+ if (p0) {
+ buf0 |= *p0++;
+ }
+ if (p1) {
+ buf1 |= *p1++;
+ }
+ buf2 |= *p2++;
+ }
+ for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) {
+
+ // build the context
+ cx0 = (buf0 >> 13) & 0x0f;
+ cx1 = (buf1 >> 13) & 0x1f;
+ cx2 = (buf2 >> 16) & 0x07;
+ cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) |
+ bitmap->getPixel(x + atx[0], y + aty[0]);
+
+ // check for a skipped pixel
+ if (!(useSkip && skip->getPixel(x, y))) {
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ *pp |= mask;
+ buf2 |= 0x8000;
+ }
+ }
+
+ // update the context
+ buf0 <<= 1;
+ buf1 <<= 1;
+ buf2 <<= 1;
+ }
+ }
+ }
+ break;
+
+ case 2:
+
+ // set up the context
+ p2 = pp = bitmap->getDataPtr() + y * bitmap->getLineSize();
+ buf2 = *p2++ << 8;
+ if (y >= 1) {
+ p1 = bitmap->getDataPtr() + (y - 1) * bitmap->getLineSize();
+ buf1 = *p1++ << 8;
+ if (y >= 2) {
+ p0 = bitmap->getDataPtr() + (y - 2) * bitmap->getLineSize();
+ buf0 = *p0++ << 8;
+ } else {
+ p0 = NULL;
+ buf0 = 0;
+ }
+ } else {
+ p1 = p0 = NULL;
+ buf1 = buf0 = 0;
+ }
+
+ if (atx[0] >= -8 && atx[0] <= 8) {
+ // set up the adaptive context
+ const int atY = y + aty[0];
+ if ((atY >= 0) && (atY < bitmap->getHeight())) {
+ atP0 = bitmap->getDataPtr() + atY * bitmap->getLineSize();
+ atBuf0 = *atP0++ << 8;
+ } else {
+ atP0 = NULL;
+ atBuf0 = 0;
+ }
+ atShift0 = 15 - atx[0];
+
+ // decode the row
+ for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) {
+ if (x0 + 8 < w) {
+ if (p0) {
+ buf0 |= *p0++;
+ }
+ if (p1) {
+ buf1 |= *p1++;
+ }
+ buf2 |= *p2++;
+ if (atP0) {
+ atBuf0 |= *atP0++;
+ }
+ }
+ for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) {
+
+ // build the context
+ cx0 = (buf0 >> 14) & 0x07;
+ cx1 = (buf1 >> 14) & 0x0f;
+ cx2 = (buf2 >> 16) & 0x03;
+ cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) |
+ ((atBuf0 >> atShift0) & 1);
+
+ // check for a skipped pixel
+ if (!(useSkip && skip->getPixel(x, y))) {
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ *pp |= mask;
+ buf2 |= 0x8000;
+ if (aty[0] == 0) {
+ atBuf0 |= 0x8000;
+ }
+ }
+ }
+
+ // update the context
+ buf0 <<= 1;
+ buf1 <<= 1;
+ buf2 <<= 1;
+ atBuf0 <<= 1;
+ }
+ }
+
+ } else {
+ // decode the row
+ for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) {
+ if (x0 + 8 < w) {
+ if (p0) {
+ buf0 |= *p0++;
+ }
+ if (p1) {
+ buf1 |= *p1++;
+ }
+ buf2 |= *p2++;
+ }
+ for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) {
+
+ // build the context
+ cx0 = (buf0 >> 14) & 0x07;
+ cx1 = (buf1 >> 14) & 0x0f;
+ cx2 = (buf2 >> 16) & 0x03;
+ cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) |
+ bitmap->getPixel(x + atx[0], y + aty[0]);
+
+ // check for a skipped pixel
+ if (!(useSkip && skip->getPixel(x, y))) {
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ *pp |= mask;
+ buf2 |= 0x8000;
+ }
+ }
+
+ // update the context
+ buf0 <<= 1;
+ buf1 <<= 1;
+ buf2 <<= 1;
+ }
+ }
+ }
+ break;
+
+ case 3:
+
+ // set up the context
+ p2 = pp = bitmap->getDataPtr() + y * bitmap->getLineSize();
+ buf2 = *p2++ << 8;
+ if (y >= 1) {
+ p1 = bitmap->getDataPtr() + (y - 1) * bitmap->getLineSize();
+ buf1 = *p1++ << 8;
+ } else {
+ p1 = NULL;
+ buf1 = 0;
+ }
+
+ if (atx[0] >= -8 && atx[0] <= 8) {
+ // set up the adaptive context
+ const int atY = y + aty[0];
+ if ((atY >= 0) && (atY < bitmap->getHeight())) {
+ atP0 = bitmap->getDataPtr() + atY * bitmap->getLineSize();
+ atBuf0 = *atP0++ << 8;
+ } else {
+ atP0 = NULL;
+ atBuf0 = 0;
+ }
+ atShift0 = 15 - atx[0];
+
+ // decode the row
+ for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) {
+ if (x0 + 8 < w) {
+ if (p1) {
+ buf1 |= *p1++;
+ }
+ buf2 |= *p2++;
+ if (atP0) {
+ atBuf0 |= *atP0++;
+ }
+ }
+ for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) {
+
+ // build the context
+ cx1 = (buf1 >> 14) & 0x1f;
+ cx2 = (buf2 >> 16) & 0x0f;
+ cx = (cx1 << 5) | (cx2 << 1) |
+ ((atBuf0 >> atShift0) & 1);
+
+ // check for a skipped pixel
+ if (!(useSkip && skip->getPixel(x, y))) {
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ *pp |= mask;
+ buf2 |= 0x8000;
+ if (aty[0] == 0) {
+ atBuf0 |= 0x8000;
+ }
+ }
+ }
+
+ // update the context
+ buf1 <<= 1;
+ buf2 <<= 1;
+ atBuf0 <<= 1;
+ }
+ }
+
+ } else {
+ // decode the row
+ for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) {
+ if (x0 + 8 < w) {
+ if (p1) {
+ buf1 |= *p1++;
+ }
+ buf2 |= *p2++;
+ }
+ for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) {
+
+ // build the context
+ cx1 = (buf1 >> 14) & 0x1f;
+ cx2 = (buf2 >> 16) & 0x0f;
+ cx = (cx1 << 5) | (cx2 << 1) |
+ bitmap->getPixel(x + atx[0], y + aty[0]);
+
+ // check for a skipped pixel
+ if (!(useSkip && skip->getPixel(x, y))) {
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ *pp |= mask;
+ buf2 |= 0x8000;
+ }
+ }
+
+ // update the context
+ buf1 <<= 1;
+ buf2 <<= 1;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return bitmap;
+}
+
+void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs,
+ Guint nRefSegs) {
+ JBIG2Bitmap *bitmap, *refBitmap;
+ Guint w, h, x, y, segInfoFlags, extCombOp;
+ Guint flags, templ, tpgrOn;
+ int atx[2], aty[2];
+ JBIG2Segment *seg;
+
+ // region segment info field
+ if (!readULong(&w) || !readULong(&h) ||
+ !readULong(&x) || !readULong(&y) ||
+ !readUByte(&segInfoFlags)) {
+ goto eofError;
+ }
+ extCombOp = segInfoFlags & 7;
+
+ // rest of the generic refinement region segment header
+ if (!readUByte(&flags)) {
+ goto eofError;
+ }
+ templ = flags & 1;
+ tpgrOn = (flags >> 1) & 1;
+
+ // AT flags
+ if (!templ) {
+ if (!readByte(&atx[0]) || !readByte(&aty[0]) ||
+ !readByte(&atx[1]) || !readByte(&aty[1])) {
+ goto eofError;
+ }
+ }
+
+ // resize the page bitmap if needed
+ if (nRefSegs == 0 || imm) {
+ if (pageH == 0xffffffff && y + h > curPageH) {
+ pageBitmap->expand(y + h, pageDefPixel);
+ }
+ }
+
+ // get referenced bitmap
+ if (nRefSegs > 1) {
+ error(errSyntaxError, curStr->getPos(), "Bad reference in JBIG2 generic refinement segment");
+ return;
+ }
+ if (nRefSegs == 1) {
+ seg = findSegment(refSegs[0]);
+ if (seg == NULL || seg->getType() != jbig2SegBitmap) {
+ error(errSyntaxError, curStr->getPos(), "Bad bitmap reference in JBIG2 generic refinement segment");
+ return;
+ }
+ refBitmap = (JBIG2Bitmap *)seg;
+ } else {
+ refBitmap = pageBitmap->getSlice(x, y, w, h);
+ }
+
+ // set up the arithmetic decoder
+ resetRefinementStats(templ, NULL);
+ arithDecoder->start();
+
+ // read
+ bitmap = readGenericRefinementRegion(w, h, templ, tpgrOn,
+ refBitmap, 0, 0, atx, aty);
+
+ // combine the region bitmap into the page bitmap
+ if (imm && bitmap) {
+ pageBitmap->combine(bitmap, x, y, extCombOp);
+ delete bitmap;
+
+ // store the region bitmap
+ } else {
+ if (bitmap) {
+ bitmap->setSegNum(segNum);
+ segments->append(bitmap);
+ } else {
+ error(errSyntaxError, curStr->getPos(), "readGenericRefinementRegionSeg with null bitmap");
+ }
+ }
+
+ // delete the referenced bitmap
+ if (nRefSegs == 1) {
+ discardSegment(refSegs[0]);
+ } else {
+ delete refBitmap;
+ }
+
+ return;
+
+ eofError:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h,
+ int templ, GBool tpgrOn,
+ JBIG2Bitmap *refBitmap,
+ int refDX, int refDY,
+ int *atx, int *aty) {
+ JBIG2Bitmap *bitmap;
+ GBool ltp;
+ Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2;
+ JBIG2BitmapPtr cxPtr0 = {0};
+ JBIG2BitmapPtr cxPtr1 = {0};
+ JBIG2BitmapPtr cxPtr2 = {0};
+ JBIG2BitmapPtr cxPtr3 = {0};
+ JBIG2BitmapPtr cxPtr4 = {0};
+ JBIG2BitmapPtr cxPtr5 = {0};
+ JBIG2BitmapPtr cxPtr6 = {0};
+ JBIG2BitmapPtr tpgrCXPtr0 = {0};
+ JBIG2BitmapPtr tpgrCXPtr1 = {0};
+ JBIG2BitmapPtr tpgrCXPtr2 = {0};
+ int x, y, pix;
+
+ bitmap = new JBIG2Bitmap(0, w, h);
+ if (!bitmap->isOk())
+ {
+ delete bitmap;
+ return NULL;
+ }
+ bitmap->clearToZero();
+
+ // set up the typical row context
+ if (templ) {
+ ltpCX = 0x008;
+ } else {
+ ltpCX = 0x0010;
+ }
+
+ ltp = 0;
+ for (y = 0; y < h; ++y) {
+
+ if (templ) {
+
+ // set up the context
+ bitmap->getPixelPtr(0, y-1, &cxPtr0);
+ cx0 = bitmap->nextPixel(&cxPtr0);
+ bitmap->getPixelPtr(-1, y, &cxPtr1);
+ refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2);
+ refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3);
+ cx3 = refBitmap->nextPixel(&cxPtr3);
+ cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3);
+ refBitmap->getPixelPtr(-refDX, y+1-refDY, &cxPtr4);
+ cx4 = refBitmap->nextPixel(&cxPtr4);
+
+ // set up the typical prediction context
+ tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy
+ if (tpgrOn) {
+ refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0);
+ tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0);
+ tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+ tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+ refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1);
+ tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1);
+ tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+ tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+ refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2);
+ tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2);
+ tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+ tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+ } else {
+ tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy
+ tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0;
+ tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0;
+ }
+
+ for (x = 0; x < w; ++x) {
+
+ // update the context
+ cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 7;
+ cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7;
+ cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 3;
+
+ if (tpgrOn) {
+ // update the typical predictor context
+ tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7;
+ tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7;
+ tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7;
+
+ // check for a "typical" pixel
+ if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) {
+ ltp = !ltp;
+ }
+ if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) {
+ bitmap->clearPixel(x, y);
+ continue;
+ } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) {
+ bitmap->setPixel(x, y);
+ continue;
+ }
+ }
+
+ // build the context
+ cx = (cx0 << 7) | (bitmap->nextPixel(&cxPtr1) << 6) |
+ (refBitmap->nextPixel(&cxPtr2) << 5) |
+ (cx3 << 2) | cx4;
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+ }
+
+ } else {
+
+ // set up the context
+ bitmap->getPixelPtr(0, y-1, &cxPtr0);
+ cx0 = bitmap->nextPixel(&cxPtr0);
+ bitmap->getPixelPtr(-1, y, &cxPtr1);
+ refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2);
+ cx2 = refBitmap->nextPixel(&cxPtr2);
+ refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3);
+ cx3 = refBitmap->nextPixel(&cxPtr3);
+ cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3);
+ refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &cxPtr4);
+ cx4 = refBitmap->nextPixel(&cxPtr4);
+ cx4 = (cx4 << 1) | refBitmap->nextPixel(&cxPtr4);
+ bitmap->getPixelPtr(atx[0], y+aty[0], &cxPtr5);
+ refBitmap->getPixelPtr(atx[1]-refDX, y+aty[1]-refDY, &cxPtr6);
+
+ // set up the typical prediction context
+ tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy
+ if (tpgrOn) {
+ refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0);
+ tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0);
+ tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+ tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+ refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1);
+ tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1);
+ tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+ tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+ refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2);
+ tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2);
+ tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+ tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+ } else {
+ tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy
+ tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0;
+ tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0;
+ }
+
+ for (x = 0; x < w; ++x) {
+
+ // update the context
+ cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 3;
+ cx2 = ((cx2 << 1) | refBitmap->nextPixel(&cxPtr2)) & 3;
+ cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7;
+ cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 7;
+
+ if (tpgrOn) {
+ // update the typical predictor context
+ tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7;
+ tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7;
+ tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7;
+
+ // check for a "typical" pixel
+ if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) {
+ ltp = !ltp;
+ }
+ if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) {
+ bitmap->clearPixel(x, y);
+ continue;
+ } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) {
+ bitmap->setPixel(x, y);
+ continue;
+ }
+ }
+
+ // build the context
+ cx = (cx0 << 11) | (bitmap->nextPixel(&cxPtr1) << 10) |
+ (cx2 << 8) | (cx3 << 5) | (cx4 << 2) |
+ (bitmap->nextPixel(&cxPtr5) << 1) |
+ refBitmap->nextPixel(&cxPtr6);
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+ }
+ }
+ }
+
+ return bitmap;
+}
+
+void JBIG2Stream::readPageInfoSeg(Guint length) {
+ Guint xRes, yRes, flags, striping;
+
+ if (!readULong(&pageW) || !readULong(&pageH) ||
+ !readULong(&xRes) || !readULong(&yRes) ||
+ !readUByte(&flags) || !readUWord(&striping)) {
+ goto eofError;
+ }
+ pageDefPixel = (flags >> 2) & 1;
+ defCombOp = (flags >> 3) & 3;
+
+ // allocate the page bitmap
+ if (pageH == 0xffffffff) {
+ curPageH = striping & 0x7fff;
+ } else {
+ curPageH = pageH;
+ }
+ pageBitmap = new JBIG2Bitmap(0, pageW, curPageH);
+
+ if (!pageBitmap->isOk()) {
+ delete pageBitmap;
+ pageBitmap = NULL;
+ return;
+ }
+
+ // default pixel value
+ if (pageDefPixel) {
+ pageBitmap->clearToOne();
+ } else {
+ pageBitmap->clearToZero();
+ }
+
+ return;
+
+ eofError:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void JBIG2Stream::readEndOfStripeSeg(Guint length) {
+ Guint i;
+
+ // skip the segment
+ for (i = 0; i < length; ++i) {
+ if (curStr->getChar() == EOF) {
+ break;
+ }
+ }
+}
+
+void JBIG2Stream::readProfilesSeg(Guint length) {
+ Guint i;
+
+ // skip the segment
+ for (i = 0; i < length; ++i) {
+ if (curStr->getChar() == EOF) {
+ break;
+ }
+ }
+}
+
+void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) {
+ JBIG2HuffmanTable *huffTab;
+ Guint flags, oob, prefixBits, rangeBits;
+ int lowVal, highVal, val;
+ Guint huffTabSize, i;
+
+ if (!readUByte(&flags) || !readLong(&lowVal) || !readLong(&highVal)) {
+ goto eofError;
+ }
+ oob = flags & 1;
+ prefixBits = ((flags >> 1) & 7) + 1;
+ rangeBits = ((flags >> 4) & 7) + 1;
+
+ huffDecoder->reset();
+ huffTabSize = 8;
+ huffTab = (JBIG2HuffmanTable *)
+ gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable));
+ i = 0;
+ val = lowVal;
+ while (val < highVal) {
+ if (i == huffTabSize) {
+ huffTabSize *= 2;
+ huffTab = (JBIG2HuffmanTable *)
+ greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable));
+ }
+ huffTab[i].val = val;
+ huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
+ huffTab[i].rangeLen = huffDecoder->readBits(rangeBits);
+ val += 1 << huffTab[i].rangeLen;
+ ++i;
+ }
+ if (i + oob + 3 > huffTabSize) {
+ huffTabSize = i + oob + 3;
+ huffTab = (JBIG2HuffmanTable *)
+ greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable));
+ }
+ huffTab[i].val = lowVal - 1;
+ huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
+ huffTab[i].rangeLen = jbig2HuffmanLOW;
+ ++i;
+ huffTab[i].val = highVal;
+ huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
+ huffTab[i].rangeLen = 32;
+ ++i;
+ if (oob) {
+ huffTab[i].val = 0;
+ huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
+ huffTab[i].rangeLen = jbig2HuffmanOOB;
+ ++i;
+ }
+ huffTab[i].val = 0;
+ huffTab[i].prefixLen = 0;
+ huffTab[i].rangeLen = jbig2HuffmanEOT;
+ huffDecoder->buildTable(huffTab, i);
+
+ // create and store the new table segment
+ segments->append(new JBIG2CodeTable(segNum, huffTab));
+
+ return;
+
+ eofError:
+ error(errSyntaxError, curStr->getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void JBIG2Stream::readExtensionSeg(Guint length) {
+ Guint i;
+
+ // skip the segment
+ for (i = 0; i < length; ++i) {
+ if (curStr->getChar() == EOF) {
+ break;
+ }
+ }
+}
+
+JBIG2Segment *JBIG2Stream::findSegment(Guint segNum) {
+ JBIG2Segment *seg;
+ int i;
+
+ for (i = 0; i < globalSegments->getLength(); ++i) {
+ seg = (JBIG2Segment *)globalSegments->get(i);
+ if (seg->getSegNum() == segNum) {
+ return seg;
+ }
+ }
+ for (i = 0; i < segments->getLength(); ++i) {
+ seg = (JBIG2Segment *)segments->get(i);
+ if (seg->getSegNum() == segNum) {
+ return seg;
+ }
+ }
+ return NULL;
+}
+
+void JBIG2Stream::discardSegment(Guint segNum) {
+ JBIG2Segment *seg;
+ int i;
+
+ for (i = 0; i < globalSegments->getLength(); ++i) {
+ seg = (JBIG2Segment *)globalSegments->get(i);
+ if (seg->getSegNum() == segNum) {
+ globalSegments->del(i);
+ return;
+ }
+ }
+ for (i = 0; i < segments->getLength(); ++i) {
+ seg = (JBIG2Segment *)segments->get(i);
+ if (seg->getSegNum() == segNum) {
+ segments->del(i);
+ return;
+ }
+ }
+}
+
+void JBIG2Stream::resetGenericStats(Guint templ,
+ JArithmeticDecoderStats *prevStats) {
+ int size;
+
+ size = contextSize[templ];
+ if (prevStats && prevStats->getContextSize() == size) {
+ if (genericRegionStats->getContextSize() == size) {
+ genericRegionStats->copyFrom(prevStats);
+ } else {
+ delete genericRegionStats;
+ genericRegionStats = prevStats->copy();
+ }
+ } else {
+ if (genericRegionStats->getContextSize() == size) {
+ genericRegionStats->reset();
+ } else {
+ delete genericRegionStats;
+ genericRegionStats = new JArithmeticDecoderStats(1 << size);
+ }
+ }
+}
+
+void JBIG2Stream::resetRefinementStats(Guint templ,
+ JArithmeticDecoderStats *prevStats) {
+ int size;
+
+ size = refContextSize[templ];
+ if (prevStats && prevStats->getContextSize() == size) {
+ if (refinementRegionStats->getContextSize() == size) {
+ refinementRegionStats->copyFrom(prevStats);
+ } else {
+ delete refinementRegionStats;
+ refinementRegionStats = prevStats->copy();
+ }
+ } else {
+ if (refinementRegionStats->getContextSize() == size) {
+ refinementRegionStats->reset();
+ } else {
+ delete refinementRegionStats;
+ refinementRegionStats = new JArithmeticDecoderStats(1 << size);
+ }
+ }
+}
+
+void JBIG2Stream::resetIntStats(int symCodeLen) {
+ iadhStats->reset();
+ iadwStats->reset();
+ iaexStats->reset();
+ iaaiStats->reset();
+ iadtStats->reset();
+ iaitStats->reset();
+ iafsStats->reset();
+ iadsStats->reset();
+ iardxStats->reset();
+ iardyStats->reset();
+ iardwStats->reset();
+ iardhStats->reset();
+ iariStats->reset();
+ if (iaidStats->getContextSize() == 1 << (symCodeLen + 1)) {
+ iaidStats->reset();
+ } else {
+ delete iaidStats;
+ iaidStats = new JArithmeticDecoderStats(1 << (symCodeLen + 1));
+ }
+}
+
+GBool JBIG2Stream::readUByte(Guint *x) {
+ int c0;
+
+ if ((c0 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)c0;
+ return gTrue;
+}
+
+GBool JBIG2Stream::readByte(int *x) {
+ int c0;
+
+ if ((c0 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = c0;
+ if (c0 & 0x80) {
+ *x |= -1 - 0xff;
+ }
+ return gTrue;
+}
+
+GBool JBIG2Stream::readUWord(Guint *x) {
+ int c0, c1;
+
+ if ((c0 = curStr->getChar()) == EOF ||
+ (c1 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)((c0 << 8) | c1);
+ return gTrue;
+}
+
+GBool JBIG2Stream::readULong(Guint *x) {
+ int c0, c1, c2, c3;
+
+ if ((c0 = curStr->getChar()) == EOF ||
+ (c1 = curStr->getChar()) == EOF ||
+ (c2 = curStr->getChar()) == EOF ||
+ (c3 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
+ return gTrue;
+}
+
+GBool JBIG2Stream::readLong(int *x) {
+ int c0, c1, c2, c3;
+
+ if ((c0 = curStr->getChar()) == EOF ||
+ (c1 = curStr->getChar()) == EOF ||
+ (c2 = curStr->getChar()) == EOF ||
+ (c3 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
+ if (c0 & 0x80) {
+ *x |= -1 - (int)0xffffffff;
+ }
+ return gTrue;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/JBIG2Stream.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/JBIG2Stream.h
new file mode 100644
index 00000000000..1e14c5cf783
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/JBIG2Stream.h
@@ -0,0 +1,169 @@
+//========================================================================
+//
+// JBIG2Stream.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2015 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef JBIG2STREAM_H
+#define JBIG2STREAM_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "Object.h"
+#include "Stream.h"
+
+class GooList;
+class JBIG2Segment;
+class JBIG2Bitmap;
+class JArithmeticDecoder;
+class JArithmeticDecoderStats;
+class JBIG2HuffmanDecoder;
+struct JBIG2HuffmanTable;
+class JBIG2MMRDecoder;
+
+//------------------------------------------------------------------------
+
+class JBIG2Stream: public FilterStream {
+public:
+
+ JBIG2Stream(Stream *strA, Object *globalsStreamA, Object *globalsStreamRefA);
+ virtual ~JBIG2Stream();
+ virtual StreamKind getKind() { return strJBIG2; }
+ virtual void reset();
+ virtual void close();
+ virtual Goffset getPos();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+ virtual Object *getGlobalsStream() { return &globalsStream; }
+ virtual Ref getGlobalsStreamRef() { return globalsStreamRef; }
+
+private:
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ void readSegments();
+ GBool readSymbolDictSeg(Guint segNum, Guint length,
+ Guint *refSegs, Guint nRefSegs);
+ void readTextRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs, Guint nRefSegs);
+ JBIG2Bitmap *readTextRegion(GBool huff, GBool refine,
+ int w, int h,
+ Guint numInstances,
+ Guint logStrips,
+ int numSyms,
+ JBIG2HuffmanTable *symCodeTab,
+ Guint symCodeLen,
+ JBIG2Bitmap **syms,
+ Guint defPixel, Guint combOp,
+ Guint transposed, Guint refCorner,
+ int sOffset,
+ JBIG2HuffmanTable *huffFSTable,
+ JBIG2HuffmanTable *huffDSTable,
+ JBIG2HuffmanTable *huffDTTable,
+ JBIG2HuffmanTable *huffRDWTable,
+ JBIG2HuffmanTable *huffRDHTable,
+ JBIG2HuffmanTable *huffRDXTable,
+ JBIG2HuffmanTable *huffRDYTable,
+ JBIG2HuffmanTable *huffRSizeTable,
+ Guint templ,
+ int *atx, int *aty);
+ void readPatternDictSeg(Guint segNum, Guint length);
+ void readHalftoneRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs, Guint nRefSegs);
+ void readGenericRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length);
+ void mmrAddPixels(int a1, int blackPixels,
+ int *codingLine, int *a0i, int w);
+ void mmrAddPixelsNeg(int a1, int blackPixels,
+ int *codingLine, int *a0i, int w);
+ JBIG2Bitmap *readGenericBitmap(GBool mmr, int w, int h,
+ int templ, GBool tpgdOn,
+ GBool useSkip, JBIG2Bitmap *skip,
+ int *atx, int *aty,
+ int mmrDataLength);
+ void readGenericRefinementRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs,
+ Guint nRefSegs);
+ JBIG2Bitmap *readGenericRefinementRegion(int w, int h,
+ int templ, GBool tpgrOn,
+ JBIG2Bitmap *refBitmap,
+ int refDX, int refDY,
+ int *atx, int *aty);
+ void readPageInfoSeg(Guint length);
+ void readEndOfStripeSeg(Guint length);
+ void readProfilesSeg(Guint length);
+ void readCodeTableSeg(Guint segNum, Guint length);
+ void readExtensionSeg(Guint length);
+ JBIG2Segment *findSegment(Guint segNum);
+ void discardSegment(Guint segNum);
+ void resetGenericStats(Guint templ,
+ JArithmeticDecoderStats *prevStats);
+ void resetRefinementStats(Guint templ,
+ JArithmeticDecoderStats *prevStats);
+ void resetIntStats(int symCodeLen);
+ GBool readUByte(Guint *x);
+ GBool readByte(int *x);
+ GBool readUWord(Guint *x);
+ GBool readULong(Guint *x);
+ GBool readLong(int *x);
+
+ Object globalsStream;
+ Ref globalsStreamRef;
+ Guint pageW, pageH, curPageH;
+ Guint pageDefPixel;
+ JBIG2Bitmap *pageBitmap;
+ Guint defCombOp;
+ GooList *segments; // [JBIG2Segment]
+ GooList *globalSegments; // [JBIG2Segment]
+ Stream *curStr;
+ Guchar *dataPtr;
+ Guchar *dataEnd;
+
+ JArithmeticDecoder *arithDecoder;
+ JArithmeticDecoderStats *genericRegionStats;
+ JArithmeticDecoderStats *refinementRegionStats;
+ JArithmeticDecoderStats *iadhStats;
+ JArithmeticDecoderStats *iadwStats;
+ JArithmeticDecoderStats *iaexStats;
+ JArithmeticDecoderStats *iaaiStats;
+ JArithmeticDecoderStats *iadtStats;
+ JArithmeticDecoderStats *iaitStats;
+ JArithmeticDecoderStats *iafsStats;
+ JArithmeticDecoderStats *iadsStats;
+ JArithmeticDecoderStats *iardxStats;
+ JArithmeticDecoderStats *iardyStats;
+ JArithmeticDecoderStats *iardwStats;
+ JArithmeticDecoderStats *iardhStats;
+ JArithmeticDecoderStats *iariStats;
+ JArithmeticDecoderStats *iaidStats;
+ JBIG2HuffmanDecoder *huffDecoder;
+ JBIG2MMRDecoder *mmrDecoder;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/JPEG2000Stream.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/JPEG2000Stream.cc
new file mode 100644
index 00000000000..35e98b86ebc
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/JPEG2000Stream.cc
@@ -0,0 +1,448 @@
+//========================================================================
+//
+// JPEG2000Stream.cc
+//
+// A JPX stream decoder using OpenJPEG
+//
+// Copyright 2008-2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright 2011 Daniel Glöckner <daniel-gl@gmx.net>
+// Copyright 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright 2013, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright 2015 Adam Reichold <adam.reichold@t-online.de>
+//
+// Licensed under GPLv2 or later
+//
+//========================================================================
+
+#include "config.h"
+#include "JPEG2000Stream.h"
+#include <openjpeg.h>
+
+#define OPENJPEG_VERSION_ENCODE(major, minor, micro) ( \
+ ((major) * 10000) \
+ + ((minor) * 100) \
+ + ((micro) * 1))
+
+#ifdef USE_OPENJPEG2
+#ifdef OPJ_VERSION_MAJOR
+#define OPENJPEG_VERSION OPENJPEG_VERSION_ENCODE(OPJ_VERSION_MAJOR, OPJ_VERSION_MINOR, OPJ_VERSION_BUILD)
+#else
+// OpenJPEG started providing version macros in version 2.1.
+// If the version macro is not found, set the version to 2.0.0 and
+// assume there will be no API changes in 2.0.x.
+#define OPENJPEG_VERSION OPENJPEG_VERSION_ENCODE(2, 0, 0)
+#endif
+#endif
+
+struct JPXStreamPrivate {
+ opj_image_t *image;
+ int counter;
+ int ccounter;
+ int npixels;
+ int ncomps;
+ GBool inited;
+#ifdef USE_OPENJPEG1
+ opj_dinfo_t *dinfo;
+ void init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format);
+#endif
+#ifdef USE_OPENJPEG2
+ void init2(OPJ_CODEC_FORMAT format, unsigned char *data, int length);
+#endif
+};
+
+static inline int doLookChar(JPXStreamPrivate* priv) {
+ if (unlikely(priv->counter >= priv->npixels))
+ return EOF;
+
+ return ((unsigned char *)priv->image->comps[priv->ccounter].data)[priv->counter];
+}
+
+static inline int doGetChar(JPXStreamPrivate* priv) {
+ const int result = doLookChar(priv);
+ if (++priv->ccounter == priv->ncomps) {
+ priv->ccounter = 0;
+ ++priv->counter;
+ }
+ return result;
+}
+
+JPXStream::JPXStream(Stream *strA) : FilterStream(strA) {
+ priv = new JPXStreamPrivate;
+ priv->inited = gFalse;
+ priv->image = NULL;
+ priv->npixels = 0;
+ priv->ncomps = 0;
+#ifdef USE_OPENJPEG1
+ priv->dinfo = NULL;
+#endif
+}
+
+JPXStream::~JPXStream() {
+ delete str;
+ close();
+ delete priv;
+}
+
+void JPXStream::reset() {
+ priv->counter = 0;
+ priv->ccounter = 0;
+}
+
+void JPXStream::close() {
+ if (priv->image != NULL) {
+ opj_image_destroy(priv->image);
+ priv->image = NULL;
+ priv->npixels = 0;
+ }
+
+#ifdef USE_OPENJPEG1
+ if (priv->dinfo != NULL) {
+ opj_destroy_decompress(priv->dinfo);
+ priv->dinfo = NULL;
+ }
+#endif
+}
+
+Goffset JPXStream::getPos() {
+ return priv->counter * priv->ncomps + priv->ccounter;
+}
+
+int JPXStream::getChars(int nChars, Guchar *buffer) {
+ if (unlikely(priv->inited == gFalse)) { init(); }
+
+ for (int i = 0; i < nChars; ++i) {
+ const int c = doGetChar(priv);
+ if (likely(c != EOF)) buffer[i] = c;
+ else return i;
+ }
+ return nChars;
+}
+
+int JPXStream::getChar() {
+ if (unlikely(priv->inited == gFalse)) { init(); }
+
+ return doGetChar(priv);
+}
+
+int JPXStream::lookChar() {
+ if (unlikely(priv->inited == gFalse)) { init(); }
+
+ return doLookChar(priv);
+}
+
+GooString *JPXStream::getPSFilter(int psLevel, const char *indent) {
+ return NULL;
+}
+
+GBool JPXStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+void JPXStream::getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode) {
+ if (unlikely(priv->inited == gFalse)) { init(); }
+
+ *bitsPerComponent = 8;
+ if (priv->image && priv->image->numcomps == 3)
+ *csMode = streamCSDeviceRGB;
+ else if (priv->image && priv->image->numcomps == 4)
+ *csMode = streamCSDeviceCMYK;
+ else
+ *csMode = streamCSDeviceGray;
+}
+
+
+static void libopenjpeg_error_callback(const char *msg, void * /*client_data*/) {
+ error(errSyntaxError, -1, "{0:s}", msg);
+}
+
+static void libopenjpeg_warning_callback(const char *msg, void * /*client_data*/) {
+ error(errSyntaxWarning, -1, "{0:s}", msg);
+}
+
+#ifdef USE_OPENJPEG1
+
+#define BUFFER_INITIAL_SIZE 4096
+
+void JPXStream::init()
+{
+ Object oLen;
+ if (getDict()) getDict()->lookup("Length", &oLen);
+
+ int bufSize = BUFFER_INITIAL_SIZE;
+ if (oLen.isInt()) bufSize = oLen.getInt();
+ oLen.free();
+
+ int length = 0;
+ unsigned char *buf = str->toUnsignedChars(&length, bufSize);
+ priv->init2(buf, length, CODEC_JP2);
+ free(buf);
+
+ if (priv->image) {
+ priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h;
+ priv->ncomps = priv->image->numcomps;
+ for (int component = 0; component < priv->ncomps; component++) {
+ if (priv->image->comps[component].data == NULL) {
+ close();
+ break;
+ }
+ unsigned char *cdata = (unsigned char *)priv->image->comps[component].data;
+ int adjust = 0;
+ if (priv->image->comps[component].prec > 8)
+ adjust = priv->image->comps[component].prec - 8;
+ int sgndcorr = 0;
+ if (priv->image->comps[component].sgnd)
+ sgndcorr = 1 << (priv->image->comps[0].prec - 1);
+ for (int i = 0; i < priv->npixels; i++) {
+ int r = priv->image->comps[component].data[i];
+ r += sgndcorr;
+ if (adjust) {
+ r = (r >> adjust)+((r >> (adjust-1))%2);
+ if (unlikely(r > 255))
+ r = 255;
+ }
+ *(cdata++) = r;
+ }
+ }
+ } else
+ priv->npixels = 0;
+
+ priv->counter = 0;
+ priv->ccounter = 0;
+ priv->inited = gTrue;
+}
+
+void JPXStreamPrivate::init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format)
+{
+ opj_cio_t *cio = NULL;
+
+ /* Use default decompression parameters */
+ opj_dparameters_t parameters;
+ opj_set_default_decoder_parameters(&parameters);
+#ifdef WITH_OPENJPEG_IGNORE_PCLR_CMAP_CDEF_FLAG
+ parameters.flags = OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
+#endif
+
+ /* Configure the event manager to receive errors and warnings */
+ opj_event_mgr_t event_mgr;
+ memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
+ event_mgr.error_handler = libopenjpeg_error_callback;
+ event_mgr.warning_handler = libopenjpeg_warning_callback;
+
+ /* Get the decoder handle of the format */
+ dinfo = opj_create_decompress(format);
+ if (dinfo == NULL) goto error;
+ /* Catch events using our callbacks */
+ opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL);
+
+ /* Setup the decoder decoding parameters */
+ opj_setup_decoder(dinfo, &parameters);
+
+ /* Open a byte stream */
+ cio = opj_cio_open((opj_common_ptr)dinfo, buf, bufLen);
+ if (cio == NULL) goto error;
+
+ /* Decode the stream and fill the image structure */
+ image = opj_decode(dinfo, cio);
+
+ /* Close the byte stream */
+ opj_cio_close(cio);
+
+ if (image == NULL) goto error;
+ else return;
+
+error:
+ if (format == CODEC_JP2) {
+ error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as JP2, trying as J2K.");
+ init2(buf, bufLen, CODEC_J2K);
+ } else if (format == CODEC_J2K) {
+ error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as J2K, trying as JPT.");
+ init2(buf, bufLen, CODEC_JPT);
+ } else {
+ error(errSyntaxError, -1, "Did no succeed opening JPX Stream.");
+ }
+}
+#endif
+
+
+#ifdef USE_OPENJPEG2
+typedef struct JPXData_s
+{
+ unsigned char *data;
+ int size;
+ int pos;
+} JPXData;
+
+#define BUFFER_INITIAL_SIZE 4096
+
+static OPJ_SIZE_T jpxRead_callback(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data)
+{
+ JPXData *jpxData = (JPXData *)p_user_data;
+ int len;
+
+ len = jpxData->size - jpxData->pos;
+ if (len < 0)
+ len = 0;
+ if (len == 0)
+ return (OPJ_SIZE_T)-1; /* End of file! */
+ if ((OPJ_SIZE_T)len > p_nb_bytes)
+ len = p_nb_bytes;
+ memcpy(p_buffer, jpxData->data + jpxData->pos, len);
+ jpxData->pos += len;
+ return len;
+}
+
+static OPJ_OFF_T jpxSkip_callback(OPJ_OFF_T skip, void * p_user_data)
+{
+ JPXData *jpxData = (JPXData *)p_user_data;
+
+ jpxData->pos += (skip > jpxData->size - jpxData->pos) ? jpxData->size - jpxData->pos : skip;
+ /* Always return input value to avoid "Problem with skipping JPEG2000 box, stream error" */
+ return skip;
+}
+
+static OPJ_BOOL jpxSeek_callback(OPJ_OFF_T seek_pos, void * p_user_data)
+{
+ JPXData *jpxData = (JPXData *)p_user_data;
+
+ if (seek_pos > jpxData->size)
+ return OPJ_FALSE;
+ jpxData->pos = seek_pos;
+ return OPJ_TRUE;
+}
+
+void JPXStream::init()
+{
+ Object oLen;
+ if (getDict()) getDict()->lookup("Length", &oLen);
+
+ int bufSize = BUFFER_INITIAL_SIZE;
+ if (oLen.isInt()) bufSize = oLen.getInt();
+ oLen.free();
+
+ int length = 0;
+ unsigned char *buf = str->toUnsignedChars(&length, bufSize);
+ priv->init2(OPJ_CODEC_JP2, buf, length);
+ gfree(buf);
+
+ if (priv->image) {
+ priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h;
+ priv->ncomps = priv->image->numcomps;
+ for (int component = 0; component < priv->ncomps; component++) {
+ if (priv->image->comps[component].data == NULL) {
+ close();
+ break;
+ }
+ unsigned char *cdata = (unsigned char *)priv->image->comps[component].data;
+ int adjust = 0;
+ if (priv->image->comps[component].prec > 8)
+ adjust = priv->image->comps[component].prec - 8;
+ int sgndcorr = 0;
+ if (priv->image->comps[component].sgnd)
+ sgndcorr = 1 << (priv->image->comps[0].prec - 1);
+ for (int i = 0; i < priv->npixels; i++) {
+ int r = priv->image->comps[component].data[i];
+ r += sgndcorr;
+ if (adjust) {
+ r = (r >> adjust)+((r >> (adjust-1))%2);
+ if (unlikely(r > 255))
+ r = 255;
+ }
+ *(cdata++) = r;
+ }
+ }
+ } else {
+ priv->npixels = 0;
+ }
+
+ priv->counter = 0;
+ priv->ccounter = 0;
+ priv->inited = gTrue;
+}
+
+void JPXStreamPrivate::init2(OPJ_CODEC_FORMAT format, unsigned char *buf, int length)
+{
+ JPXData jpxData;
+
+ jpxData.data = buf;
+ jpxData.pos = 0;
+ jpxData.size = length;
+
+ opj_stream_t *stream;
+
+ stream = opj_stream_default_create(OPJ_TRUE);
+
+#if OPENJPEG_VERSION >= OPENJPEG_VERSION_ENCODE(2, 1, 0)
+ opj_stream_set_user_data (stream, &jpxData, NULL);
+#else
+ opj_stream_set_user_data (stream, &jpxData);
+#endif
+
+ opj_stream_set_read_function(stream, jpxRead_callback);
+ opj_stream_set_skip_function(stream, jpxSkip_callback);
+ opj_stream_set_seek_function(stream, jpxSeek_callback);
+ /* Set the length to avoid an assert */
+ opj_stream_set_user_data_length(stream, length);
+
+ opj_codec_t *decoder;
+
+ /* Use default decompression parameters */
+ opj_dparameters_t parameters;
+ opj_set_default_decoder_parameters(&parameters);
+ parameters.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
+
+ /* Get the decoder handle of the format */
+ decoder = opj_create_decompress(format);
+ if (decoder == NULL) {
+ error(errSyntaxWarning, -1, "Unable to create decoder");
+ goto error;
+ }
+
+ /* Catch events using our callbacks */
+ opj_set_warning_handler(decoder, libopenjpeg_warning_callback, NULL);
+ opj_set_error_handler(decoder, libopenjpeg_error_callback, NULL);
+
+ /* Setup the decoder decoding parameters */
+ if (!opj_setup_decoder(decoder, &parameters)) {
+ error(errSyntaxWarning, -1, "Unable to set decoder parameters");
+ goto error;
+ }
+
+ /* Decode the stream and fill the image structure */
+ image = NULL;
+ if (!opj_read_header(stream, decoder, &image)) {
+ error(errSyntaxWarning, -1, "Unable to read header");
+ goto error;
+ }
+
+ /* Optional if you want decode the entire image */
+ if (!opj_set_decode_area(decoder, image, parameters.DA_x0,
+ parameters.DA_y0, parameters.DA_x1, parameters.DA_y1)){
+ error(errSyntaxWarning, -1, "X2");
+ goto error;
+ }
+
+ /* Get the decoded image */
+ if (!(opj_decode(decoder, stream, image) && opj_end_decompress(decoder, stream))) {
+ error(errSyntaxWarning, -1, "Unable to decode image");
+ goto error;
+ }
+
+ opj_destroy_codec(decoder);
+ opj_stream_destroy(stream);
+
+ if (image != NULL)
+ return;
+
+error:
+ opj_destroy_codec(decoder);
+ if (format == OPJ_CODEC_JP2) {
+ error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as JP2, trying as J2K.");
+ init2(OPJ_CODEC_J2K, buf, length);
+ } else if (format == OPJ_CODEC_J2K) {
+ error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as J2K, trying as JPT.");
+ init2(OPJ_CODEC_JPT, buf, length);
+ } else {
+ error(errSyntaxError, -1, "Did no succeed opening JPX Stream.");
+ }
+}
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/JPEG2000Stream.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/JPEG2000Stream.h
new file mode 100644
index 00000000000..73b6bdd97b8
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/JPEG2000Stream.h
@@ -0,0 +1,55 @@
+//========================================================================
+//
+// JPEG2000Stream.h
+//
+// A JPX stream decoder using OpenJPEG
+//
+// Copyright 2008, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright 2011 Daniel Glöckner <daniel-gl@gmx.net>
+// Copyright 2013, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright 2015 Adam Reichold <adam.reichold@t-online.de>
+//
+// Licensed under GPLv2 or later
+//
+//========================================================================
+
+
+#ifndef JPEG2000STREAM_H
+#define JPEG2000STREAM_H
+
+#include "config.h"
+#include "goo/gtypes.h"
+#include "Object.h"
+#include "Stream.h"
+
+struct JPXStreamPrivate;
+
+class JPXStream: public FilterStream {
+public:
+
+ JPXStream(Stream *strA);
+ virtual ~JPXStream();
+ virtual StreamKind getKind() { return strJPX; }
+ virtual void reset();
+ virtual void close();
+ virtual Goffset getPos();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+ virtual void getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode);
+
+ int readStream(int nChars, Guchar *buffer) {
+ return str->doGetChars(nChars, buffer);
+ }
+private:
+ JPXStream(const JPXStream &other);
+ JPXStream& operator=(const JPXStream &other);
+ JPXStreamPrivate *priv;
+
+ void init();
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/JPXStream.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/JPXStream.cc
new file mode 100644
index 00000000000..1476e6a0cfe
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/JPXStream.cc
@@ -0,0 +1,3478 @@
+//========================================================================
+//
+// JPXStream.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Even Rouault <even.rouault@mines-paris.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <limits.h>
+#include "gmem.h"
+#include "Error.h"
+#include "JArithmeticDecoder.h"
+#include "JPXStream.h"
+
+//~ to do:
+// - precincts
+// - ROI
+// - progression order changes
+// - packed packet headers
+// - support for palettes, channel maps, etc.
+// - make sure all needed JP2/JPX subboxes are parsed (readBoxes)
+// - can we assume that QCC segments must come after the QCD segment?
+// - handle tilePartToEOC in readTilePartData
+// - progression orders 2, 3, and 4
+// - in coefficient decoding (readCodeBlockData):
+// - selective arithmetic coding bypass
+// (this also affects reading the cb->dataLen array)
+// - coeffs longer than 31 bits (should just ignore the extra bits?)
+// - handle boxes larger than 2^32 bytes
+// - the fixed-point arithmetic won't handle 16-bit pixels
+
+//------------------------------------------------------------------------
+
+// number of contexts for the arithmetic decoder
+#define jpxNContexts 19
+
+#define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup
+#define jpxContextSign 9 // 9 - 13: sign
+#define jpxContextMagRef 14 // 14 -16: magnitude refinement
+#define jpxContextRunLength 17 // cleanup: run length
+#define jpxContextUniform 18 // cleanup: first signif coeff
+
+//------------------------------------------------------------------------
+
+#define jpxPassSigProp 0
+#define jpxPassMagRef 1
+#define jpxPassCleanup 2
+
+//------------------------------------------------------------------------
+
+// arithmetic decoder context for the significance propagation and
+// cleanup passes:
+// [horiz][vert][diag][subband]
+// where subband = 0 for HL
+// = 1 for LH and LL
+// = 2 for HH
+static const Guint sigPropContext[3][3][5][3] = {
+ {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0
+ { 1, 1, 3 }, // horiz=0, vert=0, diag=1
+ { 2, 2, 6 }, // horiz=0, vert=0, diag=2
+ { 2, 2, 8 }, // horiz=0, vert=0, diag=3
+ { 2, 2, 8 }}, // horiz=0, vert=0, diag=4
+ {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0
+ { 6, 3, 4 }, // horiz=0, vert=1, diag=1
+ { 6, 3, 7 }, // horiz=0, vert=1, diag=2
+ { 6, 3, 8 }, // horiz=0, vert=1, diag=3
+ { 6, 3, 8 }}, // horiz=0, vert=1, diag=4
+ {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0
+ { 8, 4, 5 }, // horiz=0, vert=2, diag=1
+ { 8, 4, 7 }, // horiz=0, vert=2, diag=2
+ { 8, 4, 8 }, // horiz=0, vert=2, diag=3
+ { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4
+ {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0
+ { 3, 6, 4 }, // horiz=1, vert=0, diag=1
+ { 3, 6, 7 }, // horiz=1, vert=0, diag=2
+ { 3, 6, 8 }, // horiz=1, vert=0, diag=3
+ { 3, 6, 8 }}, // horiz=1, vert=0, diag=4
+ {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0
+ { 7, 7, 5 }, // horiz=1, vert=1, diag=1
+ { 7, 7, 7 }, // horiz=1, vert=1, diag=2
+ { 7, 7, 8 }, // horiz=1, vert=1, diag=3
+ { 7, 7, 8 }}, // horiz=1, vert=1, diag=4
+ {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0
+ { 8, 7, 5 }, // horiz=1, vert=2, diag=1
+ { 8, 7, 7 }, // horiz=1, vert=2, diag=2
+ { 8, 7, 8 }, // horiz=1, vert=2, diag=3
+ { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4
+ {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0
+ { 4, 8, 5 }, // horiz=2, vert=0, diag=1
+ { 4, 8, 7 }, // horiz=2, vert=0, diag=2
+ { 4, 8, 8 }, // horiz=2, vert=0, diag=3
+ { 4, 8, 8 }}, // horiz=2, vert=0, diag=4
+ {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0
+ { 7, 8, 5 }, // horiz=2, vert=1, diag=1
+ { 7, 8, 7 }, // horiz=2, vert=1, diag=2
+ { 7, 8, 8 }, // horiz=2, vert=1, diag=3
+ { 7, 8, 8 }}, // horiz=2, vert=1, diag=4
+ {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0
+ { 8, 8, 5 }, // horiz=2, vert=2, diag=1
+ { 8, 8, 7 }, // horiz=2, vert=2, diag=2
+ { 8, 8, 8 }, // horiz=2, vert=2, diag=3
+ { 8, 8, 8 }}} // horiz=2, vert=2, diag=4
+};
+
+// arithmetic decoder context and xor bit for the sign bit in the
+// significance propagation pass:
+// [horiz][vert][k]
+// where horiz/vert are offset by 2 (i.e., range is -2 .. 2)
+// and k = 0 for the context
+// = 1 for the xor bit
+static const Guint signContext[5][5][2] = {
+ {{ 13, 1 }, // horiz=-2, vert=-2
+ { 13, 1 }, // horiz=-2, vert=-1
+ { 12, 1 }, // horiz=-2, vert= 0
+ { 11, 1 }, // horiz=-2, vert=+1
+ { 11, 1 }}, // horiz=-2, vert=+2
+ {{ 13, 1 }, // horiz=-1, vert=-2
+ { 13, 1 }, // horiz=-1, vert=-1
+ { 12, 1 }, // horiz=-1, vert= 0
+ { 11, 1 }, // horiz=-1, vert=+1
+ { 11, 1 }}, // horiz=-1, vert=+2
+ {{ 10, 1 }, // horiz= 0, vert=-2
+ { 10, 1 }, // horiz= 0, vert=-1
+ { 9, 0 }, // horiz= 0, vert= 0
+ { 10, 0 }, // horiz= 0, vert=+1
+ { 10, 0 }}, // horiz= 0, vert=+2
+ {{ 11, 0 }, // horiz=+1, vert=-2
+ { 11, 0 }, // horiz=+1, vert=-1
+ { 12, 0 }, // horiz=+1, vert= 0
+ { 13, 0 }, // horiz=+1, vert=+1
+ { 13, 0 }}, // horiz=+1, vert=+2
+ {{ 11, 0 }, // horiz=+2, vert=-2
+ { 11, 0 }, // horiz=+2, vert=-1
+ { 12, 0 }, // horiz=+2, vert= 0
+ { 13, 0 }, // horiz=+2, vert=+1
+ { 13, 0 }}, // horiz=+2, vert=+2
+};
+
+//------------------------------------------------------------------------
+
+// constants used in the IDWT
+#define idwtAlpha -1.586134342059924
+#define idwtBeta -0.052980118572961
+#define idwtGamma 0.882911075530934
+#define idwtDelta 0.443506852043971
+#define idwtKappa 1.230174104914001
+#define idwtIKappa (1.0 / idwtKappa)
+
+// number of bits to the right of the decimal point for the fixed
+// point arithmetic used in the IDWT
+#define fracBits 16
+
+//------------------------------------------------------------------------
+
+// floor(x / y)
+#define jpxFloorDiv(x, y) ((x) / (y))
+
+// floor(x / 2^y)
+#define jpxFloorDivPow2(x, y) ((x) >> (y))
+
+// ceil(x / y)
+#define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y))
+
+// ceil(x / 2^y)
+#define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y))
+
+//------------------------------------------------------------------------
+
+#if 1 //----- disable coverage tracking
+
+#define cover(idx)
+
+#else //----- enable coverage tracking
+
+class JPXCover {
+public:
+
+ JPXCover(int sizeA);
+ ~JPXCover();
+ void incr(int idx);
+
+private:
+
+ int size, used;
+ int *data;
+};
+
+JPXCover::JPXCover(int sizeA) {
+ size = sizeA;
+ used = -1;
+ data = (int *)gmallocn(size, sizeof(int));
+ memset(data, 0, size * sizeof(int));
+}
+
+JPXCover::~JPXCover() {
+ int i;
+
+ printf("JPX coverage:\n");
+ for (i = 0; i <= used; ++i) {
+ printf(" %4d: %8d\n", i, data[i]);
+ }
+ gfree(data);
+}
+
+void JPXCover::incr(int idx) {
+ if (idx < size) {
+ ++data[idx];
+ if (idx > used) {
+ used = idx;
+ }
+ }
+}
+
+JPXCover jpxCover(150);
+
+#define cover(idx) jpxCover.incr(idx)
+
+#endif //----- coverage tracking
+
+//------------------------------------------------------------------------
+
+JPXStream::JPXStream(Stream *strA):
+ FilterStream(strA)
+{
+ bufStr = new BufStream(str, 2);
+
+ nComps = 0;
+ bpc = NULL;
+ width = height = 0;
+ haveCS = gFalse;
+ havePalette = gFalse;
+ haveCompMap = gFalse;
+ haveChannelDefn = gFalse;
+
+ img.tiles = NULL;
+ bitBuf = 0;
+ bitBufLen = 0;
+ bitBufSkip = gFalse;
+ byteCount = 0;
+
+ curX = curY = 0;
+ curComp = 0;
+ readBufLen = 0;
+}
+
+JPXStream::~JPXStream() {
+ close();
+ delete bufStr;
+}
+
+void JPXStream::reset() {
+ bufStr->reset();
+ if (readBoxes()) {
+ curY = img.yOffset;
+ } else {
+ // readBoxes reported an error, so we go immediately to EOF
+ curY = img.ySize;
+ }
+ curX = img.xOffset;
+ curComp = 0;
+ readBufLen = 0;
+}
+
+void JPXStream::close() {
+ JPXTile *tile;
+ JPXTileComp *tileComp;
+ JPXResLevel *resLevel;
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ Guint comp, i, k, r, pre, sb;
+
+ gfree(bpc);
+ bpc = NULL;
+ if (havePalette) {
+ gfree(palette.bpc);
+ gfree(palette.c);
+ havePalette = gFalse;
+ }
+ if (haveCompMap) {
+ gfree(compMap.comp);
+ gfree(compMap.type);
+ gfree(compMap.pComp);
+ haveCompMap = gFalse;
+ }
+ if (haveChannelDefn) {
+ gfree(channelDefn.idx);
+ gfree(channelDefn.type);
+ gfree(channelDefn.assoc);
+ haveChannelDefn = gFalse;
+ }
+
+ if (img.tiles) {
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ tile = &img.tiles[i];
+ if (tile->tileComps) {
+ for (comp = 0; comp < img.nComps; ++comp) {
+ tileComp = &tile->tileComps[comp];
+ gfree(tileComp->quantSteps);
+ gfree(tileComp->data);
+ gfree(tileComp->buf);
+ if (tileComp->resLevels) {
+ for (r = 0; r <= tileComp->nDecompLevels; ++r) {
+ resLevel = &tileComp->resLevels[r];
+ if (resLevel->precincts) {
+ for (pre = 0; pre < 1; ++pre) {
+ precinct = &resLevel->precincts[pre];
+ if (precinct->subbands) {
+ for (sb = 0; sb < (Guint)(r == 0 ? 1 : 3); ++sb) {
+ subband = &precinct->subbands[sb];
+ gfree(subband->inclusion);
+ gfree(subband->zeroBitPlane);
+ if (subband->cbs) {
+ for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
+ cb = &subband->cbs[k];
+ gfree(cb->dataLen);
+ gfree(cb->touched);
+ if (cb->arithDecoder) {
+ delete cb->arithDecoder;
+ }
+ if (cb->stats) {
+ delete cb->stats;
+ }
+ }
+ gfree(subband->cbs);
+ }
+ }
+ gfree(precinct->subbands);
+ }
+ }
+ gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts);
+ }
+ }
+ gfree(img.tiles[i].tileComps[comp].resLevels);
+ }
+ }
+ gfree(img.tiles[i].tileComps);
+ }
+ }
+ gfree(img.tiles);
+ img.tiles = NULL;
+ }
+ bufStr->close();
+}
+
+int JPXStream::getChar() {
+ int c;
+
+ if (readBufLen < 8) {
+ fillReadBuf();
+ }
+ if (readBufLen == 8) {
+ c = readBuf & 0xff;
+ readBufLen = 0;
+ } else if (readBufLen > 8) {
+ c = (readBuf >> (readBufLen - 8)) & 0xff;
+ readBufLen -= 8;
+ } else if (readBufLen == 0) {
+ c = EOF;
+ } else {
+ c = (readBuf << (8 - readBufLen)) & 0xff;
+ readBufLen = 0;
+ }
+ return c;
+}
+
+int JPXStream::lookChar() {
+ int c;
+
+ if (readBufLen < 8) {
+ fillReadBuf();
+ }
+ if (readBufLen == 8) {
+ c = readBuf & 0xff;
+ } else if (readBufLen > 8) {
+ c = (readBuf >> (readBufLen - 8)) & 0xff;
+ } else if (readBufLen == 0) {
+ c = EOF;
+ } else {
+ c = (readBuf << (8 - readBufLen)) & 0xff;
+ }
+ return c;
+}
+
+void JPXStream::fillReadBuf() {
+ JPXTileComp *tileComp;
+ Guint tileIdx, tx, ty;
+ int pix, pixBits;
+
+ do {
+ if (curY >= img.ySize) {
+ return;
+ }
+ tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles
+ + (curX - img.xTileOffset) / img.xTileSize;
+#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
+ if (img.tiles == NULL || tileIdx >= img.nXTiles * img.nYTiles || img.tiles[tileIdx].tileComps == NULL) {
+ error(errSyntaxError, getPos(), "Unexpected tileIdx in fillReadBuf in JPX stream");
+ return;
+ }
+ tileComp = &img.tiles[tileIdx].tileComps[curComp];
+#else
+ tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp];
+#endif
+ tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep);
+ ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep);
+ if (unlikely(ty >= (tileComp->y1 - tileComp->y0))) {
+ error(errSyntaxError, getPos(), "Unexpected ty in fillReadBuf in JPX stream");
+ return;
+ }
+ if (unlikely(tx >= (tileComp->x1 - tileComp->x0))) {
+ error(errSyntaxError, getPos(), "Unexpected tx in fillReadBuf in JPX stream");
+ return;
+ }
+ pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx];
+ pixBits = tileComp->prec;
+#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
+ if (++curComp == img.nComps) {
+#else
+ if (havePalette) {
+ if (pix >= 0 && pix < palette.nEntries) {
+ pix = palette.c[pix * palette.nComps + curComp];
+ } else {
+ pix = 0;
+ }
+ pixBits = palette.bpc[curComp];
+ }
+ if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) {
+#endif
+ curComp = 0;
+ if (++curX == img.xSize) {
+ curX = img.xOffset;
+ ++curY;
+ if (pixBits < 8) {
+ pix <<= 8 - pixBits;
+ pixBits = 8;
+ }
+ }
+ }
+ if (pixBits == 8) {
+ readBuf = (readBuf << 8) | (pix & 0xff);
+ } else {
+ readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1));
+ }
+ readBufLen += pixBits;
+ } while (readBufLen < 8);
+}
+
+GooString *JPXStream::getPSFilter(int psLevel, const char *indent) {
+ return NULL;
+}
+
+GBool JPXStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+void JPXStream::getImageParams(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode) {
+ Guint boxType, boxLen, dataLen, csEnum;
+ Guint bpc1, dummy, i;
+ int csMeth, csPrec, csPrec1, dummy2;
+ StreamColorSpaceMode csMode1;
+ GBool haveBPC, haveCSMode;
+
+ csPrec = 0; // make gcc happy
+ haveBPC = haveCSMode = gFalse;
+ bufStr->reset();
+ if (bufStr->lookChar() == 0xff) {
+ getImageParams2(bitsPerComponent, csMode);
+ } else {
+ while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
+ if (boxType == 0x6a703268) { // JP2 header
+ cover(0);
+ // skip the superbox
+ } else if (boxType == 0x69686472) { // image header
+ cover(1);
+ if (readULong(&dummy) &&
+ readULong(&dummy) &&
+ readUWord(&dummy) &&
+ readUByte(&bpc1) &&
+ readUByte(&dummy) &&
+ readUByte(&dummy) &&
+ readUByte(&dummy)) {
+ *bitsPerComponent = bpc1 + 1;
+ haveBPC = gTrue;
+ }
+ } else if (boxType == 0x636F6C72) { // color specification
+ cover(2);
+ if (readByte(&csMeth) &&
+ readByte(&csPrec1) &&
+ readByte(&dummy2)) {
+ if (csMeth == 1) {
+ if (readULong(&csEnum)) {
+ csMode1 = streamCSNone;
+ if (csEnum == jpxCSBiLevel ||
+ csEnum == jpxCSGrayscale) {
+ csMode1 = streamCSDeviceGray;
+ } else if (csEnum == jpxCSCMYK) {
+ csMode1 = streamCSDeviceCMYK;
+ } else if (csEnum == jpxCSsRGB ||
+ csEnum == jpxCSCISesRGB ||
+ csEnum == jpxCSROMMRGB) {
+ csMode1 = streamCSDeviceRGB;
+ }
+ if (csMode1 != streamCSNone &&
+ (!haveCSMode || csPrec1 > csPrec)) {
+ *csMode = csMode1;
+ csPrec = csPrec1;
+ haveCSMode = gTrue;
+ }
+ if( dataLen >= 7 ) {
+ for (i = 0; i < dataLen - 7; ++i) {
+ if (bufStr->getChar() == EOF)
+ break;
+ }
+ }
+ }
+ } else {
+ if( dataLen >= 3 ) {
+ for (i = 0; i < dataLen - 3; ++i) {
+ if (bufStr->getChar() == EOF)
+ break;
+ }
+ }
+ }
+ }
+ } else if (boxType == 0x6A703263) { // codestream
+ cover(3);
+ if (!(haveBPC && haveCSMode)) {
+ getImageParams2(bitsPerComponent, csMode);
+ }
+ break;
+ } else {
+ cover(4);
+ for (i = 0; i < dataLen; ++i) {
+ if (unlikely(bufStr->getChar() == EOF)) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in getImageParams in JPX stream");
+ break;
+ }
+ }
+ }
+ }
+ }
+ bufStr->close();
+}
+
+// Get image parameters from the codestream.
+void JPXStream::getImageParams2(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode) {
+ int segType;
+ Guint segLen, nComps1, bpc1, dummy, i;
+
+ while (readMarkerHdr(&segType, &segLen)) {
+ if (segType == 0x51) { // SIZ - image and tile size
+ cover(5);
+ if (readUWord(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readUWord(&nComps1) &&
+ readUByte(&bpc1)) {
+ *bitsPerComponent = (bpc1 & 0x7f) + 1;
+ // if there's no color space info, take a guess
+ if (nComps1 == 1) {
+ *csMode = streamCSDeviceGray;
+ } else if (nComps1 == 3) {
+ *csMode = streamCSDeviceRGB;
+ } else if (nComps1 == 4) {
+ *csMode = streamCSDeviceCMYK;
+ }
+ }
+ break;
+ } else {
+ cover(6);
+ if (segLen > 2) {
+ for (i = 0; i < segLen - 2; ++i) {
+ bufStr->getChar();
+ }
+ }
+ }
+ }
+}
+
+GBool JPXStream::readBoxes() {
+ Guint boxType, boxLen, dataLen;
+ Guint bpc1, compression, unknownColorspace, ipr;
+ Guint i, j;
+
+ haveImgHdr = gFalse;
+
+ // initialize in case there is a parse error
+ img.xSize = img.ySize = 0;
+ img.xOffset = img.yOffset = 0;
+ img.xTileSize = img.yTileSize = 0;
+ img.xTileOffset = img.yTileOffset = 0;
+ img.nComps = 0;
+
+ // check for a naked JPEG 2000 codestream (without the JP2/JPX
+ // wrapper) -- this appears to be a violation of the PDF spec, but
+ // Acrobat allows it
+ if (bufStr->lookChar() == 0xff) {
+ cover(7);
+ error(errSyntaxWarning, getPos(),
+ "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
+ if (!readCodestream(0)) {
+ return gFalse;
+ }
+ nComps = img.nComps;
+ bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
+ for (i = 0; i < nComps; ++i) {
+ bpc[i] = img.tiles[0].tileComps[i].prec;
+ }
+ width = img.xSize - img.xOffset;
+ height = img.ySize - img.yOffset;
+ return gTrue;
+ }
+
+ while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
+ switch (boxType) {
+ case 0x6a703268: // JP2 header
+ // this is a grouping box ('superbox') which has no real
+ // contents and doesn't appear to be used consistently, i.e.,
+ // some things which should be subboxes of the JP2 header box
+ // show up outside of it - so we simply ignore the JP2 header
+ // box
+ cover(8);
+ break;
+ case 0x69686472: // image header
+ cover(9);
+ if (!readULong(&height) ||
+ !readULong(&width) ||
+ !readUWord(&nComps) ||
+ !readUByte(&bpc1) ||
+ !readUByte(&compression) ||
+ !readUByte(&unknownColorspace) ||
+ !readUByte(&ipr)) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ if (compression != 7) {
+ error(errSyntaxError, getPos(),
+ "Unknown compression type in JPX stream");
+ return gFalse;
+ }
+ bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
+ for (i = 0; i < nComps; ++i) {
+ bpc[i] = bpc1;
+ }
+ haveImgHdr = gTrue;
+ break;
+ case 0x62706363: // bits per component
+ cover(10);
+ if (!haveImgHdr) {
+ error(errSyntaxError, getPos(),
+ "Found bits per component box before image header box in JPX stream");
+ return gFalse;
+ }
+ if (dataLen != nComps) {
+ error(errSyntaxError, getPos(),
+ "Invalid bits per component box in JPX stream");
+ return gFalse;
+ }
+ for (i = 0; i < nComps; ++i) {
+ if (!readUByte(&bpc[i])) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x636F6C72: // color specification
+ cover(11);
+ if (!readColorSpecBox(dataLen)) {
+ return gFalse;
+ }
+ break;
+ case 0x70636c72: // palette
+ cover(12);
+ if (!readUWord(&palette.nEntries) ||
+ !readUByte(&palette.nComps)) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint));
+ palette.c =
+ (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int));
+ for (i = 0; i < palette.nComps; ++i) {
+ if (!readUByte(&palette.bpc[i])) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ ++palette.bpc[i];
+ }
+ for (i = 0; i < palette.nEntries; ++i) {
+ for (j = 0; j < palette.nComps; ++j) {
+ if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3,
+ (palette.bpc[j] & 0x80) ? gTrue : gFalse,
+ &palette.c[i * palette.nComps + j])) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ }
+ havePalette = gTrue;
+ break;
+ case 0x636d6170: // component mapping
+ cover(13);
+ compMap.nChannels = dataLen / 4;
+ compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+ compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+ compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+ for (i = 0; i < compMap.nChannels; ++i) {
+ if (!readUWord(&compMap.comp[i]) ||
+ !readUByte(&compMap.type[i]) ||
+ !readUByte(&compMap.pComp[i])) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ haveCompMap = gTrue;
+ break;
+ case 0x63646566: // channel definition
+ cover(14);
+ if (!readUWord(&channelDefn.nChannels)) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ channelDefn.idx =
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
+ channelDefn.type =
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
+ channelDefn.assoc =
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
+ for (i = 0; i < channelDefn.nChannels; ++i) {
+ if (!readUWord(&channelDefn.idx[i]) ||
+ !readUWord(&channelDefn.type[i]) ||
+ !readUWord(&channelDefn.assoc[i])) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ haveChannelDefn = gTrue;
+ break;
+ case 0x6A703263: // contiguous codestream
+ cover(15);
+ if (!bpc) {
+ error(errSyntaxError, getPos(),
+ "JPX stream is missing the image header box");
+ }
+ if (!haveCS) {
+ error(errSyntaxError, getPos(),
+ "JPX stream has no supported color spec");
+ }
+ if (!readCodestream(dataLen)) {
+ return gFalse;
+ }
+ break;
+ default:
+ cover(16);
+ for (i = 0; i < dataLen; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ break;
+ }
+ }
+ return gTrue;
+}
+
+GBool JPXStream::readColorSpecBox(Guint dataLen) {
+ JPXColorSpec newCS;
+ Guint csApprox, csEnum;
+ Guint i;
+ GBool ok;
+
+ ok = gFalse;
+ if (!readUByte(&newCS.meth) ||
+ !readByte(&newCS.prec) ||
+ !readUByte(&csApprox)) {
+ goto err;
+ }
+ switch (newCS.meth) {
+ case 1: // enumerated colorspace
+ cover(17);
+ if (!readULong(&csEnum)) {
+ goto err;
+ }
+ newCS.enumerated.type = (JPXColorSpaceType)csEnum;
+ switch (newCS.enumerated.type) {
+ case jpxCSBiLevel:
+ ok = gTrue;
+ break;
+ case jpxCSYCbCr1:
+ ok = gTrue;
+ break;
+ case jpxCSYCbCr2:
+ ok = gTrue;
+ break;
+ case jpxCSYCBCr3:
+ ok = gTrue;
+ break;
+ case jpxCSPhotoYCC:
+ ok = gTrue;
+ break;
+ case jpxCSCMY:
+ ok = gTrue;
+ break;
+ case jpxCSCMYK:
+ ok = gTrue;
+ break;
+ case jpxCSYCCK:
+ ok = gTrue;
+ break;
+ case jpxCSCIELab:
+ if (dataLen == 7 + 7*4) {
+ if (!readULong(&newCS.enumerated.cieLab.rl) ||
+ !readULong(&newCS.enumerated.cieLab.ol) ||
+ !readULong(&newCS.enumerated.cieLab.ra) ||
+ !readULong(&newCS.enumerated.cieLab.oa) ||
+ !readULong(&newCS.enumerated.cieLab.rb) ||
+ !readULong(&newCS.enumerated.cieLab.ob) ||
+ !readULong(&newCS.enumerated.cieLab.il)) {
+ goto err;
+ }
+ } else if (dataLen == 7) {
+ //~ this assumes the 8-bit case
+ cover(92);
+ newCS.enumerated.cieLab.rl = 100;
+ newCS.enumerated.cieLab.ol = 0;
+ newCS.enumerated.cieLab.ra = 255;
+ newCS.enumerated.cieLab.oa = 128;
+ newCS.enumerated.cieLab.rb = 255;
+ newCS.enumerated.cieLab.ob = 96;
+ newCS.enumerated.cieLab.il = 0x00443530;
+ } else {
+ goto err;
+ }
+ ok = gTrue;
+ break;
+ case jpxCSsRGB:
+ ok = gTrue;
+ break;
+ case jpxCSGrayscale:
+ ok = gTrue;
+ break;
+ case jpxCSBiLevel2:
+ ok = gTrue;
+ break;
+ case jpxCSCIEJab:
+ // not allowed in PDF
+ goto err;
+ case jpxCSCISesRGB:
+ ok = gTrue;
+ break;
+ case jpxCSROMMRGB:
+ ok = gTrue;
+ break;
+ case jpxCSsRGBYCbCr:
+ ok = gTrue;
+ break;
+ case jpxCSYPbPr1125:
+ ok = gTrue;
+ break;
+ case jpxCSYPbPr1250:
+ ok = gTrue;
+ break;
+ default:
+ goto err;
+ }
+ break;
+ case 2: // restricted ICC profile
+ case 3: // any ICC profile (JPX)
+ case 4: // vendor color (JPX)
+ cover(18);
+ for (i = 0; i < dataLen - 3; ++i) {
+ if (bufStr->getChar() == EOF) {
+ goto err;
+ }
+ }
+ break;
+ }
+
+ if (ok && (!haveCS || newCS.prec > cs.prec)) {
+ cs = newCS;
+ haveCS = gTrue;
+ }
+
+ return gTrue;
+
+ err:
+ error(errSyntaxError, getPos(), "Error in JPX color spec");
+ return gFalse;
+}
+
+GBool JPXStream::readCodestream(Guint len) {
+ JPXTile *tile;
+ JPXTileComp *tileComp;
+ int segType;
+ GBool haveSIZ, haveCOD, haveQCD, haveSOT;
+ Guint precinctSize, style, nDecompLevels;
+ Guint segLen, capabilities, comp, i, j, r;
+
+ //----- main header
+ haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
+ do {
+ if (!readMarkerHdr(&segType, &segLen)) {
+ error(errSyntaxError, getPos(), "Error in JPX codestream");
+ return gFalse;
+ }
+ switch (segType) {
+ case 0x4f: // SOC - start of codestream
+ // marker only
+ cover(19);
+ break;
+ case 0x51: // SIZ - image and tile size
+ cover(20);
+ if (haveSIZ) {
+ error(errSyntaxError, getPos(),
+ "Duplicate SIZ marker segment in JPX stream");
+ return gFalse;
+ }
+ if (!readUWord(&capabilities) ||
+ !readULong(&img.xSize) ||
+ !readULong(&img.ySize) ||
+ !readULong(&img.xOffset) ||
+ !readULong(&img.yOffset) ||
+ !readULong(&img.xTileSize) ||
+ !readULong(&img.yTileSize) ||
+ !readULong(&img.xTileOffset) ||
+ !readULong(&img.yTileOffset) ||
+ !readUWord(&img.nComps)) {
+ error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment");
+ return gFalse;
+ }
+ if (haveImgHdr && img.nComps != nComps) {
+ error(errSyntaxError, getPos(),
+ "Different number of components in JPX SIZ marker segment");
+ return gFalse;
+ }
+ if (img.xSize == 0 || img.ySize == 0 ||
+ img.xOffset >= img.xSize || img.yOffset >= img.ySize ||
+ img.xTileSize == 0 || img.yTileSize == 0 ||
+ img.xTileOffset > img.xOffset ||
+ img.yTileOffset > img.yOffset ||
+ img.xTileSize + img.xTileOffset <= img.xOffset ||
+ img.yTileSize + img.yTileOffset <= img.yOffset) {
+ error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment");
+ return gFalse;
+ }
+ img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1)
+ / img.xTileSize;
+ img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
+ / img.yTileSize;
+ // check for overflow before allocating memory
+ if (img.nXTiles <= 0 || img.nYTiles <= 0 ||
+ img.nXTiles >= 65535 / img.nYTiles) {
+ error(errSyntaxError, getPos(),
+ "Bad tile count in JPX SIZ marker segment");
+ return gFalse;
+ }
+ img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles,
+ sizeof(JPXTile));
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ img.tiles[i].init = gFalse;
+ img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps,
+ sizeof(JPXTileComp));
+ for (comp = 0; comp < img.nComps; ++comp) {
+ img.tiles[i].tileComps[comp].quantSteps = NULL;
+ img.tiles[i].tileComps[comp].data = NULL;
+ img.tiles[i].tileComps[comp].buf = NULL;
+ img.tiles[i].tileComps[comp].resLevels = NULL;
+ }
+ }
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (!readUByte(&img.tiles[0].tileComps[comp].prec) ||
+ !readUByte(&img.tiles[0].tileComps[comp].hSep) ||
+ !readUByte(&img.tiles[0].tileComps[comp].vSep)) {
+ error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment");
+ return gFalse;
+ }
+ if (img.tiles[0].tileComps[comp].hSep == 0 ||
+ img.tiles[0].tileComps[comp].vSep == 0) {
+ error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[comp].sgned =
+ (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse;
+ img.tiles[0].tileComps[comp].prec =
+ (img.tiles[0].tileComps[comp].prec & 0x7f) + 1;
+ for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
+ img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp];
+ }
+ }
+ haveSIZ = gTrue;
+ break;
+ case 0x52: // COD - coding style default
+ cover(21);
+ if (!haveSIZ) {
+ error(errSyntaxError, getPos(),
+ "JPX COD marker segment before SIZ segment");
+ return gFalse;
+ }
+ if (img.tiles == NULL || img.nXTiles * img.nYTiles == 0 || img.tiles[0].tileComps == NULL) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ if (!readUByte(&img.tiles[0].tileComps[0].style) ||
+ !readUByte(&img.tiles[0].progOrder) ||
+ !readUWord(&img.tiles[0].nLayers) ||
+ !readUByte(&img.tiles[0].multiComp) ||
+ !readUByte(&nDecompLevels) ||
+ !readUByte(&img.tiles[0].tileComps[0].codeBlockW) ||
+ !readUByte(&img.tiles[0].tileComps[0].codeBlockH) ||
+ !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) ||
+ !readUByte(&img.tiles[0].tileComps[0].transform)) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ if (nDecompLevels > 32 ||
+ img.tiles[0].tileComps[0].codeBlockW > 8 ||
+ img.tiles[0].tileComps[0].codeBlockH > 8) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[0].nDecompLevels = nDecompLevels;
+ img.tiles[0].tileComps[0].codeBlockW += 2;
+ img.tiles[0].tileComps[0].codeBlockH += 2;
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ if (i != 0) {
+ img.tiles[i].progOrder = img.tiles[0].progOrder;
+ img.tiles[i].nLayers = img.tiles[0].nLayers;
+ img.tiles[i].multiComp = img.tiles[0].multiComp;
+ }
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (!(i == 0 && comp == 0)) {
+ img.tiles[i].tileComps[comp].style =
+ img.tiles[0].tileComps[0].style;
+ img.tiles[i].tileComps[comp].nDecompLevels =
+ img.tiles[0].tileComps[0].nDecompLevels;
+ img.tiles[i].tileComps[comp].codeBlockW =
+ img.tiles[0].tileComps[0].codeBlockW;
+ img.tiles[i].tileComps[comp].codeBlockH =
+ img.tiles[0].tileComps[0].codeBlockH;
+ img.tiles[i].tileComps[comp].codeBlockStyle =
+ img.tiles[0].tileComps[0].codeBlockStyle;
+ img.tiles[i].tileComps[comp].transform =
+ img.tiles[0].tileComps[0].transform;
+ }
+ img.tiles[i].tileComps[comp].resLevels =
+ (JPXResLevel *)gmallocn_checkoverflow(
+ (img.tiles[i].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
+ if (img.tiles[i].tileComps[comp].resLevels == NULL) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
+ }
+ }
+ }
+ for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) {
+ if (img.tiles[0].tileComps[0].style & 0x01) {
+ cover(91);
+ if (!readUByte(&precinctSize)) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[0].resLevels[r].precinctWidth =
+ precinctSize & 0x0f;
+ img.tiles[0].tileComps[0].resLevels[r].precinctHeight =
+ (precinctSize >> 4) & 0x0f;
+ } else {
+ img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15;
+ img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15;
+ }
+ }
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (!(i == 0 && comp == 0)) {
+ for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
+ img.tiles[0].tileComps[0].resLevels[r].precinctWidth;
+ img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
+ img.tiles[0].tileComps[0].resLevels[r].precinctHeight;
+ }
+ }
+ }
+ }
+ haveCOD = gTrue;
+ break;
+ case 0x53: // COC - coding style component
+ cover(22);
+ if (!haveCOD) {
+ error(errSyntaxError, getPos(),
+ "JPX COC marker segment before COD segment");
+ return gFalse;
+ }
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&style) ||
+ !readUByte(&nDecompLevels) ||
+ !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) ||
+ !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) ||
+ !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) ||
+ !readUByte(&img.tiles[0].tileComps[comp].transform)) {
+ error(errSyntaxError, getPos(), "Error in JPX COC marker segment");
+ return gFalse;
+ }
+ if (nDecompLevels > 32 ||
+ img.tiles[0].tileComps[comp].codeBlockW > 8 ||
+ img.tiles[0].tileComps[comp].codeBlockH > 8) {
+ error(errSyntaxError, getPos(), "Error in JPX COC marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[comp].nDecompLevels = nDecompLevels;
+ img.tiles[0].tileComps[comp].style =
+ (img.tiles[0].tileComps[comp].style & ~1) | (style & 1);
+ img.tiles[0].tileComps[comp].codeBlockW += 2;
+ img.tiles[0].tileComps[comp].codeBlockH += 2;
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ if (i != 0) {
+ img.tiles[i].tileComps[comp].style =
+ img.tiles[0].tileComps[comp].style;
+ img.tiles[i].tileComps[comp].nDecompLevels =
+ img.tiles[0].tileComps[comp].nDecompLevels;
+ img.tiles[i].tileComps[comp].codeBlockW =
+ img.tiles[0].tileComps[comp].codeBlockW;
+ img.tiles[i].tileComps[comp].codeBlockH =
+ img.tiles[0].tileComps[comp].codeBlockH;
+ img.tiles[i].tileComps[comp].codeBlockStyle =
+ img.tiles[0].tileComps[comp].codeBlockStyle;
+ img.tiles[i].tileComps[comp].transform =
+ img.tiles[0].tileComps[comp].transform;
+ }
+ img.tiles[i].tileComps[comp].resLevels =
+ (JPXResLevel *)greallocn(
+ img.tiles[i].tileComps[comp].resLevels,
+ (img.tiles[i].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
+ for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
+ }
+ }
+ for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) {
+ if (img.tiles[0].tileComps[comp].style & 0x01) {
+ if (!readUByte(&precinctSize)) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[comp].resLevels[r].precinctWidth =
+ precinctSize & 0x0f;
+ img.tiles[0].tileComps[comp].resLevels[r].precinctHeight =
+ (precinctSize >> 4) & 0x0f;
+ } else {
+ img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15;
+ img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15;
+ }
+ }
+ for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
+ for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
+ img.tiles[0].tileComps[comp].resLevels[r].precinctWidth;
+ img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
+ img.tiles[0].tileComps[comp].resLevels[r].precinctHeight;
+ }
+ }
+ break;
+ case 0x5c: // QCD - quantization default
+ cover(23);
+ if (!haveSIZ) {
+ error(errSyntaxError, getPos(),
+ "JPX QCD marker segment before SIZ segment");
+ return gFalse;
+ }
+ if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
+ if (segLen <= 3) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
+ img.tiles[0].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
+ if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
+ img.tiles[0].tileComps[0].nQuantSteps = 1;
+ img.tiles[0].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
+ if (segLen < 5) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
+ img.tiles[0].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
+ if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (!(i == 0 && comp == 0)) {
+ img.tiles[i].tileComps[comp].quantStyle =
+ img.tiles[0].tileComps[0].quantStyle;
+ img.tiles[i].tileComps[comp].nQuantSteps =
+ img.tiles[0].tileComps[0].nQuantSteps;
+ img.tiles[i].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
+ img.tiles[i].tileComps[comp].quantSteps[j] =
+ img.tiles[0].tileComps[0].quantSteps[j];
+ }
+ }
+ }
+ }
+ haveQCD = gTrue;
+ break;
+ case 0x5d: // QCC - quantization component
+ cover(24);
+ if (!haveQCD) {
+ error(errSyntaxError, getPos(),
+ "JPX QCC marker segment before QCD segment");
+ return gFalse;
+ }
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) {
+ if (segLen <= (img.nComps > 256 ? 5U : 4U)) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[comp].nQuantSteps =
+ segLen - (img.nComps > 256 ? 5 : 4);
+ img.tiles[0].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
+ if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ }
+ } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
+ img.tiles[0].tileComps[comp].nQuantSteps = 1;
+ img.tiles[0].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) {
+ if (segLen < (img.nComps > 256 ? 5U : 4U) + 2) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[comp].nQuantSteps =
+ (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
+ img.tiles[0].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
+ if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
+ img.tiles[i].tileComps[comp].quantStyle =
+ img.tiles[0].tileComps[comp].quantStyle;
+ img.tiles[i].tileComps[comp].nQuantSteps =
+ img.tiles[0].tileComps[comp].nQuantSteps;
+ img.tiles[i].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
+ img.tiles[i].tileComps[comp].quantSteps[j] =
+ img.tiles[0].tileComps[comp].quantSteps[j];
+ }
+ }
+ break;
+ case 0x5e: // RGN - region of interest
+ cover(25);
+#if 1 //~ ROI is unimplemented
+ error(errUnimplemented, -1, "got a JPX RGN segment");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX RGN marker segment");
+ return gFalse;
+ }
+ }
+#else
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&compInfo[comp].defROI.style) ||
+ !readUByte(&compInfo[comp].defROI.shift)) {
+ error(errSyntaxError, getPos(), "Error in JPX RGN marker segment");
+ return gFalse;
+ }
+#endif
+ break;
+ case 0x5f: // POC - progression order change
+ cover(26);
+#if 1 //~ progression order changes are unimplemented
+ error(errUnimplemented, -1, "got a JPX POC segment");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX POC marker segment");
+ return gFalse;
+ }
+ }
+#else
+ nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
+ progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder));
+ for (i = 0; i < nProgs; ++i) {
+ if (!readUByte(&progs[i].startRes) ||
+ !(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
+ !(img.nComps <= 256 && readUByte(&progs[i].startComp)) ||
+ !readUWord(&progs[i].endLayer) ||
+ !readUByte(&progs[i].endRes) ||
+ !(img.nComps > 256 && readUWord(&progs[i].endComp)) ||
+ !(img.nComps <= 256 && readUByte(&progs[i].endComp)) ||
+ !readUByte(&progs[i].progOrder)) {
+ error(errSyntaxError, getPos(), "Error in JPX POC marker segment");
+ return gFalse;
+ }
+ }
+#endif
+ break;
+ case 0x60: // PPM - packed packet headers, main header
+ cover(27);
+#if 1 //~ packed packet headers are unimplemented
+ error(errUnimplemented, -1, "Got a JPX PPM segment");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX PPM marker segment");
+ return gFalse;
+ }
+ }
+#endif
+ break;
+ case 0x55: // TLM - tile-part lengths
+ // skipped
+ cover(28);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX TLM marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x57: // PLM - packet length, main header
+ // skipped
+ cover(29);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX PLM marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x63: // CRG - component registration
+ // skipped
+ cover(30);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX CRG marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x64: // COM - comment
+ // skipped
+ cover(31);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX COM marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x90: // SOT - start of tile
+ cover(32);
+ haveSOT = gTrue;
+ break;
+ default:
+ cover(33);
+ error(errSyntaxError, getPos(),
+ "Unknown marker segment {0:02x} in JPX stream", segType);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ break;
+ }
+ }
+ break;
+ }
+ } while (!haveSOT);
+
+ if (!haveSIZ) {
+ error(errSyntaxError, getPos(),
+ "Missing SIZ marker segment in JPX stream");
+ return gFalse;
+ }
+ if (!haveCOD) {
+ error(errSyntaxError, getPos(),
+ "Missing COD marker segment in JPX stream");
+ return gFalse;
+ }
+ if (!haveQCD) {
+ error(errSyntaxError, getPos(),
+ "Missing QCD marker segment in JPX stream");
+ return gFalse;
+ }
+
+ //----- read the tile-parts
+ while (1) {
+ if (!readTilePart()) {
+ return gFalse;
+ }
+ if (!readMarkerHdr(&segType, &segLen)) {
+ error(errSyntaxError, getPos(), "Error in JPX codestream");
+ return gFalse;
+ }
+ if (segType != 0x90) { // SOT - start of tile
+ break;
+ }
+ }
+
+ if (segType != 0xd9) { // EOC - end of codestream
+ error(errSyntaxError, getPos(), "Missing EOC marker in JPX codestream");
+ return gFalse;
+ }
+
+ //----- finish decoding the image
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ tile = &img.tiles[i];
+ if (!tile->init) {
+ error(errSyntaxError, getPos(), "Uninitialized tile in JPX codestream");
+ return gFalse;
+ }
+ for (comp = 0; comp < img.nComps; ++comp) {
+ tileComp = &tile->tileComps[comp];
+ inverseTransform(tileComp);
+ }
+ if (!inverseMultiCompAndDC(tile)) {
+ return gFalse;
+ }
+ }
+
+ //~ can free memory below tileComps here, and also tileComp.buf
+
+ return gTrue;
+}
+
+GBool JPXStream::readTilePart() {
+ JPXTile *tile;
+ JPXTileComp *tileComp;
+ JPXResLevel *resLevel;
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ int *sbCoeffs;
+ GBool haveSOD;
+ Guint tileIdx, tilePartLen, tilePartIdx, nTileParts;
+ GBool tilePartToEOC;
+ Guint precinctSize, style, nDecompLevels;
+ Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen;
+ Guint i, j, k, cbX, cbY, r, pre, sb, cbi, cbj;
+ int segType, level;
+
+ // process the SOT marker segment
+ if (!readUWord(&tileIdx) ||
+ !readULong(&tilePartLen) ||
+ !readUByte(&tilePartIdx) ||
+ !readUByte(&nTileParts)) {
+ error(errSyntaxError, getPos(), "Error in JPX SOT marker segment");
+ return gFalse;
+ }
+
+ if (tileIdx >= img.nXTiles * img.nYTiles ||
+ (tilePartIdx > 0 && !img.tiles[tileIdx].init)) {
+ error(errSyntaxError, getPos(), "Weird tile index in JPX stream");
+ return gFalse;
+ }
+
+ tilePartToEOC = tilePartLen == 0;
+ tilePartLen -= 12; // subtract size of SOT segment
+
+ haveSOD = gFalse;
+ do {
+ if (!readMarkerHdr(&segType, &segLen)) {
+ error(errSyntaxError, getPos(), "Error in JPX tile-part codestream");
+ return gFalse;
+ }
+ tilePartLen -= 2 + segLen;
+ switch (segType) {
+ case 0x52: // COD - coding style default
+ cover(34);
+ if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) ||
+ !readUByte(&img.tiles[tileIdx].progOrder) ||
+ !readUWord(&img.tiles[tileIdx].nLayers) ||
+ !readUByte(&img.tiles[tileIdx].multiComp) ||
+ !readUByte(&nDecompLevels) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ if (nDecompLevels > 32 ||
+ img.tiles[tileIdx].tileComps[0].codeBlockW > 8 ||
+ img.tiles[tileIdx].tileComps[0].codeBlockH > 8) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[0].nDecompLevels = nDecompLevels;
+ img.tiles[tileIdx].tileComps[0].codeBlockW += 2;
+ img.tiles[tileIdx].tileComps[0].codeBlockH += 2;
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (comp != 0) {
+ img.tiles[tileIdx].tileComps[comp].style =
+ img.tiles[tileIdx].tileComps[0].style;
+ img.tiles[tileIdx].tileComps[comp].nDecompLevels =
+ img.tiles[tileIdx].tileComps[0].nDecompLevels;
+ img.tiles[tileIdx].tileComps[comp].codeBlockW =
+ img.tiles[tileIdx].tileComps[0].codeBlockW;
+ img.tiles[tileIdx].tileComps[comp].codeBlockH =
+ img.tiles[tileIdx].tileComps[0].codeBlockH;
+ img.tiles[tileIdx].tileComps[comp].codeBlockStyle =
+ img.tiles[tileIdx].tileComps[0].codeBlockStyle;
+ img.tiles[tileIdx].tileComps[comp].transform =
+ img.tiles[tileIdx].tileComps[0].transform;
+ }
+ img.tiles[tileIdx].tileComps[comp].resLevels =
+ (JPXResLevel *)greallocn(
+ img.tiles[tileIdx].tileComps[comp].resLevels,
+ (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
+ for (r = 0;
+ r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
+ ++r) {
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
+ }
+ }
+ for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) {
+ if (img.tiles[tileIdx].tileComps[0].style & 0x01) {
+ if (!readUByte(&precinctSize)) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth =
+ precinctSize & 0x0f;
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight =
+ (precinctSize >> 4) & 0x0f;
+ } else {
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15;
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15;
+ }
+ }
+ for (comp = 1; comp < img.nComps; ++comp) {
+ for (r = 0;
+ r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
+ ++r) {
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth;
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight;
+ }
+ }
+ break;
+ case 0x53: // COC - coding style component
+ cover(35);
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&style) ||
+ !readUByte(&nDecompLevels) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) {
+ error(errSyntaxError, getPos(), "Error in JPX COC marker segment");
+ return gFalse;
+ }
+ if (nDecompLevels > 32 ||
+ img.tiles[tileIdx].tileComps[comp].codeBlockW > 8 ||
+ img.tiles[tileIdx].tileComps[comp].codeBlockH > 8) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[comp].nDecompLevels = nDecompLevels;
+ img.tiles[tileIdx].tileComps[comp].style =
+ (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1);
+ img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
+ img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
+ img.tiles[tileIdx].tileComps[comp].resLevels =
+ (JPXResLevel *)greallocn(
+ img.tiles[tileIdx].tileComps[comp].resLevels,
+ (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
+ for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
+ }
+ for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
+ if (img.tiles[tileIdx].tileComps[comp].style & 0x01) {
+ if (!readUByte(&precinctSize)) {
+ error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
+ precinctSize & 0x0f;
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
+ (precinctSize >> 4) & 0x0f;
+ } else {
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15;
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15;
+ }
+ }
+ break;
+ case 0x5c: // QCD - quantization default
+ cover(36);
+ if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) {
+ if (segLen <= 3) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[0].nQuantSteps = segLen - 3;
+ img.tiles[tileIdx].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
+ if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
+ img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
+ img.tiles[tileIdx].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
+ if (segLen < 5) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
+ img.tiles[tileIdx].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
+ if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ for (comp = 1; comp < img.nComps; ++comp) {
+ img.tiles[tileIdx].tileComps[comp].quantStyle =
+ img.tiles[tileIdx].tileComps[0].quantStyle;
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps =
+ img.tiles[tileIdx].tileComps[0].nQuantSteps;
+ img.tiles[tileIdx].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
+ img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
+ img.tiles[tileIdx].tileComps[0].quantSteps[j];
+ }
+ }
+ break;
+ case 0x5d: // QCC - quantization component
+ cover(37);
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) {
+ if (segLen <= (img.nComps > 256 ? 5U : 4U)) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps =
+ segLen - (img.nComps > 256 ? 5 : 4);
+ img.tiles[tileIdx].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
+ if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ }
+ } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
+ == 0x01) {
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
+ img.tiles[tileIdx].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
+ == 0x02) {
+ if (segLen < (img.nComps > 256 ? 5U : 4U) + 2) {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps =
+ (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
+ img.tiles[tileIdx].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
+ if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
+ error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else {
+ error(errSyntaxError, getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ break;
+ case 0x5e: // RGN - region of interest
+ cover(38);
+#if 1 //~ ROI is unimplemented
+ error(errUnimplemented, -1, "Got a JPX RGN segment");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX RGN marker segment");
+ return gFalse;
+ }
+ }
+#else
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&compInfo[comp].roi.style) ||
+ !readUByte(&compInfo[comp].roi.shift)) {
+ error(errSyntaxError, getPos(), "Error in JPX RGN marker segment");
+ return gFalse;
+ }
+#endif
+ break;
+ case 0x5f: // POC - progression order change
+ cover(39);
+#if 1 //~ progression order changes are unimplemented
+ error(errUnimplemented, -1, "Got a JPX POC segment");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX POC marker segment");
+ return gFalse;
+ }
+ }
+#else
+ nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
+ tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder));
+ for (i = 0; i < nTileProgs; ++i) {
+ if (!readUByte(&tileProgs[i].startRes) ||
+ !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
+ !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) ||
+ !readUWord(&tileProgs[i].endLayer) ||
+ !readUByte(&tileProgs[i].endRes) ||
+ !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) ||
+ !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) ||
+ !readUByte(&tileProgs[i].progOrder)) {
+ error(errSyntaxError, getPos(), "Error in JPX POC marker segment");
+ return gFalse;
+ }
+ }
+#endif
+ break;
+ case 0x61: // PPT - packed packet headers, tile-part hdr
+ cover(40);
+#if 1 //~ packed packet headers are unimplemented
+ error(errUnimplemented, -1, "Got a JPX PPT segment");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX PPT marker segment");
+ return gFalse;
+ }
+ }
+#endif
+ case 0x58: // PLT - packet length, tile-part header
+ // skipped
+ cover(41);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX PLT marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x64: // COM - comment
+ // skipped
+ cover(42);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Error in JPX COM marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x93: // SOD - start of data
+ cover(43);
+ haveSOD = gTrue;
+ break;
+ default:
+ cover(44);
+ error(errSyntaxError, getPos(),
+ "Unknown marker segment {0:02x} in JPX tile-part stream",
+ segType);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (bufStr->getChar() == EOF) {
+ break;
+ }
+ }
+ break;
+ }
+ } while (!haveSOD);
+
+ //----- initialize the tile, precincts, and code-blocks
+ if (tilePartIdx == 0) {
+ tile = &img.tiles[tileIdx];
+ tile->init = gTrue;
+ i = tileIdx / img.nXTiles;
+ j = tileIdx % img.nXTiles;
+ if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) {
+ tile->x0 = img.xOffset;
+ }
+ if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) {
+ tile->y0 = img.yOffset;
+ }
+ if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) {
+ tile->x1 = img.xSize;
+ }
+ if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) {
+ tile->y1 = img.ySize;
+ }
+ tile->comp = 0;
+ tile->res = 0;
+ tile->precinct = 0;
+ tile->layer = 0;
+ tile->maxNDecompLevels = 0;
+ for (comp = 0; comp < img.nComps; ++comp) {
+ tileComp = &tile->tileComps[comp];
+ if (tileComp->nDecompLevels > tile->maxNDecompLevels) {
+ tile->maxNDecompLevels = tileComp->nDecompLevels;
+ }
+ tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep);
+ tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->vSep);
+ tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep);
+ tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->vSep);
+ tileComp->w = tileComp->x1 - tileComp->x0;
+ tileComp->cbW = 1 << tileComp->codeBlockW;
+ tileComp->cbH = 1 << tileComp->codeBlockH;
+ tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) *
+ (tileComp->y1 - tileComp->y0),
+ sizeof(int));
+ if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
+ n = tileComp->x1 - tileComp->x0;
+ } else {
+ n = tileComp->y1 - tileComp->y0;
+ }
+ tileComp->buf = (int *)gmallocn(n + 8, sizeof(int));
+ for (r = 0; r <= tileComp->nDecompLevels; ++r) {
+ resLevel = &tileComp->resLevels[r];
+ k = r == 0 ? tileComp->nDecompLevels
+ : tileComp->nDecompLevels - r + 1;
+ resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k);
+ resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k);
+ resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k);
+ resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k);
+ if (r == 0) {
+ resLevel->bx0[0] = resLevel->x0;
+ resLevel->by0[0] = resLevel->y0;
+ resLevel->bx1[0] = resLevel->x1;
+ resLevel->by1[0] = resLevel->y1;
+ } else {
+ resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
+ resLevel->by0[0] = resLevel->y0;
+ resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
+ resLevel->by1[0] = resLevel->y1;
+ resLevel->bx0[1] = resLevel->x0;
+ resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
+ resLevel->bx1[1] = resLevel->x1;
+ resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
+ resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
+ resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
+ resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
+ resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
+ }
+ resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct));
+ for (pre = 0; pre < 1; ++pre) {
+ precinct = &resLevel->precincts[pre];
+ precinct->x0 = resLevel->x0;
+ precinct->y0 = resLevel->y0;
+ precinct->x1 = resLevel->x1;
+ precinct->y1 = resLevel->y1;
+ nSBs = r == 0 ? 1 : 3;
+ precinct->subbands =
+ (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
+ for (sb = 0; sb < nSBs; ++sb) {
+ subband = &precinct->subbands[sb];
+ subband->x0 = resLevel->bx0[sb];
+ subband->y0 = resLevel->by0[sb];
+ subband->x1 = resLevel->bx1[sb];
+ subband->y1 = resLevel->by1[sb];
+ subband->nXCBs = jpxCeilDivPow2(subband->x1,
+ tileComp->codeBlockW)
+ - jpxFloorDivPow2(subband->x0,
+ tileComp->codeBlockW);
+ subband->nYCBs = jpxCeilDivPow2(subband->y1,
+ tileComp->codeBlockH)
+ - jpxFloorDivPow2(subband->y0,
+ tileComp->codeBlockH);
+ n = subband->nXCBs > subband->nYCBs ? subband->nXCBs
+ : subband->nYCBs;
+ for (subband->maxTTLevel = 0, --n;
+ n;
+ ++subband->maxTTLevel, n >>= 1) ;
+ n = 0;
+ for (level = subband->maxTTLevel; level >= 0; --level) {
+ nx = jpxCeilDivPow2(subband->nXCBs, level);
+ ny = jpxCeilDivPow2(subband->nYCBs, level);
+ n += nx * ny;
+ }
+ subband->inclusion =
+ (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
+ subband->zeroBitPlane =
+ (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
+ for (k = 0; k < n; ++k) {
+ subband->inclusion[k].finished = gFalse;
+ subband->inclusion[k].val = 0;
+ subband->zeroBitPlane[k].finished = gFalse;
+ subband->zeroBitPlane[k].val = 0;
+ }
+ subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
+ subband->nYCBs,
+ sizeof(JPXCodeBlock));
+ sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
+ sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
+ if (r == 0) { // (NL)LL
+ sbCoeffs = tileComp->data;
+ } else if (sb == 0) { // (NL-r+1)HL
+ sbCoeffs = tileComp->data
+ + resLevel->bx1[1] - resLevel->bx0[1];
+ } else if (sb == 1) { // (NL-r+1)LH
+ sbCoeffs = tileComp->data
+ + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w;
+ } else { // (NL-r+1)HH
+ sbCoeffs = tileComp->data
+ + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w
+ + resLevel->bx1[1] - resLevel->bx0[1];
+ }
+ cb = subband->cbs;
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW;
+ cb->x1 = cb->x0 + tileComp->cbW;
+ if (subband->x0 > cb->x0) {
+ cb->x0 = subband->x0;
+ }
+ if (subband->x1 < cb->x1) {
+ cb->x1 = subband->x1;
+ }
+ cb->y0 = (sby0 + cbY) << tileComp->codeBlockH;
+ cb->y1 = cb->y0 + tileComp->cbH;
+ if (subband->y0 > cb->y0) {
+ cb->y0 = subband->y0;
+ }
+ if (subband->y1 < cb->y1) {
+ cb->y1 = subband->y1;
+ }
+ cb->seen = gFalse;
+ cb->lBlock = 3;
+ cb->nextPass = jpxPassCleanup;
+ cb->nZeroBitPlanes = 0;
+ cb->dataLenSize = 1;
+ cb->dataLen = (Guint *)gmalloc(sizeof(Guint));
+ cb->coeffs = sbCoeffs
+ + (cb->y0 - subband->y0) * tileComp->w
+ + (cb->x0 - subband->x0);
+ cb->touched = (char *)gmalloc(1 << (tileComp->codeBlockW
+ + tileComp->codeBlockH));
+ cb->len = 0;
+ for (cbj = 0; cbj < cb->y1 - cb->y0; ++cbj) {
+ for (cbi = 0; cbi < cb->x1 - cb->x0; ++cbi) {
+ cb->coeffs[cbj * tileComp->w + cbi] = 0;
+ }
+ }
+ memset(cb->touched, 0,
+ (1 << (tileComp->codeBlockW + tileComp->codeBlockH)));
+ cb->arithDecoder = NULL;
+ cb->stats = NULL;
+ ++cb;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return readTilePartData(tileIdx, tilePartLen, tilePartToEOC);
+}
+
+GBool JPXStream::readTilePartData(Guint tileIdx,
+ Guint tilePartLen, GBool tilePartToEOC) {
+ JPXTile *tile;
+ JPXTileComp *tileComp;
+ JPXResLevel *resLevel;
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ Guint ttVal;
+ Guint bits, cbX, cbY, nx, ny, i, j, n, sb;
+ int level;
+
+ tile = &img.tiles[tileIdx];
+
+ // read all packets from this tile-part
+ while (1) {
+ if (tilePartToEOC) {
+ //~ peek for an EOC marker
+ cover(93);
+ } else if (tilePartLen == 0) {
+ break;
+ }
+
+ tileComp = &tile->tileComps[tile->comp];
+ resLevel = &tileComp->resLevels[tile->res];
+ precinct = &resLevel->precincts[tile->precinct];
+
+ //----- packet header
+
+ // setup
+ startBitBuf(tilePartLen);
+ if (tileComp->style & 0x02) {
+ skipSOP();
+ }
+
+ // zero-length flag
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (!bits) {
+ // packet is empty -- clear all code-block inclusion flags
+ cover(45);
+ for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
+ subband = &precinct->subbands[sb];
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ cb = &subband->cbs[cbY * subband->nXCBs + cbX];
+ cb->included = gFalse;
+ }
+ }
+ }
+ } else {
+
+ for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
+ subband = &precinct->subbands[sb];
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ cb = &subband->cbs[cbY * subband->nXCBs + cbX];
+
+ // skip code-blocks with no coefficients
+ if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) {
+ cover(46);
+ cb->included = gFalse;
+ continue;
+ }
+
+ // code-block inclusion
+ if (cb->seen) {
+ cover(47);
+ if (!readBits(1, &cb->included)) {
+ goto err;
+ }
+ } else {
+ cover(48);
+ ttVal = 0;
+ i = 0;
+ for (level = subband->maxTTLevel; level >= 0; --level) {
+ nx = jpxCeilDivPow2(subband->nXCBs, level);
+ ny = jpxCeilDivPow2(subband->nYCBs, level);
+ j = i + (cbY >> level) * nx + (cbX >> level);
+ if (!subband->inclusion[j].finished &&
+ !subband->inclusion[j].val) {
+ subband->inclusion[j].val = ttVal;
+ } else {
+ ttVal = subband->inclusion[j].val;
+ }
+ while (!subband->inclusion[j].finished &&
+ ttVal <= tile->layer) {
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (bits == 1) {
+ subband->inclusion[j].finished = gTrue;
+ } else {
+ ++ttVal;
+ }
+ }
+ subband->inclusion[j].val = ttVal;
+ if (ttVal > tile->layer) {
+ break;
+ }
+ i += nx * ny;
+ }
+ cb->included = level < 0;
+ }
+
+ if (cb->included) {
+ cover(49);
+
+ // zero bit-plane count
+ if (!cb->seen) {
+ cover(50);
+ ttVal = 0;
+ i = 0;
+ for (level = subband->maxTTLevel; level >= 0; --level) {
+ nx = jpxCeilDivPow2(subband->nXCBs, level);
+ ny = jpxCeilDivPow2(subband->nYCBs, level);
+ j = i + (cbY >> level) * nx + (cbX >> level);
+ if (!subband->zeroBitPlane[j].finished &&
+ !subband->zeroBitPlane[j].val) {
+ subband->zeroBitPlane[j].val = ttVal;
+ } else {
+ ttVal = subband->zeroBitPlane[j].val;
+ }
+ while (!subband->zeroBitPlane[j].finished) {
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (bits == 1) {
+ subband->zeroBitPlane[j].finished = gTrue;
+ } else {
+ ++ttVal;
+ }
+ }
+ subband->zeroBitPlane[j].val = ttVal;
+ i += nx * ny;
+ }
+ cb->nZeroBitPlanes = ttVal;
+ }
+
+ // number of coding passes
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (bits == 0) {
+ cover(51);
+ cb->nCodingPasses = 1;
+ } else {
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (bits == 0) {
+ cover(52);
+ cb->nCodingPasses = 2;
+ } else {
+ cover(53);
+ if (!readBits(2, &bits)) {
+ goto err;
+ }
+ if (bits < 3) {
+ cover(54);
+ cb->nCodingPasses = 3 + bits;
+ } else {
+ cover(55);
+ if (!readBits(5, &bits)) {
+ goto err;
+ }
+ if (bits < 31) {
+ cover(56);
+ cb->nCodingPasses = 6 + bits;
+ } else {
+ cover(57);
+ if (!readBits(7, &bits)) {
+ goto err;
+ }
+ cb->nCodingPasses = 37 + bits;
+ }
+ }
+ }
+ }
+
+ // update Lblock
+ while (1) {
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (!bits) {
+ break;
+ }
+ ++cb->lBlock;
+ }
+
+ // one codeword segment for each of the coding passes
+ if (tileComp->codeBlockStyle & 0x04) {
+ if (cb->nCodingPasses > cb->dataLenSize) {
+ cb->dataLenSize = cb->nCodingPasses;
+ cb->dataLen = (Guint *)greallocn(cb->dataLen,
+ cb->dataLenSize,
+ sizeof(Guint));
+ }
+
+ // read the lengths
+ for (i = 0; i < cb->nCodingPasses; ++i) {
+ if (!readBits(cb->lBlock, &cb->dataLen[i])) {
+ goto err;
+ }
+ }
+
+ // one codeword segment for all of the coding passes
+ } else {
+
+ // read the length
+ for (n = cb->lBlock, i = cb->nCodingPasses >> 1;
+ i;
+ ++n, i >>= 1) ;
+ if (!readBits(n, &cb->dataLen[0])) {
+ goto err;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (tileComp->style & 0x04) {
+ skipEPH();
+ }
+ tilePartLen = finishBitBuf();
+
+ //----- packet data
+
+ for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
+ subband = &precinct->subbands[sb];
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ cb = &subband->cbs[cbY * subband->nXCBs + cbX];
+ if (cb->included) {
+ if (!readCodeBlockData(tileComp, resLevel, precinct, subband,
+ tile->res, sb, cb)) {
+ return gFalse;
+ }
+ if (tileComp->codeBlockStyle & 0x04) {
+ for (i = 0; i < cb->nCodingPasses; ++i) {
+ tilePartLen -= cb->dataLen[i];
+ }
+ } else {
+ tilePartLen -= cb->dataLen[0];
+ }
+ cb->seen = gTrue;
+ }
+ }
+ }
+ }
+
+ //----- next packet
+
+ switch (tile->progOrder) {
+ case 0: // layer, resolution level, component, precinct
+ cover(58);
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ }
+ }
+ }
+ break;
+ case 1: // resolution level, layer, component, precinct
+ cover(59);
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ }
+ }
+ }
+ break;
+ case 2: // resolution level, precinct, component, layer
+ //~ this isn't correct -- see B.12.1.3
+ cover(60);
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ }
+ }
+ tileComp = &tile->tileComps[tile->comp];
+ if (tile->res >= tileComp->nDecompLevels + 1) {
+ if (++tile->comp == img.nComps) {
+ return gTrue;
+ }
+ }
+ }
+ break;
+ case 3: // precinct, component, resolution level, layer
+ //~ this isn't correct -- see B.12.1.4
+ cover(61);
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ }
+ }
+ }
+ break;
+ case 4: // component, precinct, resolution level, layer
+ //~ this isn't correct -- see B.12.1.5
+ cover(62);
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return gTrue;
+
+ err:
+ error(errSyntaxError, getPos(), "Error in JPX stream");
+ return gFalse;
+}
+
+GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
+ JPXResLevel *resLevel,
+ JPXPrecinct *precinct,
+ JPXSubband *subband,
+ Guint res, Guint sb,
+ JPXCodeBlock *cb) {
+ int *coeff0, *coeff1, *coeff;
+ char *touched0, *touched1, *touched;
+ Guint horiz, vert, diag, all, cx, xorBit;
+ int horizSign, vertSign, bit;
+ int segSym;
+ Guint i, x, y0, y1;
+
+ if (cb->arithDecoder) {
+ cover(63);
+ cb->arithDecoder->restart(cb->dataLen[0]);
+ } else {
+ cover(64);
+ cb->arithDecoder = new JArithmeticDecoder();
+ cb->arithDecoder->setStream(bufStr, cb->dataLen[0]);
+ cb->arithDecoder->start();
+ cb->stats = new JArithmeticDecoderStats(jpxNContexts);
+ cb->stats->setEntry(jpxContextSigProp, 4, 0);
+ cb->stats->setEntry(jpxContextRunLength, 3, 0);
+ cb->stats->setEntry(jpxContextUniform, 46, 0);
+ }
+
+ for (i = 0; i < cb->nCodingPasses; ++i) {
+ if ((tileComp->codeBlockStyle & 0x04) && i > 0) {
+ cb->arithDecoder->setStream(bufStr, cb->dataLen[i]);
+ cb->arithDecoder->start();
+ }
+
+ switch (cb->nextPass) {
+
+ //----- significance propagation pass
+ case jpxPassSigProp:
+ cover(65);
+ for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
+ y0 < cb->y1;
+ y0 += 4, coeff0 += 4 * tileComp->w,
+ touched0 += 4 << tileComp->codeBlockW) {
+ for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
+ x < cb->x1;
+ ++x, ++coeff1, ++touched1) {
+ for (y1 = 0, coeff = coeff1, touched = touched1;
+ y1 < 4 && y0+y1 < cb->y1;
+ ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
+ if (!*coeff) {
+ horiz = vert = diag = 0;
+ horizSign = vertSign = 2;
+ if (x > cb->x0) {
+ if (coeff[-1]) {
+ ++horiz;
+ horizSign += coeff[-1] < 0 ? -1 : 1;
+ }
+ if (y0+y1 > cb->y0) {
+ diag += coeff[-(int)tileComp->w - 1] ? 1 : 0;
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ diag += coeff[tileComp->w - 1] ? 1 : 0;
+ }
+ }
+ if (x < cb->x1 - 1) {
+ if (coeff[1]) {
+ ++horiz;
+ horizSign += coeff[1] < 0 ? -1 : 1;
+ }
+ if (y0+y1 > cb->y0) {
+ diag += coeff[-(int)tileComp->w + 1] ? 1 : 0;
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ diag += coeff[tileComp->w + 1] ? 1 : 0;
+ }
+ }
+ if (y0+y1 > cb->y0) {
+ if (coeff[-(int)tileComp->w]) {
+ ++vert;
+ vertSign += coeff[-(int)tileComp->w] < 0 ? -1 : 1;
+ }
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ if (coeff[tileComp->w]) {
+ ++vert;
+ vertSign += coeff[tileComp->w] < 0 ? -1 : 1;
+ }
+ }
+ cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
+ if (cx != 0) {
+ if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
+ cx = signContext[horizSign][vertSign][0];
+ xorBit = signContext[horizSign][vertSign][1];
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ *coeff = -1;
+ } else {
+ *coeff = 1;
+ }
+ }
+ *touched = 1;
+ }
+ }
+ }
+ }
+ }
+ ++cb->nextPass;
+ break;
+
+ //----- magnitude refinement pass
+ case jpxPassMagRef:
+ cover(66);
+ for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
+ y0 < cb->y1;
+ y0 += 4, coeff0 += 4 * tileComp->w,
+ touched0 += 4 << tileComp->codeBlockW) {
+ for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
+ x < cb->x1;
+ ++x, ++coeff1, ++touched1) {
+ for (y1 = 0, coeff = coeff1, touched = touched1;
+ y1 < 4 && y0+y1 < cb->y1;
+ ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
+ if (*coeff && !*touched) {
+ if (*coeff == 1 || *coeff == -1) {
+ all = 0;
+ if (x > cb->x0) {
+ all += coeff[-1] ? 1 : 0;
+ if (y0+y1 > cb->y0) {
+ all += coeff[-(int)tileComp->w - 1] ? 1 : 0;
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ all += coeff[tileComp->w - 1] ? 1 : 0;
+ }
+ }
+ if (x < cb->x1 - 1) {
+ all += coeff[1] ? 1 : 0;
+ if (y0+y1 > cb->y0) {
+ all += coeff[-(int)tileComp->w + 1] ? 1 : 0;
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ all += coeff[tileComp->w + 1] ? 1 : 0;
+ }
+ }
+ if (y0+y1 > cb->y0) {
+ all += coeff[-(int)tileComp->w] ? 1 : 0;
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ all += coeff[tileComp->w] ? 1 : 0;
+ }
+ cx = all ? 15 : 14;
+ } else {
+ cx = 16;
+ }
+ bit = cb->arithDecoder->decodeBit(cx, cb->stats);
+ if (*coeff < 0) {
+ *coeff = (*coeff << 1) - bit;
+ } else {
+ *coeff = (*coeff << 1) + bit;
+ }
+ *touched = 1;
+ }
+ }
+ }
+ }
+ ++cb->nextPass;
+ break;
+
+ //----- cleanup pass
+ case jpxPassCleanup:
+ cover(67);
+ for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
+ y0 < cb->y1;
+ y0 += 4, coeff0 += 4 * tileComp->w,
+ touched0 += 4 << tileComp->codeBlockW) {
+ for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
+ x < cb->x1;
+ ++x, ++coeff1, ++touched1) {
+ y1 = 0;
+ if (y0 + 3 < cb->y1 &&
+ !(*touched1) &&
+ !(touched1[tileComp->cbW]) &&
+ !(touched1[2 * tileComp->cbW]) &&
+ !(touched1[3 * tileComp->cbW]) &&
+ (x == cb->x0 || y0 == cb->y0 ||
+ !coeff1[-(int)tileComp->w - 1]) &&
+ (y0 == cb->y0 ||
+ !coeff1[-(int)tileComp->w]) &&
+ (x == cb->x1 - 1 || y0 == cb->y0 ||
+ !coeff1[-(int)tileComp->w + 1]) &&
+ (x == cb->x0 ||
+ (!coeff1[-1] &&
+ !coeff1[tileComp->w - 1] &&
+ !coeff1[2 * tileComp->w - 1] &&
+ !coeff1[3 * tileComp->w - 1])) &&
+ (x == cb->x1 - 1 ||
+ (!coeff1[1] &&
+ !coeff1[tileComp->w + 1] &&
+ !coeff1[2 * tileComp->w + 1] &&
+ !coeff1[3 * tileComp->w + 1])) &&
+ ((tileComp->codeBlockStyle & 0x08) ||
+ ((x == cb->x0 || y0+4 == cb->y1 ||
+ !coeff1[4 * tileComp->w - 1]) &&
+ (y0+4 == cb->y1 ||
+ !coeff1[4 * tileComp->w]) &&
+ (x == cb->x1 - 1 || y0+4 == cb->y1 ||
+ !coeff1[4 * tileComp->w + 1])))) {
+ if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
+ y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+ y1 = (y1 << 1) |
+ cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+ coeff = &coeff1[y1 * tileComp->w];
+ cx = signContext[2][2][0];
+ xorBit = signContext[2][2][1];
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ *coeff = -1;
+ } else {
+ *coeff = 1;
+ }
+ ++y1;
+ } else {
+ y1 = 4;
+ }
+ }
+ for (coeff = &coeff1[y1 * tileComp->w],
+ touched = &touched1[y1 << tileComp->codeBlockW];
+ y1 < 4 && y0 + y1 < cb->y1;
+ ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
+ if (!*touched) {
+ horiz = vert = diag = 0;
+ horizSign = vertSign = 2;
+ if (x > cb->x0) {
+ if (coeff[-1]) {
+ ++horiz;
+ horizSign += coeff[-1] < 0 ? -1 : 1;
+ }
+ if (y0+y1 > cb->y0) {
+ diag += coeff[-(int)tileComp->w - 1] ? 1 : 0;
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ diag += coeff[tileComp->w - 1] ? 1 : 0;
+ }
+ }
+ if (x < cb->x1 - 1) {
+ if (coeff[1]) {
+ ++horiz;
+ horizSign += coeff[1] < 0 ? -1 : 1;
+ }
+ if (y0+y1 > cb->y0) {
+ diag += coeff[-(int)tileComp->w + 1] ? 1 : 0;
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ diag += coeff[tileComp->w + 1] ? 1 : 0;
+ }
+ }
+ if (y0+y1 > cb->y0) {
+ if (coeff[-(int)tileComp->w]) {
+ ++vert;
+ vertSign += coeff[-(int)tileComp->w] < 0 ? -1 : 1;
+ }
+ }
+ if (y0+y1 < cb->y1 - 1 &&
+ (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) {
+ if (coeff[tileComp->w]) {
+ ++vert;
+ vertSign += coeff[tileComp->w] < 0 ? -1 : 1;
+ }
+ }
+ cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
+ if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
+ cx = signContext[horizSign][vertSign][0];
+ xorBit = signContext[horizSign][vertSign][1];
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ *coeff = -1;
+ } else {
+ *coeff = 1;
+ }
+ }
+ } else {
+ *touched = 0;
+ }
+ }
+ }
+ }
+ ++cb->len;
+ // look for a segmentation symbol
+ if (tileComp->codeBlockStyle & 0x20) {
+ segSym = cb->arithDecoder->decodeBit(jpxContextUniform,
+ cb->stats) << 3;
+ segSym |= cb->arithDecoder->decodeBit(jpxContextUniform,
+ cb->stats) << 2;
+ segSym |= cb->arithDecoder->decodeBit(jpxContextUniform,
+ cb->stats) << 1;
+ segSym |= cb->arithDecoder->decodeBit(jpxContextUniform,
+ cb->stats);
+ if (segSym != 0x0a) {
+ // in theory this should be a fatal error, but it seems to
+ // be problematic
+ error(errSyntaxWarning, getPos(),
+ "Missing or invalid segmentation symbol in JPX stream");
+ }
+ }
+ cb->nextPass = jpxPassSigProp;
+ break;
+ }
+
+ if (tileComp->codeBlockStyle & 0x02) {
+ cb->stats->reset();
+ cb->stats->setEntry(jpxContextSigProp, 4, 0);
+ cb->stats->setEntry(jpxContextRunLength, 3, 0);
+ cb->stats->setEntry(jpxContextUniform, 46, 0);
+ }
+
+ if (tileComp->codeBlockStyle & 0x04) {
+ cb->arithDecoder->cleanup();
+ }
+ }
+
+ cb->arithDecoder->cleanup();
+ return gTrue;
+}
+
+// Inverse quantization, and wavelet transform (IDWT). This also does
+// the initial shift to convert to fixed point format.
+void JPXStream::inverseTransform(JPXTileComp *tileComp) {
+ JPXResLevel *resLevel;
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ int *coeff0, *coeff;
+ char *touched0, *touched;
+ Guint qStyle, guard, eps, shift;
+ int shift2;
+ double mu;
+ int val;
+ Guint r, cbX, cbY, x, y;
+
+ cover(68);
+
+ //----- (NL)LL subband (resolution level 0)
+
+ resLevel = &tileComp->resLevels[0];
+ precinct = &resLevel->precincts[0];
+ subband = &precinct->subbands[0];
+
+ // i-quant parameters
+ qStyle = tileComp->quantStyle & 0x1f;
+ guard = (tileComp->quantStyle >> 5) & 7;
+ if (qStyle == 0) {
+ cover(69);
+ eps = (tileComp->quantSteps[0] >> 3) & 0x1f;
+ shift = guard + eps - 1;
+ mu = 0; // make gcc happy
+ } else {
+ cover(70);
+ shift = guard - 1 + tileComp->prec;
+ mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0;
+ }
+ if (tileComp->transform == 0) {
+ cover(71);
+ shift += fracBits;
+ }
+
+ // do fixed point adjustment and dequantization on (NL)LL
+ cb = subband->cbs;
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
+ y < cb->y1;
+ ++y, coeff0 += tileComp->w, touched0 += tileComp->cbW) {
+ for (x = cb->x0, coeff = coeff0, touched = touched0;
+ x < cb->x1;
+ ++x, ++coeff, ++touched) {
+ val = *coeff;
+ if (val != 0) {
+ shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched);
+ if (shift2 > 0) {
+ cover(94);
+ if (val < 0) {
+ val = (val << shift2) - (1 << (shift2 - 1));
+ } else {
+ val = (val << shift2) + (1 << (shift2 - 1));
+ }
+ } else {
+ cover(95);
+ val >>= -shift2;
+ }
+ if (qStyle == 0) {
+ cover(96);
+ if (tileComp->transform == 0) {
+ cover(97);
+ val &= -1 << fracBits;
+ }
+ } else {
+ cover(98);
+ val = (int)((double)val * mu);
+ }
+ }
+ *coeff = val;
+ }
+ }
+ ++cb;
+ }
+ }
+
+ //----- IDWT for each level
+
+ for (r = 1; r <= tileComp->nDecompLevels; ++r) {
+ resLevel = &tileComp->resLevels[r];
+
+ // (n)LL is already in the upper-left corner of the
+ // tile-component data array -- interleave with (n)HL/LH/HH
+ // and inverse transform to get (n-1)LL, which will be stored
+ // in the upper-left corner of the tile-component data array
+ inverseTransformLevel(tileComp, r, resLevel);
+ }
+}
+
+// Do one level of the inverse transform:
+// - take (n)LL, (n)HL, (n)LH, and (n)HH from the upper-left corner
+// of the tile-component data array
+// - leave the resulting (n-1)LL in the same place
+void JPXStream::inverseTransformLevel(JPXTileComp *tileComp,
+ Guint r, JPXResLevel *resLevel) {
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ int *coeff0, *coeff;
+ char *touched0, *touched;
+ Guint qStyle, guard, eps, shift, t;
+ int shift2;
+ double mu;
+ int val;
+ int *dataPtr, *bufPtr;
+ Guint nx1, nx2, ny1, ny2, offset;
+ Guint x, y, sb, cbX, cbY;
+
+ //----- fixed-point adjustment and dequantization
+
+ qStyle = tileComp->quantStyle & 0x1f;
+ guard = (tileComp->quantStyle >> 5) & 7;
+ precinct = &resLevel->precincts[0];
+ for (sb = 0; sb < 3; ++sb) {
+
+ // i-quant parameters
+ if (qStyle == 0) {
+ cover(100);
+ const Guint stepIndex = 3*r - 2 + sb;
+ if (unlikely(stepIndex >= tileComp->nQuantSteps)) {
+ error(errSyntaxError, getPos(),
+ "Wrong index for quantSteps in inverseTransformLevel in JPX stream");
+ break;
+ }
+ eps = (tileComp->quantSteps[stepIndex] >> 3) & 0x1f;
+ shift = guard + eps - 1;
+ mu = 0; // make gcc happy
+ } else {
+ cover(101);
+ shift = guard + tileComp->prec;
+ if (sb == 2) {
+ cover(102);
+ ++shift;
+ }
+ const Guint stepIndex = qStyle == 1 ? 0 : (3*r - 2 + sb);
+ if (unlikely(stepIndex >= tileComp->nQuantSteps)) {
+ error(errSyntaxError, getPos(),
+ "Wrong index for quantSteps in inverseTransformLevel in JPX stream");
+ break;
+ }
+ t = tileComp->quantSteps[stepIndex];
+ mu = (double)(0x800 + (t & 0x7ff)) / 2048.0;
+ }
+ if (tileComp->transform == 0) {
+ cover(103);
+ shift += fracBits;
+ }
+
+ // fixed point adjustment and dequantization
+ subband = &precinct->subbands[sb];
+ cb = subband->cbs;
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
+ y < cb->y1;
+ ++y, coeff0 += tileComp->w, touched0 += tileComp->cbW) {
+ for (x = cb->x0, coeff = coeff0, touched = touched0;
+ x < cb->x1;
+ ++x, ++coeff, ++touched) {
+ val = *coeff;
+ if (val != 0) {
+ shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched);
+ if (shift2 > 0) {
+ cover(74);
+ if (val < 0) {
+ val = (val << shift2) - (1 << (shift2 - 1));
+ } else {
+ val = (val << shift2) + (1 << (shift2 - 1));
+ }
+ } else {
+ cover(75);
+ val >>= -shift2;
+ }
+ if (qStyle == 0) {
+ cover(76);
+ if (tileComp->transform == 0) {
+ val &= -1 << fracBits;
+ }
+ } else {
+ cover(77);
+ val = (int)((double)val * mu);
+ }
+ }
+ *coeff = val;
+ }
+ }
+ ++cb;
+ }
+ }
+ }
+
+ //----- inverse transform
+
+ // compute the subband bounds:
+ // 0 nx1 nx2
+ // | | |
+ // v v v
+ // +----+----+
+ // | LL | HL | <- 0
+ // +----+----+
+ // | LH | HH | <- ny1
+ // +----+----+
+ // <- ny2
+ nx1 = precinct->subbands[1].x1 - precinct->subbands[1].x0;
+ nx2 = nx1 + precinct->subbands[0].x1 - precinct->subbands[0].x0;
+ ny1 = precinct->subbands[0].y1 - precinct->subbands[0].y0;
+ ny2 = ny1 + precinct->subbands[1].y1 - precinct->subbands[1].y0;
+
+ // horizontal (row) transforms
+ if (r == tileComp->nDecompLevels) {
+ offset = 3 + (tileComp->x0 & 1);
+ } else {
+ offset = 3 + (tileComp->resLevels[r+1].x0 & 1);
+ }
+ for (y = 0, dataPtr = tileComp->data; y < ny2; ++y, dataPtr += tileComp->w) {
+ if (precinct->subbands[0].x0 == precinct->subbands[1].x0) {
+ // fetch LL/LH
+ for (x = 0, bufPtr = tileComp->buf + offset;
+ x < nx1;
+ ++x, bufPtr += 2) {
+ *bufPtr = dataPtr[x];
+ }
+ // fetch HL/HH
+ for (x = nx1, bufPtr = tileComp->buf + offset + 1;
+ x < nx2;
+ ++x, bufPtr += 2) {
+ *bufPtr = dataPtr[x];
+ }
+ } else {
+ // fetch LL/LH
+ for (x = 0, bufPtr = tileComp->buf + offset + 1;
+ x < nx1;
+ ++x, bufPtr += 2) {
+ *bufPtr = dataPtr[x];
+ }
+ // fetch HL/HH
+ for (x = nx1, bufPtr = tileComp->buf + offset;
+ x < nx2;
+ ++x, bufPtr += 2) {
+ *bufPtr = dataPtr[x];
+ }
+ }
+ if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
+ x = tileComp->x1 - tileComp->x0 + 5;
+ } else {
+ x = tileComp->y1 - tileComp->y0 + 5;
+ }
+ if (offset + nx2 > x || nx2 == 0) {
+ error(errSyntaxError, getPos(),
+ "Invalid call of inverseTransform1D in inverseTransformLevel in JPX stream");
+ return;
+ }
+ inverseTransform1D(tileComp, tileComp->buf, offset, nx2);
+ for (x = 0, bufPtr = tileComp->buf + offset; x < nx2; ++x, ++bufPtr) {
+ dataPtr[x] = *bufPtr;
+ }
+ }
+
+ // vertical (column) transforms
+ if (r == tileComp->nDecompLevels) {
+ offset = 3 + (tileComp->y0 & 1);
+ } else {
+ offset = 3 + (tileComp->resLevels[r+1].y0 & 1);
+ }
+ for (x = 0, dataPtr = tileComp->data; x < nx2; ++x, ++dataPtr) {
+ if (precinct->subbands[1].y0 == precinct->subbands[0].y0) {
+ // fetch LL/HL
+ for (y = 0, bufPtr = tileComp->buf + offset;
+ y < ny1;
+ ++y, bufPtr += 2) {
+ *bufPtr = dataPtr[y * tileComp->w];
+ }
+ // fetch LH/HH
+ for (y = ny1, bufPtr = tileComp->buf + offset + 1;
+ y < ny2;
+ ++y, bufPtr += 2) {
+ *bufPtr = dataPtr[y * tileComp->w];
+ }
+ } else {
+ // fetch LL/HL
+ for (y = 0, bufPtr = tileComp->buf + offset + 1;
+ y < ny1;
+ ++y, bufPtr += 2) {
+ *bufPtr = dataPtr[y * tileComp->w];
+ }
+ // fetch LH/HH
+ for (y = ny1, bufPtr = tileComp->buf + offset;
+ y < ny2;
+ ++y, bufPtr += 2) {
+ *bufPtr = dataPtr[y * tileComp->w];
+ }
+ }
+ if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
+ y = tileComp->x1 - tileComp->x0 + 5;
+ } else {
+ y = tileComp->y1 - tileComp->y0 + 5;
+ }
+ if (offset + ny2 > y || ny2 == 0) {
+ error(errSyntaxError, getPos(),
+ "Invalid call of inverseTransform1D in inverseTransformLevel in JPX stream");
+ return;
+ }
+ inverseTransform1D(tileComp, tileComp->buf, offset, ny2);
+ for (y = 0, bufPtr = tileComp->buf + offset; y < ny2; ++y, ++bufPtr) {
+ dataPtr[y * tileComp->w] = *bufPtr;
+ }
+ }
+}
+
+void JPXStream::inverseTransform1D(JPXTileComp *tileComp, int *data,
+ Guint offset, Guint n) {
+ Guint end, i;
+
+ //----- special case for length = 1
+ if (n == 1) {
+ cover(79);
+ if (offset == 4) {
+ cover(104);
+ *data >>= 1;
+ }
+
+ } else {
+ cover(80);
+
+ end = offset + n;
+
+ //----- extend right
+ data[end] = data[end - 2];
+ if (n == 2) {
+ cover(81);
+ data[end+1] = data[offset + 1];
+ data[end+2] = data[offset];
+ data[end+3] = data[offset + 1];
+ } else {
+ cover(82);
+ data[end+1] = data[end - 3];
+ if (n == 3) {
+ cover(105);
+ data[end+2] = data[offset + 1];
+ data[end+3] = data[offset + 2];
+ } else {
+ cover(106);
+ data[end+2] = data[end - 4];
+ if (n == 4) {
+ cover(107);
+ data[end+3] = data[offset + 1];
+ } else {
+ cover(108);
+ data[end+3] = data[end - 5];
+ }
+ }
+ }
+
+ //----- extend left
+ data[offset - 1] = data[offset + 1];
+ data[offset - 2] = data[offset + 2];
+ data[offset - 3] = data[offset + 3];
+ if (offset == 4) {
+ cover(83);
+ data[0] = data[offset + 4];
+ }
+
+ //----- 9-7 irreversible filter
+
+ if (tileComp->transform == 0) {
+ cover(84);
+ // step 1 (even)
+ for (i = 1; i <= end + 2; i += 2) {
+ data[i] = (int)(idwtKappa * data[i]);
+ }
+ // step 2 (odd)
+ for (i = 0; i <= end + 3; i += 2) {
+ data[i] = (int)(idwtIKappa * data[i]);
+ }
+ // step 3 (even)
+ for (i = 1; i <= end + 2; i += 2) {
+ data[i] = (int)(data[i] - idwtDelta * (data[i-1] + data[i+1]));
+ }
+ // step 4 (odd)
+ for (i = 2; i <= end + 1; i += 2) {
+ data[i] = (int)(data[i] - idwtGamma * (data[i-1] + data[i+1]));
+ }
+ // step 5 (even)
+ for (i = 3; i <= end; i += 2) {
+ data[i] = (int)(data[i] - idwtBeta * (data[i-1] + data[i+1]));
+ }
+ // step 6 (odd)
+ for (i = 4; i <= end - 1; i += 2) {
+ data[i] = (int)(data[i] - idwtAlpha * (data[i-1] + data[i+1]));
+ }
+
+ //----- 5-3 reversible filter
+
+ } else {
+ cover(85);
+ // step 1 (even)
+ for (i = 3; i <= end; i += 2) {
+ data[i] -= (data[i-1] + data[i+1] + 2) >> 2;
+ }
+ // step 2 (odd)
+ for (i = 4; i < end; i += 2) {
+ data[i] += (data[i-1] + data[i+1]) >> 1;
+ }
+ }
+ }
+}
+
+// Inverse multi-component transform and DC level shift. This also
+// converts fixed point samples back to integers.
+GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
+ JPXTileComp *tileComp;
+ int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal;
+ int *dataPtr;
+ Guint j, comp, x, y;
+
+ //----- inverse multi-component transform
+
+ if (tile->multiComp == 1) {
+ cover(86);
+ if (img.nComps < 3 ||
+ tile->tileComps[0].hSep != tile->tileComps[1].hSep ||
+ tile->tileComps[0].vSep != tile->tileComps[1].vSep ||
+ tile->tileComps[1].hSep != tile->tileComps[2].hSep ||
+ tile->tileComps[1].vSep != tile->tileComps[2].vSep) {
+ return gFalse;
+ }
+
+ // inverse irreversible multiple component transform
+ if (tile->tileComps[0].transform == 0) {
+ cover(87);
+ j = 0;
+ for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
+ for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
+ d0 = tile->tileComps[0].data[j];
+ d1 = tile->tileComps[1].data[j];
+ d2 = tile->tileComps[2].data[j];
+ tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5);
+ tile->tileComps[1].data[j] =
+ (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5);
+ tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5);
+ ++j;
+ }
+ }
+
+ // inverse reversible multiple component transform
+ } else {
+ cover(88);
+ j = 0;
+ for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
+ for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
+ d0 = tile->tileComps[0].data[j];
+ d1 = tile->tileComps[1].data[j];
+ d2 = tile->tileComps[2].data[j];
+ tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2);
+ tile->tileComps[0].data[j] = d2 + t;
+ tile->tileComps[2].data[j] = d1 + t;
+ ++j;
+ }
+ }
+ }
+ }
+
+ //----- DC level shift
+ for (comp = 0; comp < img.nComps; ++comp) {
+ tileComp = &tile->tileComps[comp];
+
+ // signed: clip
+ if (tileComp->sgned) {
+ cover(89);
+ minVal = -(1 << (tileComp->prec - 1));
+ maxVal = (1 << (tileComp->prec - 1)) - 1;
+ dataPtr = tileComp->data;
+ for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
+ for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
+ coeff = *dataPtr;
+ if (tileComp->transform == 0) {
+ cover(109);
+ coeff >>= fracBits;
+ }
+ if (coeff < minVal) {
+ cover(110);
+ coeff = minVal;
+ } else if (coeff > maxVal) {
+ cover(111);
+ coeff = maxVal;
+ }
+ *dataPtr++ = coeff;
+ }
+ }
+
+ // unsigned: inverse DC level shift and clip
+ } else {
+ cover(90);
+ maxVal = (1 << tileComp->prec) - 1;
+ zeroVal = 1 << (tileComp->prec - 1);
+ dataPtr = tileComp->data;
+ for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
+ for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
+ coeff = *dataPtr;
+ if (tileComp->transform == 0) {
+ cover(112);
+ coeff >>= fracBits;
+ }
+ coeff += zeroVal;
+ if (coeff < 0) {
+ cover(113);
+ coeff = 0;
+ } else if (coeff > maxVal) {
+ cover(114);
+ coeff = maxVal;
+ }
+ *dataPtr++ = coeff;
+ }
+ }
+ }
+ }
+
+ return gTrue;
+}
+
+GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) {
+ Guint len, lenH;
+
+ if (!readULong(&len) ||
+ !readULong(boxType)) {
+ return gFalse;
+ }
+ if (len == 1) {
+ if (!readULong(&lenH) || !readULong(&len)) {
+ return gFalse;
+ }
+ if (lenH) {
+ error(errSyntaxError, getPos(),
+ "JPX stream contains a box larger than 2^32 bytes");
+ return gFalse;
+ }
+ *boxLen = len;
+ *dataLen = len - 16;
+ } else if (len == 0) {
+ *boxLen = 0;
+ *dataLen = 0;
+ } else {
+ *boxLen = len;
+ *dataLen = len - 8;
+ }
+ return gTrue;
+}
+
+int JPXStream::readMarkerHdr(int *segType, Guint *segLen) {
+ int c;
+
+ do {
+ do {
+ if ((c = bufStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ } while (c != 0xff);
+ do {
+ if ((c = bufStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ } while (c == 0xff);
+ } while (c == 0x00);
+ *segType = c;
+ if ((c >= 0x30 && c <= 0x3f) ||
+ c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) {
+ *segLen = 0;
+ return gTrue;
+ }
+ return readUWord(segLen);
+}
+
+GBool JPXStream::readUByte(Guint *x) {
+ int c0;
+
+ if ((c0 = bufStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)c0;
+ return gTrue;
+}
+
+GBool JPXStream::readByte(int *x) {
+ int c0;
+
+ if ((c0 = bufStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = c0;
+ if (c0 & 0x80) {
+ *x |= -1 - 0xff;
+ }
+ return gTrue;
+}
+
+GBool JPXStream::readUWord(Guint *x) {
+ int c0, c1;
+
+ if ((c0 = bufStr->getChar()) == EOF ||
+ (c1 = bufStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)((c0 << 8) | c1);
+ return gTrue;
+}
+
+GBool JPXStream::readULong(Guint *x) {
+ int c0, c1, c2, c3;
+
+ if ((c0 = bufStr->getChar()) == EOF ||
+ (c1 = bufStr->getChar()) == EOF ||
+ (c2 = bufStr->getChar()) == EOF ||
+ (c3 = bufStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
+ return gTrue;
+}
+
+GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) {
+ int y, c, i;
+
+ y = 0;
+ for (i = 0; i < nBytes; ++i) {
+ if ((c = bufStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ y = (y << 8) + c;
+ }
+ if (signd) {
+ if (y & (1 << (8 * nBytes - 1))) {
+ y |= -1 << (8 * nBytes);
+ }
+ }
+ *x = y;
+ return gTrue;
+}
+
+void JPXStream::startBitBuf(Guint byteCountA) {
+ bitBufLen = 0;
+ bitBufSkip = gFalse;
+ byteCount = byteCountA;
+}
+
+GBool JPXStream::readBits(int nBits, Guint *x) {
+ int c;
+
+ while (bitBufLen < nBits) {
+ if (byteCount == 0 || (c = bufStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ --byteCount;
+ if (bitBufSkip) {
+ bitBuf = (bitBuf << 7) | (c & 0x7f);
+ bitBufLen += 7;
+ } else {
+ bitBuf = (bitBuf << 8) | (c & 0xff);
+ bitBufLen += 8;
+ }
+ bitBufSkip = c == 0xff;
+ }
+ *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1);
+ bitBufLen -= nBits;
+ return gTrue;
+}
+
+void JPXStream::skipSOP() {
+ int i;
+
+ // SOP occurs at the start of the packet header, so we don't need to
+ // worry about bit-stuff prior to it
+ if (byteCount >= 6 &&
+ bufStr->lookChar(0) == 0xff &&
+ bufStr->lookChar(1) == 0x91) {
+ for (i = 0; i < 6; ++i) {
+ bufStr->getChar();
+ }
+ byteCount -= 6;
+ bitBufLen = 0;
+ bitBufSkip = gFalse;
+ }
+}
+
+void JPXStream::skipEPH() {
+ int i, k;
+
+ k = bitBufSkip ? 1 : 0;
+ if (byteCount >= (Guint)(k + 2) &&
+ bufStr->lookChar(k) == 0xff &&
+ bufStr->lookChar(k + 1) == 0x92) {
+ for (i = 0; i < k + 2; ++i) {
+ bufStr->getChar();
+ }
+ byteCount -= k + 2;
+ bitBufLen = 0;
+ bitBufSkip = gFalse;
+ }
+}
+
+Guint JPXStream::finishBitBuf() {
+ if (bitBufSkip) {
+ bufStr->getChar();
+ --byteCount;
+ }
+ return byteCount;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/JPXStream.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/JPXStream.h
new file mode 100644
index 00000000000..30855431fb4
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/JPXStream.h
@@ -0,0 +1,338 @@
+//========================================================================
+//
+// JPXStream.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef JPXSTREAM_H
+#define JPXSTREAM_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "Object.h"
+#include "Stream.h"
+
+class JArithmeticDecoder;
+class JArithmeticDecoderStats;
+
+//------------------------------------------------------------------------
+
+enum JPXColorSpaceType {
+ jpxCSBiLevel = 0,
+ jpxCSYCbCr1 = 1,
+ jpxCSYCbCr2 = 3,
+ jpxCSYCBCr3 = 4,
+ jpxCSPhotoYCC = 9,
+ jpxCSCMY = 11,
+ jpxCSCMYK = 12,
+ jpxCSYCCK = 13,
+ jpxCSCIELab = 14,
+ jpxCSsRGB = 16,
+ jpxCSGrayscale = 17,
+ jpxCSBiLevel2 = 18,
+ jpxCSCIEJab = 19,
+ jpxCSCISesRGB = 20,
+ jpxCSROMMRGB = 21,
+ jpxCSsRGBYCbCr = 22,
+ jpxCSYPbPr1125 = 23,
+ jpxCSYPbPr1250 = 24
+};
+
+struct JPXColorSpecCIELab {
+ Guint rl, ol, ra, oa, rb, ob, il;
+};
+
+struct JPXColorSpecEnumerated {
+ JPXColorSpaceType type; // color space type
+ union {
+ JPXColorSpecCIELab cieLab;
+ };
+};
+
+struct JPXColorSpec {
+ Guint meth; // method
+ int prec; // precedence
+ union {
+ JPXColorSpecEnumerated enumerated;
+ };
+};
+
+//------------------------------------------------------------------------
+
+struct JPXPalette {
+ Guint nEntries; // number of entries in the palette
+ Guint nComps; // number of components in each entry
+ Guint *bpc; // bits per component, for each component
+ int *c; // color data:
+ // c[i*nComps+j] = entry i, component j
+};
+
+//------------------------------------------------------------------------
+
+struct JPXCompMap {
+ Guint nChannels; // number of channels
+ Guint *comp; // codestream components mapped to each channel
+ Guint *type; // 0 for direct use, 1 for palette mapping
+ Guint *pComp; // palette components to use
+};
+
+//------------------------------------------------------------------------
+
+struct JPXChannelDefn {
+ Guint nChannels; // number of channels
+ Guint *idx; // channel indexes
+ Guint *type; // channel types
+ Guint *assoc; // channel associations
+};
+
+//------------------------------------------------------------------------
+
+struct JPXTagTreeNode {
+ GBool finished; // true if this node is finished
+ Guint val; // current value
+};
+
+//------------------------------------------------------------------------
+
+struct JPXCodeBlock {
+ //----- size
+ Guint x0, y0, x1, y1; // bounds
+
+ //----- persistent state
+ GBool seen; // true if this code-block has already
+ // been seen
+ Guint lBlock; // base number of bits used for pkt data length
+ Guint nextPass; // next coding pass
+
+ //---- info from first packet
+ Guint nZeroBitPlanes; // number of zero bit planes
+
+ //----- info for the current packet
+ Guint included; // code-block inclusion in this packet:
+ // 0=not included, 1=included
+ Guint nCodingPasses; // number of coding passes in this pkt
+ Guint *dataLen; // data lengths (one per codeword segment)
+ Guint dataLenSize; // size of the dataLen array
+
+ //----- coefficient data
+ int *coeffs;
+ char *touched; // coefficient 'touched' flags
+ Gushort len; // coefficient length
+ JArithmeticDecoder // arithmetic decoder
+ *arithDecoder;
+ JArithmeticDecoderStats // arithmetic decoder stats
+ *stats;
+};
+
+//------------------------------------------------------------------------
+
+struct JPXSubband {
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds
+ Guint nXCBs, nYCBs; // number of code-blocks in the x and y
+ // directions
+
+ //----- tag trees
+ Guint maxTTLevel; // max tag tree level
+ JPXTagTreeNode *inclusion; // inclusion tag tree for each subband
+ JPXTagTreeNode *zeroBitPlane; // zero-bit plane tag tree for each
+ // subband
+
+ //----- children
+ JPXCodeBlock *cbs; // the code-blocks (len = nXCBs * nYCBs)
+};
+
+//------------------------------------------------------------------------
+
+struct JPXPrecinct {
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds of the precinct
+
+ //----- children
+ JPXSubband *subbands; // the subbands
+};
+
+//------------------------------------------------------------------------
+
+struct JPXResLevel {
+ //----- from the COD and COC segments (main and tile)
+ Guint precinctWidth; // log2(precinct width)
+ Guint precinctHeight; // log2(precinct height)
+
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds of the tile-comp (for this res level)
+ Guint bx0[3], by0[3], // subband bounds
+ bx1[3], by1[3];
+
+ //---- children
+ JPXPrecinct *precincts; // the precincts
+};
+
+//------------------------------------------------------------------------
+
+struct JPXTileComp {
+ //----- from the SIZ segment
+ GBool sgned; // 1 for signed, 0 for unsigned
+ Guint prec; // precision, in bits
+ Guint hSep; // horizontal separation of samples
+ Guint vSep; // vertical separation of samples
+
+ //----- from the COD and COC segments (main and tile)
+ Guint style; // coding style parameter (Scod / Scoc)
+ Guint nDecompLevels; // number of decomposition levels
+ Guint codeBlockW; // log2(code-block width)
+ Guint codeBlockH; // log2(code-block height)
+ Guint codeBlockStyle; // code-block style
+ Guint transform; // wavelet transformation
+
+ //----- from the QCD and QCC segments (main and tile)
+ Guint quantStyle; // quantization style
+ Guint *quantSteps; // quantization step size for each subband
+ Guint nQuantSteps; // number of entries in quantSteps
+
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds of the tile-comp, in ref coords
+ Guint w; // x1 - x0
+ Guint cbW; // code-block width
+ Guint cbH; // code-block height
+
+ //----- image data
+ int *data; // the decoded image data
+ int *buf; // intermediate buffer for the inverse
+ // transform
+
+ //----- children
+ JPXResLevel *resLevels; // the resolution levels
+ // (len = nDecompLevels + 1)
+};
+
+//------------------------------------------------------------------------
+
+struct JPXTile {
+ GBool init;
+
+ //----- from the COD segments (main and tile)
+ Guint progOrder; // progression order
+ Guint nLayers; // number of layers
+ Guint multiComp; // multiple component transformation
+
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds of the tile, in ref coords
+ Guint maxNDecompLevels; // max number of decomposition levels used
+ // in any component in this tile
+
+ //----- progression order loop counters
+ Guint comp; // component
+ Guint res; // resolution level
+ Guint precinct; // precinct
+ Guint layer; // layer
+
+ //----- children
+ JPXTileComp *tileComps; // the tile-components (len = JPXImage.nComps)
+};
+
+//------------------------------------------------------------------------
+
+struct JPXImage {
+ //----- from the SIZ segment
+ Guint xSize, ySize; // size of reference grid
+ Guint xOffset, yOffset; // image offset
+ Guint xTileSize, yTileSize; // size of tiles
+ Guint xTileOffset, // offset of first tile
+ yTileOffset;
+ Guint nComps; // number of components
+
+ //----- computed
+ Guint nXTiles; // number of tiles in x direction
+ Guint nYTiles; // number of tiles in y direction
+
+ //----- children
+ JPXTile *tiles; // the tiles (len = nXTiles * nYTiles)
+};
+
+//------------------------------------------------------------------------
+
+class JPXStream: public FilterStream {
+public:
+
+ JPXStream(Stream *strA);
+ virtual ~JPXStream();
+ virtual StreamKind getKind() { return strJPX; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+ virtual void getImageParams(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode);
+
+private:
+
+ void fillReadBuf();
+ void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode);
+ GBool readBoxes();
+ GBool readColorSpecBox(Guint dataLen);
+ GBool readCodestream(Guint len);
+ GBool readTilePart();
+ GBool readTilePartData(Guint tileIdx,
+ Guint tilePartLen, GBool tilePartToEOC);
+ GBool readCodeBlockData(JPXTileComp *tileComp,
+ JPXResLevel *resLevel,
+ JPXPrecinct *precinct,
+ JPXSubband *subband,
+ Guint res, Guint sb,
+ JPXCodeBlock *cb);
+ void inverseTransform(JPXTileComp *tileComp);
+ void inverseTransformLevel(JPXTileComp *tileComp,
+ Guint r, JPXResLevel *resLevel);
+ void inverseTransform1D(JPXTileComp *tileComp, int *data,
+ Guint offset, Guint n);
+ GBool inverseMultiCompAndDC(JPXTile *tile);
+ GBool readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen);
+ int readMarkerHdr(int *segType, Guint *segLen);
+ GBool readUByte(Guint *x);
+ GBool readByte(int *x);
+ GBool readUWord(Guint *x);
+ GBool readULong(Guint *x);
+ GBool readNBytes(int nBytes, GBool signd, int *x);
+ void startBitBuf(Guint byteCountA);
+ GBool readBits(int nBits, Guint *x);
+ void skipSOP();
+ void skipEPH();
+ Guint finishBitBuf();
+
+ BufStream *bufStr; // buffered stream (for lookahead)
+
+ Guint nComps; // number of components
+ Guint *bpc; // bits per component, for each component
+ Guint width, height; // image size
+ GBool haveImgHdr; // set if a JP2/JPX image header has been
+ // found
+ JPXColorSpec cs; // color specification
+ GBool haveCS; // set if a color spec has been found
+ JPXPalette palette; // the palette
+ GBool havePalette; // set if a palette has been found
+ JPXCompMap compMap; // the component mapping
+ GBool haveCompMap; // set if a component mapping has been found
+ JPXChannelDefn channelDefn; // channel definition
+ GBool haveChannelDefn; // set if a channel defn has been found
+
+ JPXImage img; // JPEG2000 decoder data
+ Guint bitBuf; // buffer for bit reads
+ int bitBufLen; // number of bits in bitBuf
+ GBool bitBufSkip; // true if next bit should be skipped
+ // (for bit stuffing)
+ Guint byteCount; // number of available bytes left
+
+ Guint curX, curY, curComp; // current position for lookChar/getChar
+ Guint readBuf; // read buffer
+ Guint readBufLen; // number of valid bits in readBuf
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Lexer.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Lexer.cc
new file mode 100644
index 00000000000..952967a998a
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Lexer.cc
@@ -0,0 +1,645 @@
+//========================================================================
+//
+// Lexer.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006-2010, 2012-2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2012, 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include "Lexer.h"
+#include "Error.h"
+#include "XRef.h"
+
+//------------------------------------------------------------------------
+
+// A '1' in this array means the character is white space. A '1' or
+// '2' means the character ends a name or command.
+static const char specialChars[256] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
+ 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
+};
+
+static const int IntegerSafeLimit = (INT_MAX - 9) / 10;
+static const long long LongLongSafeLimit = (LLONG_MAX - 9) / 10;
+
+//------------------------------------------------------------------------
+// Lexer
+//------------------------------------------------------------------------
+
+Lexer::Lexer(XRef *xrefA, Stream *str) {
+ Object obj;
+
+ lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
+ xref = xrefA;
+
+ curStr.initStream(str);
+ streams = new Array(xref);
+ streams->add(curStr.copy(&obj));
+ strPtr = 0;
+ freeArray = gTrue;
+ curStr.streamReset();
+}
+
+Lexer::Lexer(XRef *xrefA, Object *obj) {
+ Object obj2;
+
+ lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
+ xref = xrefA;
+
+ if (obj->isStream()) {
+ streams = new Array(xref);
+ freeArray = gTrue;
+ streams->add(obj->copy(&obj2));
+ } else {
+ streams = obj->getArray();
+ freeArray = gFalse;
+ }
+ strPtr = 0;
+ if (streams->getLength() > 0) {
+ streams->get(strPtr, &curStr);
+ curStr.streamReset();
+ }
+}
+
+Lexer::~Lexer() {
+ if (!curStr.isNone()) {
+ curStr.streamClose();
+ curStr.free();
+ }
+ if (freeArray) {
+ delete streams;
+ }
+}
+
+int Lexer::getChar(GBool comesFromLook) {
+ int c;
+
+ if (LOOK_VALUE_NOT_CACHED != lookCharLastValueCached) {
+ c = lookCharLastValueCached;
+ lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
+ return c;
+ }
+
+ c = EOF;
+ while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) {
+ if (comesFromLook == gTrue) {
+ return EOF;
+ } else {
+ curStr.streamClose();
+ curStr.free();
+ ++strPtr;
+ if (strPtr < streams->getLength()) {
+ streams->get(strPtr, &curStr);
+ curStr.streamReset();
+ }
+ }
+ }
+ return c;
+}
+
+int Lexer::lookChar() {
+
+ if (LOOK_VALUE_NOT_CACHED != lookCharLastValueCached) {
+ return lookCharLastValueCached;
+ }
+ lookCharLastValueCached = getChar(gTrue);
+ if (lookCharLastValueCached == EOF) {
+ lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
+ return EOF;
+ } else {
+ return lookCharLastValueCached;
+ }
+}
+
+Object *Lexer::getObj(Object *obj, int objNum) {
+ char *p;
+ int c, c2;
+ GBool comment, neg, done, overflownInteger, overflownLongLong;
+ int numParen;
+ int xi;
+ long long xll = 0;
+ double xf = 0, scale;
+ GooString *s;
+ int n, m;
+
+ // skip whitespace and comments
+ comment = gFalse;
+ while (1) {
+ if ((c = getChar()) == EOF) {
+ return obj->initEOF();
+ }
+ if (comment) {
+ if (c == '\r' || c == '\n')
+ comment = gFalse;
+ } else if (c == '%') {
+ comment = gTrue;
+ } else if (specialChars[c] != 1) {
+ break;
+ }
+ }
+
+ // start reading token
+ switch (c) {
+
+ // number
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '+': case '-': case '.':
+ overflownInteger = gFalse;
+ overflownLongLong = gFalse;
+ neg = gFalse;
+ xi = 0;
+ if (c == '-') {
+ neg = gTrue;
+ } else if (c == '.') {
+ goto doReal;
+ } else if (c != '+') {
+ xi = c - '0';
+ }
+ while (1) {
+ c = lookChar();
+ if (isdigit(c)) {
+ getChar();
+ if (unlikely(overflownLongLong)) {
+ xf = xf * 10.0 + (c - '0');
+ } else if (unlikely (overflownInteger)) {
+ if (unlikely(xll > LongLongSafeLimit) &&
+ (xll > (LLONG_MAX - (c - '0')) / 10.0)) {
+ overflownLongLong = gTrue;
+ xf = xll * 10.0 + (c - '0');
+ } else {
+ xll = xll * 10 + (c - '0');
+ }
+ } else {
+ if (unlikely(xi > IntegerSafeLimit) &&
+ (xi > (INT_MAX - (c - '0')) / 10.0)) {
+ overflownInteger = gTrue;
+ xll = xi * 10LL + (c - '0');
+ } else {
+ xi = xi * 10 + (c - '0');
+ }
+ }
+ } else if (c == '.') {
+ getChar();
+ goto doReal;
+ } else {
+ break;
+ }
+ }
+ if (neg) {
+ xi = -xi;
+ xll = -xll;
+ xf = -xf;
+ }
+ if (unlikely(overflownInteger)) {
+ if (overflownLongLong) {
+ obj->initReal(xf);
+ } else {
+ if (unlikely(xll == INT_MIN)) {
+ obj->initInt(INT_MIN);
+ } else {
+ obj->initInt64(xll);
+ }
+ }
+ } else {
+ obj->initInt(xi);
+ }
+ break;
+ doReal:
+ if (likely(!overflownInteger)) {
+ xf = xi;
+ } else if (!overflownLongLong) {
+ xf = xll;
+ }
+ scale = 0.1;
+ while (1) {
+ c = lookChar();
+ if (c == '-') {
+ // ignore minus signs in the middle of numbers to match
+ // Adobe's behavior
+ error(errSyntaxWarning, getPos(), "Badly formatted number");
+ getChar();
+ continue;
+ }
+ if (!isdigit(c)) {
+ break;
+ }
+ getChar();
+ xf = xf + scale * (c - '0');
+ scale *= 0.1;
+ }
+ if (neg) {
+ xf = -xf;
+ }
+ obj->initReal(xf);
+ break;
+
+ // string
+ case '(':
+ p = tokBuf;
+ n = 0;
+ numParen = 1;
+ done = gFalse;
+ s = NULL;
+ do {
+ c2 = EOF;
+ switch (c = getChar()) {
+
+ case EOF:
+#if 0
+ // This breaks some PDF files, e.g., ones from Photoshop.
+ case '\r':
+ case '\n':
+#endif
+ error(errSyntaxError, getPos(), "Unterminated string");
+ done = gTrue;
+ break;
+
+ case '(':
+ ++numParen;
+ c2 = c;
+ break;
+
+ case ')':
+ if (--numParen == 0) {
+ done = gTrue;
+ } else {
+ c2 = c;
+ }
+ break;
+
+ case '\\':
+ switch (c = getChar()) {
+ case 'n':
+ c2 = '\n';
+ break;
+ case 'r':
+ c2 = '\r';
+ break;
+ case 't':
+ c2 = '\t';
+ break;
+ case 'b':
+ c2 = '\b';
+ break;
+ case 'f':
+ c2 = '\f';
+ break;
+ case '\\':
+ case '(':
+ case ')':
+ c2 = c;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c2 = c - '0';
+ c = lookChar();
+ if (c >= '0' && c <= '7') {
+ getChar();
+ c2 = (c2 << 3) + (c - '0');
+ c = lookChar();
+ if (c >= '0' && c <= '7') {
+ getChar();
+ c2 = (c2 << 3) + (c - '0');
+ }
+ }
+ break;
+ case '\r':
+ c = lookChar();
+ if (c == '\n') {
+ getChar();
+ }
+ break;
+ case '\n':
+ break;
+ case EOF:
+ error(errSyntaxError, getPos(), "Unterminated string");
+ done = gTrue;
+ break;
+ default:
+ c2 = c;
+ break;
+ }
+ break;
+
+ default:
+ c2 = c;
+ break;
+ }
+
+ if (c2 != EOF) {
+ if (n == tokBufSize) {
+ if (!s)
+ s = new GooString(tokBuf, tokBufSize);
+ else
+ s->append(tokBuf, tokBufSize);
+ p = tokBuf;
+ n = 0;
+
+ // we are growing see if the document is not malformed and we are growing too much
+ if (objNum > 0 && xref != NULL)
+ {
+ int newObjNum = xref->getNumEntry(curStr.streamGetPos());
+ if (newObjNum != objNum)
+ {
+ error(errSyntaxError, getPos(), "Unterminated string");
+ done = gTrue;
+ delete s;
+ n = -2;
+ }
+ }
+ }
+ *p++ = (char)c2;
+ ++n;
+ }
+ } while (!done);
+ if (n >= 0) {
+ if (!s)
+ s = new GooString(tokBuf, n);
+ else
+ s->append(tokBuf, n);
+ obj->initString(s);
+ } else {
+ obj->initEOF();
+ }
+ break;
+
+ // name
+ case '/':
+ p = tokBuf;
+ n = 0;
+ s = NULL;
+ while ((c = lookChar()) != EOF && !specialChars[c]) {
+ getChar();
+ if (c == '#') {
+ c2 = lookChar();
+ if (c2 >= '0' && c2 <= '9') {
+ c = c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ c = c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ c = c2 - 'a' + 10;
+ } else {
+ goto notEscChar;
+ }
+ getChar();
+ c <<= 4;
+ c2 = getChar();
+ if (c2 >= '0' && c2 <= '9') {
+ c += c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ c += c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ c += c2 - 'a' + 10;
+ } else {
+ error(errSyntaxError, getPos(), "Illegal digit in hex char in name");
+ }
+ }
+ notEscChar:
+ // the PDF spec claims that names are limited to 127 chars, but
+ // Distiller 8 will produce longer names, and Acrobat 8 will
+ // accept longer names
+ ++n;
+ if (n < tokBufSize) {
+ *p++ = c;
+ } else if (n == tokBufSize) {
+ error(errSyntaxError, getPos(), "Warning: name token is longer than what the specification says it can be");
+ *p = c;
+ s = new GooString(tokBuf, n);
+ } else {
+ s->append((char)c);
+ }
+ }
+ if (n < tokBufSize) {
+ *p = '\0';
+ obj->initName(tokBuf);
+ } else {
+ obj->initName(s->getCString());
+ delete s;
+ }
+ break;
+
+ // array punctuation
+ case '[':
+ case ']':
+ tokBuf[0] = c;
+ tokBuf[1] = '\0';
+ obj->initCmd(tokBuf);
+ break;
+
+ // hex string or dict punctuation
+ case '<':
+ c = lookChar();
+
+ // dict punctuation
+ if (c == '<') {
+ getChar();
+ tokBuf[0] = tokBuf[1] = '<';
+ tokBuf[2] = '\0';
+ obj->initCmd(tokBuf);
+
+ // hex string
+ } else {
+ p = tokBuf;
+ m = n = 0;
+ c2 = 0;
+ s = NULL;
+ while (1) {
+ c = getChar();
+ if (c == '>') {
+ break;
+ } else if (c == EOF) {
+ error(errSyntaxError, getPos(), "Unterminated hex string");
+ break;
+ } else if (specialChars[c] != 1) {
+ c2 = c2 << 4;
+ if (c >= '0' && c <= '9')
+ c2 += c - '0';
+ else if (c >= 'A' && c <= 'F')
+ c2 += c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ c2 += c - 'a' + 10;
+ else
+ error(errSyntaxError, getPos(), "Illegal character <{0:02x}> in hex string", c);
+ if (++m == 2) {
+ if (n == tokBufSize) {
+ if (!s)
+ s = new GooString(tokBuf, tokBufSize);
+ else
+ s->append(tokBuf, tokBufSize);
+ p = tokBuf;
+ n = 0;
+ }
+ *p++ = (char)c2;
+ ++n;
+ c2 = 0;
+ m = 0;
+ }
+ }
+ }
+ if (!s)
+ s = new GooString(tokBuf, n);
+ else
+ s->append(tokBuf, n);
+ if (m == 1)
+ s->append((char)(c2 << 4));
+ obj->initString(s);
+ }
+ break;
+
+ // dict punctuation
+ case '>':
+ c = lookChar();
+ if (c == '>') {
+ getChar();
+ tokBuf[0] = tokBuf[1] = '>';
+ tokBuf[2] = '\0';
+ obj->initCmd(tokBuf);
+ } else {
+ error(errSyntaxError, getPos(), "Illegal character '>'");
+ obj->initError();
+ }
+ break;
+
+ // error
+ case ')':
+ case '{':
+ case '}':
+ error(errSyntaxError, getPos(), "Illegal character '{0:c}'", c);
+ obj->initError();
+ break;
+
+ // command
+ default:
+ p = tokBuf;
+ *p++ = c;
+ n = 1;
+ while ((c = lookChar()) != EOF && !specialChars[c]) {
+ getChar();
+ if (++n == tokBufSize) {
+ error(errSyntaxError, getPos(), "Command token too long");
+ break;
+ }
+ *p++ = c;
+ }
+ *p = '\0';
+ if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) {
+ obj->initBool(gTrue);
+ } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) {
+ obj->initBool(gFalse);
+ } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) {
+ obj->initNull();
+ } else {
+ obj->initCmd(tokBuf);
+ }
+ break;
+ }
+
+ return obj;
+}
+
+Object *Lexer::getObj(Object *obj, const char *cmdA, int objNum) {
+ char *p;
+ int c;
+ GBool comment;
+ int n;
+
+ // skip whitespace and comments
+ comment = gFalse;
+ const char *cmd1 = tokBuf;
+ *tokBuf = 0;
+ while (strcmp(cmdA, cmd1) && (objNum < 0 || (xref && xref->getNumEntry(getPos()) == objNum))) {
+ while (1) {
+ if ((c = getChar()) == EOF) {
+ return obj->initEOF();
+ }
+ if (comment) {
+ if (c == '\r' || c == '\n') {
+ comment = gFalse;
+ }
+ } else if (c == '%') {
+ comment = gTrue;
+ } else if (specialChars[c] != 1) {
+ break;
+ }
+ }
+ p = tokBuf;
+ *p++ = c;
+ n = 1;
+ while ((c = lookChar()) != EOF && specialChars[c] == 0) {
+ getChar();
+ if (++n == tokBufSize) {
+ break;
+ }
+ *p++ = c;
+ }
+ *p = '\0';
+ }
+ obj->initCmd(tokBuf);
+
+ return obj;
+}
+
+void Lexer::skipToNextLine() {
+ int c;
+
+ while (1) {
+ c = getChar();
+ if (c == EOF || c == '\n') {
+ return;
+ }
+ if (c == '\r') {
+ if ((c = lookChar()) == '\n') {
+ getChar();
+ }
+ return;
+ }
+ }
+}
+
+GBool Lexer::isSpace(int c) {
+ return c >= 0 && c <= 0xff && specialChars[c] == 1;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Lexer.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Lexer.h
new file mode 100644
index 00000000000..02b6cdc6923
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Lexer.h
@@ -0,0 +1,108 @@
+//========================================================================
+//
+// Lexer.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2007, 2010, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+#include "Stream.h"
+
+class XRef;
+
+#define tokBufSize 128 // size of token buffer
+
+//------------------------------------------------------------------------
+// Lexer
+//------------------------------------------------------------------------
+
+class Lexer {
+public:
+
+ // Construct a lexer for a single stream. Deletes the stream when
+ // lexer is deleted.
+ Lexer(XRef *xrefA, Stream *str);
+
+ // Construct a lexer for a stream or array of streams (assumes obj
+ // is either a stream or array of streams).
+ Lexer(XRef *xrefA, Object *obj);
+
+ // Destructor.
+ ~Lexer();
+
+ // Get the next object from the input stream.
+ Object *getObj(Object *obj, int objNum = -1);
+ Object *getObj(Object *obj, const char *cmdA, int objNum);
+
+ // Skip to the beginning of the next line in the input stream.
+ void skipToNextLine();
+
+ // Skip over one character.
+ void skipChar() { getChar(); }
+
+ // Get stream.
+ Stream *getStream()
+ { return curStr.isStream() ? curStr.getStream() : (Stream *)NULL; }
+
+ // Get current position in file. This is only used for error
+ // messages.
+ Goffset getPos()
+ { return curStr.isStream() ? curStr.streamGetPos() : -1; }
+
+ // Set position in file.
+ void setPos(Goffset pos, int dir = 0)
+ { if (curStr.isStream()) curStr.streamSetPos(pos, dir); }
+
+ // Returns true if <c> is a whitespace character.
+ static GBool isSpace(int c);
+
+
+ // often (e.g. ~30% on PDF Refernce 1.6 pdf file from Adobe site) getChar
+ // is called right after lookChar. In order to avoid expensive re-doing
+ // getChar() of underlying stream, we cache the last value found by
+ // lookChar() in lookCharLastValueCached. A special value
+ // LOOK_VALUE_NOT_CACHED that should never be part of stream indicates
+ // that no value was cached
+ static const int LOOK_VALUE_NOT_CACHED = -3;
+ int lookCharLastValueCached;
+
+private:
+
+ int getChar(GBool comesFromLook = gFalse);
+ int lookChar();
+
+ Array *streams; // array of input streams
+ int strPtr; // index of current stream
+ Object curStr; // current stream
+ GBool freeArray; // should lexer free the streams array?
+ char tokBuf[tokBufSize]; // temporary token buffer
+
+ XRef *xref;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Linearization.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Linearization.cc
new file mode 100644
index 00000000000..be041f96407
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Linearization.cc
@@ -0,0 +1,223 @@
+//========================================================================
+//
+// Linearization.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010, 2012 Hib Eris <hib@hiberis.nl>
+// Copyright 2015 Jason Crain <jason@aquaticape.us>
+//
+//========================================================================
+
+#include "Linearization.h"
+#include "Parser.h"
+#include "Lexer.h"
+
+//------------------------------------------------------------------------
+// Linearization
+//------------------------------------------------------------------------
+
+Linearization::Linearization (BaseStream *str)
+{
+ Parser *parser;
+ Object obj1, obj2, obj3, obj5;
+
+ linDict.initNull();
+
+ str->reset();
+ obj1.initNull();
+ parser = new Parser(NULL,
+ new Lexer(NULL, str->makeSubStream(str->getStart(), gFalse, 0, &obj1)),
+ gFalse);
+ parser->getObj(&obj1);
+ parser->getObj(&obj2);
+ parser->getObj(&obj3);
+ parser->getObj(&linDict);
+ if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && linDict.isDict()) {
+ linDict.dictLookup("Linearized", &obj5);
+ if (!(obj5.isNum() && obj5.getNum() > 0)) {
+ linDict.free();
+ linDict.initNull();
+ }
+ obj5.free();
+ }
+ obj3.free();
+ obj2.free();
+ obj1.free();
+ delete parser;
+}
+
+Linearization:: ~Linearization()
+{
+ linDict.free();
+}
+
+Guint Linearization::getLength()
+{
+ if (!linDict.isDict()) return 0;
+
+ int length;
+ if (linDict.getDict()->lookupInt("L", NULL, &length) &&
+ length > 0) {
+ return length;
+ } else {
+ error(errSyntaxWarning, -1, "Length in linearization table is invalid");
+ return 0;
+ }
+}
+
+Guint Linearization::getHintsOffset()
+{
+ int hintsOffset;
+
+ Object obj1, obj2;
+ if (linDict.isDict() &&
+ linDict.dictLookup("H", &obj1)->isArray() &&
+ obj1.arrayGetLength()>=2 &&
+ obj1.arrayGet(0, &obj2)->isInt() &&
+ obj2.getInt() > 0) {
+ hintsOffset = obj2.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Hints table offset in linearization table is invalid");
+ hintsOffset = 0;
+ }
+ obj2.free();
+ obj1.free();
+
+ return hintsOffset;
+}
+
+Guint Linearization::getHintsLength()
+{
+ int hintsLength;
+
+ Object obj1, obj2;
+ if (linDict.isDict() &&
+ linDict.dictLookup("H", &obj1)->isArray() &&
+ obj1.arrayGetLength()>=2 &&
+ obj1.arrayGet(1, &obj2)->isInt() &&
+ obj2.getInt() > 0) {
+ hintsLength = obj2.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Hints table length in linearization table is invalid");
+ hintsLength = 0;
+ }
+ obj2.free();
+ obj1.free();
+
+ return hintsLength;
+}
+
+Guint Linearization::getHintsOffset2()
+{
+ int hintsOffset2 = 0; // default to 0
+
+ Object obj1, obj2;
+ if (linDict.isDict() &&
+ linDict.dictLookup("H", &obj1)->isArray() &&
+ obj1.arrayGetLength()>=4) {
+ if (obj1.arrayGet(2, &obj2)->isInt() &&
+ obj2.getInt() > 0) {
+ hintsOffset2 = obj2.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Second hints table offset in linearization table is invalid");
+ hintsOffset2 = 0;
+ }
+ }
+ obj2.free();
+ obj1.free();
+
+ return hintsOffset2;
+}
+
+Guint Linearization::getHintsLength2()
+{
+ int hintsLength2 = 0; // default to 0
+
+ Object obj1, obj2;
+ if (linDict.isDict() &&
+ linDict.dictLookup("H", &obj1)->isArray() &&
+ obj1.arrayGetLength()>=4) {
+ if (obj1.arrayGet(3, &obj2)->isInt() &&
+ obj2.getInt() > 0) {
+ hintsLength2 = obj2.getInt();
+ } else {
+ error(errSyntaxWarning, -1, "Second hints table length in linearization table is invalid");
+ hintsLength2 = 0;
+ }
+ }
+ obj2.free();
+ obj1.free();
+
+ return hintsLength2;
+}
+
+int Linearization::getObjectNumberFirst()
+{
+ int objectNumberFirst = 0;
+ if (linDict.isDict() &&
+ linDict.getDict()->lookupInt("O", NULL, &objectNumberFirst) &&
+ objectNumberFirst > 0) {
+ return objectNumberFirst;
+ } else {
+ error(errSyntaxWarning, -1, "Object number of first page in linearization table is invalid");
+ return 0;
+ }
+}
+
+Guint Linearization::getEndFirst()
+{
+ int pageEndFirst = 0;
+ if (linDict.isDict() &&
+ linDict.getDict()->lookupInt("E", NULL, &pageEndFirst) &&
+ pageEndFirst > 0) {
+ return pageEndFirst;
+ } else {
+ error(errSyntaxWarning, -1, "First page end offset in linearization table is invalid");
+ return 0;
+ }
+}
+
+int Linearization::getNumPages()
+{
+ int numPages = 0;
+ if (linDict.isDict() &&
+ linDict.getDict()->lookupInt("N", NULL, &numPages) &&
+ numPages > 0) {
+ return numPages;
+ } else {
+ error(errSyntaxWarning, -1, "Page count in linearization table is invalid");
+ return 0;
+ }
+}
+
+Guint Linearization::getMainXRefEntriesOffset()
+{
+ int mainXRefEntriesOffset = 0;
+ if (linDict.isDict() &&
+ linDict.getDict()->lookupInt("T", NULL, &mainXRefEntriesOffset) &&
+ mainXRefEntriesOffset > 0) {
+ return mainXRefEntriesOffset;
+ } else {
+ error(errSyntaxWarning, -1, "Main Xref offset in linearization table is invalid");
+ return 0;
+ }
+}
+
+int Linearization::getPageFirst()
+{
+ int pageFirst = 0; // Optional, defaults to 0.
+
+ if (linDict.isDict()) {
+ linDict.getDict()->lookupInt("P", NULL, &pageFirst);
+ }
+
+ if ((pageFirst < 0) || (pageFirst >= getNumPages())) {
+ error(errSyntaxWarning, -1, "First page in linearization table is invalid");
+ return 0;
+ }
+
+ return pageFirst;
+}
+
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Linearization.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Linearization.h
new file mode 100644
index 00000000000..6728a750aba
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Linearization.h
@@ -0,0 +1,45 @@
+//========================================================================
+//
+// Linearization.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+//
+//========================================================================
+
+#ifndef LINEARIZATION_H
+#define LINEARIZATION_H
+
+#include "goo/gtypes.h"
+#include "Object.h"
+class BaseStream;
+
+//------------------------------------------------------------------------
+// Linearization
+//------------------------------------------------------------------------
+
+class Linearization {
+public:
+
+ Linearization(BaseStream *str);
+ ~Linearization();
+
+ Guint getLength();
+ Guint getHintsOffset();
+ Guint getHintsLength();
+ Guint getHintsOffset2();
+ Guint getHintsLength2();
+ int getObjectNumberFirst();
+ Guint getEndFirst();
+ int getNumPages();
+ Guint getMainXRefEntriesOffset();
+ int getPageFirst();
+
+private:
+
+ Object linDict;
+
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Link.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Link.cc
new file mode 100644
index 00000000000..4ab5f52ceda
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Link.cc
@@ -0,0 +1,951 @@
+//========================================================================
+//
+// Link.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org>
+// Copyright (C) 2007, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
+// Copyright (C) 2008-2010, 2012-2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2012 Tobias Koening <tobias.koenig@kdab.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "goo/GooList.h"
+#include "Error.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Link.h"
+#include "Sound.h"
+#include "FileSpec.h"
+#include "Rendition.h"
+#include "Annot.h"
+
+//------------------------------------------------------------------------
+// LinkAction
+//------------------------------------------------------------------------
+
+LinkAction *LinkAction::parseDest(Object *obj) {
+ LinkAction *action;
+
+ action = new LinkGoTo(obj);
+ if (!action->isOk()) {
+ delete action;
+ return NULL;
+ }
+ return action;
+}
+
+LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
+ LinkAction *action;
+ Object obj2, obj3, obj4;
+
+ if (!obj->isDict()) {
+ error(errSyntaxWarning, -1, "parseAction: Bad annotation action for URI '{0:s}'",
+ baseURI ? baseURI->getCString() : "NULL");
+ return NULL;
+ }
+
+ obj->dictLookup("S", &obj2);
+
+ // GoTo action
+ if (obj2.isName("GoTo")) {
+ obj->dictLookup("D", &obj3);
+ action = new LinkGoTo(&obj3);
+ obj3.free();
+
+ // GoToR action
+ } else if (obj2.isName("GoToR")) {
+ obj->dictLookup("F", &obj3);
+ obj->dictLookup("D", &obj4);
+ action = new LinkGoToR(&obj3, &obj4);
+ obj3.free();
+ obj4.free();
+
+ // Launch action
+ } else if (obj2.isName("Launch")) {
+ action = new LinkLaunch(obj);
+
+ // URI action
+ } else if (obj2.isName("URI")) {
+ obj->dictLookup("URI", &obj3);
+ action = new LinkURI(&obj3, baseURI);
+ obj3.free();
+
+ // Named action
+ } else if (obj2.isName("Named")) {
+ obj->dictLookup("N", &obj3);
+ action = new LinkNamed(&obj3);
+ obj3.free();
+
+ // Movie action
+ } else if (obj2.isName("Movie")) {
+ action = new LinkMovie(obj);
+
+ // Rendition action
+ } else if (obj2.isName("Rendition")) {
+ action = new LinkRendition(obj);
+
+ // Sound action
+ } else if (obj2.isName("Sound")) {
+ action = new LinkSound(obj);
+
+ // JavaScript action
+ } else if (obj2.isName("JavaScript")) {
+ obj->dictLookup("JS", &obj3);
+ action = new LinkJavaScript(&obj3);
+ obj3.free();
+
+ // Set-OCG-State action
+ } else if (obj2.isName("SetOCGState")) {
+ action = new LinkOCGState(obj);
+
+ // unknown action
+ } else if (obj2.isName()) {
+ action = new LinkUnknown(obj2.getName());
+
+ // action is missing or wrong type
+ } else {
+ error(errSyntaxWarning, -1, "parseAction: Unknown annotation action object: URI = '{0:s}'",
+ baseURI ? baseURI->getCString() : "NULL");
+ action = NULL;
+ }
+
+ obj2.free();
+
+ if (action && !action->isOk()) {
+ delete action;
+ return NULL;
+ }
+ return action;
+}
+
+//------------------------------------------------------------------------
+// LinkDest
+//------------------------------------------------------------------------
+
+LinkDest::LinkDest(Array *a) {
+ Object obj1, obj2;
+
+ // initialize fields
+ left = bottom = right = top = zoom = 0;
+ changeLeft = changeTop = changeZoom = gFalse;
+ ok = gFalse;
+
+ // get page
+ if (a->getLength() < 2) {
+ error(errSyntaxWarning, -1, "Annotation destination array is too short");
+ return;
+ }
+ a->getNF(0, &obj1);
+ if (obj1.isInt()) {
+ pageNum = obj1.getInt() + 1;
+ pageIsRef = gFalse;
+ } else if (obj1.isRef()) {
+ pageRef.num = obj1.getRefNum();
+ pageRef.gen = obj1.getRefGen();
+ pageIsRef = gTrue;
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination");
+ goto err2;
+ }
+ obj1.free();
+
+ // get destination type
+ a->get(1, &obj1);
+
+ // XYZ link
+ if (obj1.isName("XYZ")) {
+ kind = destXYZ;
+ if (a->getLength() < 3) {
+ changeLeft = gFalse;
+ } else {
+ a->get(2, &obj2);
+ if (obj2.isNull()) {
+ changeLeft = gFalse;
+ } else if (obj2.isNum()) {
+ changeLeft = gTrue;
+ left = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+ }
+ if (a->getLength() < 4) {
+ changeTop = gFalse;
+ } else {
+ a->get(3, &obj2);
+ if (obj2.isNull()) {
+ changeTop = gFalse;
+ } else if (obj2.isNum()) {
+ changeTop = gTrue;
+ top = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+ }
+ if (a->getLength() < 5) {
+ changeZoom = gFalse;
+ } else {
+ a->get(4, &obj2);
+ if (obj2.isNull()) {
+ changeZoom = gFalse;
+ } else if (obj2.isNum()) {
+ zoom = obj2.getNum();
+ changeZoom = (zoom == 0) ? gFalse : gTrue;
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+ }
+
+ // Fit link
+ } else if (obj1.isName("Fit")) {
+ if (a->getLength() < 2) {
+ error(errSyntaxWarning, -1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFit;
+
+ // FitH link
+ } else if (obj1.isName("FitH")) {
+ if (a->getLength() < 3) {
+ error(errSyntaxWarning, -1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitH;
+ a->get(2, &obj2);
+ if (obj2.isNull()) {
+ changeTop = gFalse;
+ } else if (obj2.isNum()) {
+ changeTop = gTrue;
+ top = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ obj2.free();
+
+ // FitV link
+ } else if (obj1.isName("FitV")) {
+ if (a->getLength() < 3) {
+ error(errSyntaxWarning, -1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitV;
+ a->get(2, &obj2);
+ if (obj2.isNull()) {
+ changeLeft = gFalse;
+ } else if (obj2.isNum()) {
+ changeLeft = gTrue;
+ left = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ obj2.free();
+
+ // FitR link
+ } else if (obj1.isName("FitR")) {
+ if (a->getLength() < 6) {
+ error(errSyntaxWarning, -1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitR;
+ if (a->get(2, &obj2)->isNum()) {
+ left = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ obj2.free();
+ if (a->get(3, &obj2)->isNum()) {
+ bottom = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ obj2.free();
+ if (a->get(4, &obj2)->isNum()) {
+ right = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ obj2.free();
+ if (a->get(5, &obj2)->isNum()) {
+ top = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ obj2.free();
+
+ // FitB link
+ } else if (obj1.isName("FitB")) {
+ if (a->getLength() < 2) {
+ error(errSyntaxWarning, -1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitB;
+
+ // FitBH link
+ } else if (obj1.isName("FitBH")) {
+ if (a->getLength() < 3) {
+ error(errSyntaxWarning, -1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitBH;
+ a->get(2, &obj2);
+ if (obj2.isNull()) {
+ changeTop = gFalse;
+ } else if (obj2.isNum()) {
+ changeTop = gTrue;
+ top = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ obj2.free();
+
+ // FitBV link
+ } else if (obj1.isName("FitBV")) {
+ if (a->getLength() < 3) {
+ error(errSyntaxWarning, -1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitBV;
+ a->get(2, &obj2);
+ if (obj2.isNull()) {
+ changeLeft = gFalse;
+ } else if (obj2.isNum()) {
+ changeLeft = gTrue;
+ left = obj2.getNum();
+ } else {
+ error(errSyntaxWarning, -1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ obj2.free();
+
+ // unknown link kind
+ } else {
+ error(errSyntaxWarning, -1, "Unknown annotation destination type");
+ goto err2;
+ }
+
+ obj1.free();
+ ok = gTrue;
+ return;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+}
+
+LinkDest::LinkDest(LinkDest *dest) {
+ kind = dest->kind;
+ pageIsRef = dest->pageIsRef;
+ if (pageIsRef)
+ pageRef = dest->pageRef;
+ else
+ pageNum = dest->pageNum;
+ left = dest->left;
+ bottom = dest->bottom;
+ right = dest->right;
+ top = dest->top;
+ zoom = dest->zoom;
+ changeLeft = dest->changeLeft;
+ changeTop = dest->changeTop;
+ changeZoom = dest->changeZoom;
+ ok = gTrue;
+}
+
+//------------------------------------------------------------------------
+// LinkGoTo
+//------------------------------------------------------------------------
+
+LinkGoTo::LinkGoTo(Object *destObj) {
+ dest = NULL;
+ namedDest = NULL;
+
+ // named destination
+ if (destObj->isName()) {
+ namedDest = new GooString(destObj->getName());
+ } else if (destObj->isString()) {
+ namedDest = destObj->getString()->copy();
+
+ // destination dictionary
+ } else if (destObj->isArray()) {
+ dest = new LinkDest(destObj->getArray());
+ if (!dest->isOk()) {
+ delete dest;
+ dest = NULL;
+ }
+
+ // error
+ } else {
+ error(errSyntaxWarning, -1, "Illegal annotation destination");
+ }
+}
+
+LinkGoTo::~LinkGoTo() {
+ if (dest)
+ delete dest;
+ if (namedDest)
+ delete namedDest;
+}
+
+//------------------------------------------------------------------------
+// LinkGoToR
+//------------------------------------------------------------------------
+
+LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
+ fileName = NULL;
+ dest = NULL;
+ namedDest = NULL;
+
+ // get file name
+ Object obj1;
+ if (getFileSpecNameForPlatform (fileSpecObj, &obj1)) {
+ fileName = obj1.getString()->copy();
+ obj1.free();
+ }
+
+ // named destination
+ if (destObj->isName()) {
+ namedDest = new GooString(destObj->getName());
+ } else if (destObj->isString()) {
+ namedDest = destObj->getString()->copy();
+
+ // destination dictionary
+ } else if (destObj->isArray()) {
+ dest = new LinkDest(destObj->getArray());
+ if (!dest->isOk()) {
+ delete dest;
+ dest = NULL;
+ }
+
+ // error
+ } else {
+ error(errSyntaxWarning, -1, "Illegal annotation destination");
+ }
+}
+
+LinkGoToR::~LinkGoToR() {
+ if (fileName)
+ delete fileName;
+ if (dest)
+ delete dest;
+ if (namedDest)
+ delete namedDest;
+}
+
+
+//------------------------------------------------------------------------
+// LinkLaunch
+//------------------------------------------------------------------------
+
+LinkLaunch::LinkLaunch(Object *actionObj) {
+ Object obj1, obj2, obj3;
+
+ fileName = NULL;
+ params = NULL;
+
+ if (actionObj->isDict()) {
+ if (!actionObj->dictLookup("F", &obj1)->isNull()) {
+ if (getFileSpecNameForPlatform (&obj1, &obj3)) {
+ fileName = obj3.getString()->copy();
+ obj3.free();
+ }
+ } else {
+ obj1.free();
+#ifdef _WIN32
+ if (actionObj->dictLookup("Win", &obj1)->isDict()) {
+ obj1.dictLookup("F", &obj2);
+ if (getFileSpecNameForPlatform (&obj2, &obj3)) {
+ fileName = obj3.getString()->copy();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("P", &obj2)->isString()) {
+ params = obj2.getString()->copy();
+ }
+ obj2.free();
+ } else {
+ error(errSyntaxWarning, -1, "Bad launch-type link action");
+ }
+#else
+ //~ This hasn't been defined by Adobe yet, so assume it looks
+ //~ just like the Win dictionary until they say otherwise.
+ if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
+ obj1.dictLookup("F", &obj2);
+ if (getFileSpecNameForPlatform (&obj2, &obj3)) {
+ fileName = obj3.getString()->copy();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("P", &obj2)->isString()) {
+ params = obj2.getString()->copy();
+ }
+ obj2.free();
+ } else {
+ error(errSyntaxWarning, -1, "Bad launch-type link action");
+ }
+#endif
+ }
+ obj1.free();
+ }
+}
+
+LinkLaunch::~LinkLaunch() {
+ if (fileName)
+ delete fileName;
+ if (params)
+ delete params;
+}
+
+//------------------------------------------------------------------------
+// LinkURI
+//------------------------------------------------------------------------
+
+LinkURI::LinkURI(Object *uriObj, GooString *baseURI) {
+ GooString *uri2;
+ int n;
+ char c;
+
+ uri = NULL;
+ if (uriObj->isString()) {
+ uri2 = uriObj->getString();
+ n = (int)strcspn(uri2->getCString(), "/:");
+ if (n < uri2->getLength() && uri2->getChar(n) == ':') {
+ // "http:..." etc.
+ uri = uri2->copy();
+ } else if (!uri2->cmpN("www.", 4)) {
+ // "www.[...]" without the leading "http://"
+ uri = new GooString("http://");
+ uri->append(uri2);
+ } else {
+ // relative URI
+ if (baseURI) {
+ uri = baseURI->copy();
+ if (uri->getLength() > 0) {
+ c = uri->getChar(uri->getLength() - 1);
+ if (c != '/' && c != '?') {
+ uri->append('/');
+ }
+ }
+ if (uri2->getChar(0) == '/') {
+ uri->append(uri2->getCString() + 1, uri2->getLength() - 1);
+ } else {
+ uri->append(uri2);
+ }
+ } else {
+ uri = uri2->copy();
+ }
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Illegal URI-type link");
+ }
+}
+
+LinkURI::~LinkURI() {
+ if (uri)
+ delete uri;
+}
+
+//------------------------------------------------------------------------
+// LinkNamed
+//------------------------------------------------------------------------
+
+LinkNamed::LinkNamed(Object *nameObj) {
+ name = NULL;
+ if (nameObj->isName()) {
+ name = new GooString(nameObj->getName());
+ }
+}
+
+LinkNamed::~LinkNamed() {
+ if (name) {
+ delete name;
+ }
+}
+
+//------------------------------------------------------------------------
+// LinkMovie
+//------------------------------------------------------------------------
+
+LinkMovie::LinkMovie(Object *obj) {
+ annotRef.num = -1;
+ annotTitle = NULL;
+
+ Object tmp;
+ if (obj->dictLookupNF("Annotation", &tmp)->isRef()) {
+ annotRef = tmp.getRef();
+ }
+ tmp.free();
+
+ if (obj->dictLookup("T", &tmp)->isString()) {
+ annotTitle = tmp.getString()->copy();
+ }
+ tmp.free();
+
+ if ((annotTitle == NULL) && (annotRef.num == -1)) {
+ error(errSyntaxError, -1,
+ "Movie action is missing both the Annot and T keys");
+ }
+
+ if (obj->dictLookup("Operation", &tmp)->isName()) {
+ char *name = tmp.getName();
+
+ if (!strcmp(name, "Play")) {
+ operation = operationTypePlay;
+ }
+ else if (!strcmp(name, "Stop")) {
+ operation = operationTypeStop;
+ }
+ else if (!strcmp(name, "Pause")) {
+ operation = operationTypePause;
+ }
+ else if (!strcmp(name, "Resume")) {
+ operation = operationTypeResume;
+ }
+ }
+ tmp.free();
+}
+
+LinkMovie::~LinkMovie() {
+ if (annotTitle) {
+ delete annotTitle;
+ }
+}
+
+//------------------------------------------------------------------------
+// LinkSound
+//------------------------------------------------------------------------
+
+LinkSound::LinkSound(Object *soundObj) {
+ volume = 1.0;
+ sync = gFalse;
+ repeat = gFalse;
+ mix = gFalse;
+ sound = NULL;
+ if (soundObj->isDict())
+ {
+ Object tmp;
+ // volume
+ soundObj->dictLookup("Volume", &tmp);
+ if (tmp.isNum()) {
+ volume = tmp.getNum();
+ }
+ tmp.free();
+ // sync
+ soundObj->dictLookup("Synchronous", &tmp);
+ if (tmp.isBool()) {
+ sync = tmp.getBool();
+ }
+ tmp.free();
+ // repeat
+ soundObj->dictLookup("Repeat", &tmp);
+ if (tmp.isBool()) {
+ repeat = tmp.getBool();
+ }
+ tmp.free();
+ // mix
+ soundObj->dictLookup("Mix", &tmp);
+ if (tmp.isBool()) {
+ mix = tmp.getBool();
+ }
+ tmp.free();
+ // 'Sound' object
+ soundObj->dictLookup("Sound", &tmp);
+ sound = Sound::parseSound(&tmp);
+ tmp.free();
+ }
+}
+
+LinkSound::~LinkSound() {
+ delete sound;
+}
+
+//------------------------------------------------------------------------
+// LinkRendition
+//------------------------------------------------------------------------
+
+LinkRendition::LinkRendition(Object *obj) {
+ operation = NoRendition;
+ media = NULL;
+ js = NULL;
+ int operationCode = -1;
+
+ if (obj->isDict()) {
+ Object tmp;
+
+ if (!obj->dictLookup("JS", &tmp)->isNull()) {
+ if (tmp.isString()) {
+ js = new GooString(tmp.getString());
+ } else if (tmp.isStream()) {
+ Stream *stream = tmp.getStream();
+ js = new GooString();
+ stream->fillGooString(js);
+ } else {
+ error(errSyntaxWarning, -1, "Invalid Rendition Action: JS not string or stream");
+ }
+ }
+ tmp.free();
+
+ if (obj->dictLookup("OP", &tmp)->isInt()) {
+ operationCode = tmp.getInt();
+ if (!js && (operationCode < 0 || operationCode > 4)) {
+ error(errSyntaxWarning, -1, "Invalid Rendition Action: unrecognized operation valued: {0:d}", operationCode);
+ } else {
+ Object obj1;
+
+ // retrieve rendition object
+ if (obj->dictLookup("R", &renditionObj)->isDict()) {
+ media = new MediaRendition(&renditionObj);
+ } else if (operationCode == 0 || operationCode == 4) {
+ error(errSyntaxWarning, -1, "Invalid Rendition Action: no R field with op = {0:d}", operationCode);
+ renditionObj.free();
+ }
+
+ if (!obj->dictLookupNF("AN", &screenRef)->isRef() && operation >= 0 && operation <= 4) {
+ error(errSyntaxWarning, -1, "Invalid Rendition Action: no AN field with op = {0:d}", operationCode);
+ screenRef.free();
+ }
+ }
+
+ switch (operationCode) {
+ case 0:
+ operation = PlayRendition;
+ break;
+ case 1:
+ operation = StopRendition;
+ break;
+ case 2:
+ operation = PauseRendition;
+ break;
+ case 3:
+ operation = ResumeRendition;
+ break;
+ case 4:
+ operation = PlayRendition;
+ break;
+ }
+ } else if (!js) {
+ error(errSyntaxWarning, -1, "Invalid Rendition action: no OP or JS field defined");
+ }
+ tmp.free();
+ }
+}
+
+LinkRendition::~LinkRendition() {
+ renditionObj.free();
+ screenRef.free();
+
+ if (js)
+ delete js;
+ if (media)
+ delete media;
+}
+
+
+//------------------------------------------------------------------------
+// LinkJavaScript
+//------------------------------------------------------------------------
+
+LinkJavaScript::LinkJavaScript(Object *jsObj) {
+ js = NULL;
+
+ if (jsObj->isString()) {
+ js = new GooString(jsObj->getString());
+ }
+ else if (jsObj->isStream()) {
+ Stream *stream = jsObj->getStream();
+ js = new GooString();
+ stream->fillGooString(js);
+ }
+}
+
+LinkJavaScript::~LinkJavaScript() {
+ if (js) {
+ delete js;
+ }
+}
+
+//------------------------------------------------------------------------
+// LinkOCGState
+//------------------------------------------------------------------------
+LinkOCGState::LinkOCGState(Object *obj) {
+ Object obj1;
+
+ stateList = new GooList();
+ preserveRB = gTrue;
+
+ if (obj->dictLookup("State", &obj1)->isArray()) {
+ StateList *stList = NULL;
+
+ for (int i = 0; i < obj1.arrayGetLength(); ++i) {
+ Object obj2;
+
+ obj1.arrayGetNF(i, &obj2);
+ if (obj2.isName()) {
+ if (stList)
+ stateList->append(stList);
+
+ char *name = obj2.getName();
+ stList = new StateList();
+ stList->list = new GooList();
+ if (!strcmp (name, "ON")) {
+ stList->st = On;
+ } else if (!strcmp (name, "OFF")) {
+ stList->st = Off;
+ } else if (!strcmp (name, "Toggle")) {
+ stList->st = Toggle;
+ } else {
+ error(errSyntaxWarning, -1, "Invalid name '{0:s}' in OCG Action state array", name);
+ delete stList;
+ stList = NULL;
+ }
+ } else if (obj2.isRef()) {
+ if (stList) {
+ Ref ocgRef = obj2.getRef();
+ Ref *item = new Ref();
+ item->num = ocgRef.num;
+ item->gen = ocgRef.gen;
+ stList->list->append(item);
+ } else {
+ error(errSyntaxWarning, -1, "Invalid OCG Action State array, expected name instead of ref");
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Invalid item in OCG Action State array");
+ }
+ obj2.free();
+ }
+ // Add the last group
+ if (stList)
+ stateList->append(stList);
+ } else {
+ error(errSyntaxWarning, -1, "Invalid OCGState action");
+ delete stateList;
+ stateList = NULL;
+ }
+ obj1.free();
+
+ if (obj->dictLookup("PreserveRB", &obj1)->isBool()) {
+ preserveRB = obj1.getBool();
+ }
+ obj1.free();
+}
+
+LinkOCGState::~LinkOCGState() {
+ if (stateList)
+ deleteGooList(stateList, StateList);
+}
+
+LinkOCGState::StateList::~StateList() {
+ if (list)
+ deleteGooList(list, Ref);
+}
+
+//------------------------------------------------------------------------
+// LinkUnknown
+//------------------------------------------------------------------------
+
+LinkUnknown::LinkUnknown(char *actionA) {
+ action = new GooString(actionA);
+}
+
+LinkUnknown::~LinkUnknown() {
+ delete action;
+}
+
+//------------------------------------------------------------------------
+// Links
+//------------------------------------------------------------------------
+
+Links::Links(Annots *annots) {
+ int size;
+ int i;
+
+ links = NULL;
+ size = 0;
+ numLinks = 0;
+
+ if (!annots)
+ return;
+
+ for (i = 0; i < annots->getNumAnnots(); ++i) {
+ Annot *annot = annots->getAnnot(i);
+
+ if (annot->getType() != Annot::typeLink)
+ continue;
+
+ if (numLinks >= size) {
+ size += 16;
+ links = (AnnotLink **)greallocn(links, size, sizeof(AnnotLink *));
+ }
+ annot->incRefCnt();
+ links[numLinks++] = static_cast<AnnotLink *>(annot);
+ }
+}
+
+Links::~Links() {
+ int i;
+
+ for (i = 0; i < numLinks; ++i)
+ links[i]->decRefCnt();
+
+ gfree(links);
+}
+
+LinkAction *Links::find(double x, double y) const {
+ int i;
+
+ for (i = numLinks - 1; i >= 0; --i) {
+ if (links[i]->inRect(x, y)) {
+ return links[i]->getAction();
+ }
+ }
+ return NULL;
+}
+
+GBool Links::onLink(double x, double y) const {
+ int i;
+
+ for (i = 0; i < numLinks; ++i) {
+ if (links[i]->inRect(x, y))
+ return gTrue;
+ }
+ return gFalse;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Link.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Link.h
new file mode 100644
index 00000000000..fc2abe60052
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Link.h
@@ -0,0 +1,501 @@
+//========================================================================
+//
+// Link.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org>
+// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
+// Copyright (C) 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2012 Tobias Koening <tobias.koenig@kdab.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef LINK_H
+#define LINK_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class GooString;
+class GooList;
+class Array;
+class Dict;
+class Sound;
+class MediaRendition;
+class AnnotLink;
+class Annots;
+
+//------------------------------------------------------------------------
+// LinkAction
+//------------------------------------------------------------------------
+
+enum LinkActionKind {
+ actionGoTo, // go to destination
+ actionGoToR, // go to destination in new file
+ actionLaunch, // launch app (or open document)
+ actionURI, // URI
+ actionNamed, // named action
+ actionMovie, // movie action
+ actionRendition, // rendition action
+ actionSound, // sound action
+ actionJavaScript, // JavaScript action
+ actionOCGState, // Set-OCG-State action
+ actionUnknown // anything else
+};
+
+class LinkAction {
+public:
+
+ // Destructor.
+ virtual ~LinkAction() {}
+
+ // Was the LinkAction created successfully?
+ virtual GBool isOk() = 0;
+
+ // Check link action type.
+ virtual LinkActionKind getKind() = 0;
+
+ // Parse a destination (old-style action) name, string, or array.
+ static LinkAction *parseDest(Object *obj);
+
+ // Parse an action dictionary.
+ static LinkAction *parseAction(Object *obj, GooString *baseURI = NULL);
+};
+
+//------------------------------------------------------------------------
+// LinkDest
+//------------------------------------------------------------------------
+
+enum LinkDestKind {
+ destXYZ,
+ destFit,
+ destFitH,
+ destFitV,
+ destFitR,
+ destFitB,
+ destFitBH,
+ destFitBV
+};
+
+class LinkDest {
+public:
+
+ // Build a LinkDest from the array.
+ LinkDest(Array *a);
+
+ // Copy a LinkDest.
+ LinkDest *copy() { return new LinkDest(this); }
+
+ // Was the LinkDest created successfully?
+ GBool isOk() { return ok; }
+
+ // Accessors.
+ LinkDestKind getKind() { return kind; }
+ GBool isPageRef() { return pageIsRef; }
+ int getPageNum() { return pageNum; }
+ Ref getPageRef() { return pageRef; }
+ double getLeft() { return left; }
+ double getBottom() { return bottom; }
+ double getRight() { return right; }
+ double getTop() { return top; }
+ double getZoom() { return zoom; }
+ GBool getChangeLeft() { return changeLeft; }
+ GBool getChangeTop() { return changeTop; }
+ GBool getChangeZoom() { return changeZoom; }
+
+private:
+
+ LinkDestKind kind; // destination type
+ GBool pageIsRef; // is the page a reference or number?
+ union {
+ Ref pageRef; // reference to page
+ int pageNum; // one-relative page number
+ };
+ double left, bottom; // position
+ double right, top;
+ double zoom; // zoom factor
+ GBool changeLeft, changeTop; // which position components to change:
+ GBool changeZoom; // destXYZ uses all three;
+ // destFitH/BH use changeTop;
+ // destFitV/BV use changeLeft
+ GBool ok; // set if created successfully
+
+ LinkDest(LinkDest *dest);
+};
+
+//------------------------------------------------------------------------
+// LinkGoTo
+//------------------------------------------------------------------------
+
+class LinkGoTo: public LinkAction {
+public:
+
+ // Build a LinkGoTo from a destination (dictionary, name, or string).
+ LinkGoTo(Object *destObj);
+
+ // Destructor.
+ virtual ~LinkGoTo();
+
+ // Was the LinkGoTo created successfully?
+ virtual GBool isOk() { return dest || namedDest; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionGoTo; }
+ LinkDest *getDest() { return dest; }
+ GooString *getNamedDest() { return namedDest; }
+
+private:
+
+ LinkDest *dest; // regular destination (NULL for remote
+ // link with bad destination)
+ GooString *namedDest; // named destination (only one of dest and
+ // and namedDest may be non-NULL)
+};
+
+//------------------------------------------------------------------------
+// LinkGoToR
+//------------------------------------------------------------------------
+
+class LinkGoToR: public LinkAction {
+public:
+
+ // Build a LinkGoToR from a file spec (dictionary) and destination
+ // (dictionary, name, or string).
+ LinkGoToR(Object *fileSpecObj, Object *destObj);
+
+ // Destructor.
+ virtual ~LinkGoToR();
+
+ // Was the LinkGoToR created successfully?
+ virtual GBool isOk() { return fileName && (dest || namedDest); }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionGoToR; }
+ GooString *getFileName() { return fileName; }
+ LinkDest *getDest() { return dest; }
+ GooString *getNamedDest() { return namedDest; }
+
+private:
+
+ GooString *fileName; // file name
+ LinkDest *dest; // regular destination (NULL for remote
+ // link with bad destination)
+ GooString *namedDest; // named destination (only one of dest and
+ // and namedDest may be non-NULL)
+};
+
+//------------------------------------------------------------------------
+// LinkLaunch
+//------------------------------------------------------------------------
+
+class LinkLaunch: public LinkAction {
+public:
+
+ // Build a LinkLaunch from an action dictionary.
+ LinkLaunch(Object *actionObj);
+
+ // Destructor.
+ virtual ~LinkLaunch();
+
+ // Was the LinkLaunch created successfully?
+ virtual GBool isOk() { return fileName != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionLaunch; }
+ GooString *getFileName() { return fileName; }
+ GooString *getParams() { return params; }
+
+private:
+
+ GooString *fileName; // file name
+ GooString *params; // parameters
+};
+
+//------------------------------------------------------------------------
+// LinkURI
+//------------------------------------------------------------------------
+
+class LinkURI: public LinkAction {
+public:
+
+ // Build a LinkURI given the URI (string) and base URI.
+ LinkURI(Object *uriObj, GooString *baseURI);
+
+ // Destructor.
+ virtual ~LinkURI();
+
+ // Was the LinkURI created successfully?
+ virtual GBool isOk() { return uri != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionURI; }
+ GooString *getURI() { return uri; }
+
+private:
+
+ GooString *uri; // the URI
+};
+
+//------------------------------------------------------------------------
+// LinkNamed
+//------------------------------------------------------------------------
+
+class LinkNamed: public LinkAction {
+public:
+
+ // Build a LinkNamed given the action name.
+ LinkNamed(Object *nameObj);
+
+ virtual ~LinkNamed();
+
+ virtual GBool isOk() { return name != NULL; }
+
+ virtual LinkActionKind getKind() { return actionNamed; }
+ GooString *getName() { return name; }
+
+private:
+
+ GooString *name;
+};
+
+
+//------------------------------------------------------------------------
+// LinkMovie
+//------------------------------------------------------------------------
+
+class LinkMovie: public LinkAction {
+public:
+
+ enum OperationType {
+ operationTypePlay,
+ operationTypePause,
+ operationTypeResume,
+ operationTypeStop
+ };
+
+ LinkMovie(Object *obj);
+ virtual ~LinkMovie();
+
+ virtual GBool isOk() { return annotRef.num >= 0 || annotTitle != NULL; }
+ virtual LinkActionKind getKind() { return actionMovie; }
+
+ // a movie action stores either an indirect reference to a movie annotation
+ // or the movie annotation title
+
+ GBool hasAnnotRef() { return annotRef.num >= 0; }
+ GBool hasAnnotTitle() { return annotTitle != NULL; }
+ Ref *getAnnotRef() { return &annotRef; }
+ GooString *getAnnotTitle() { return annotTitle; }
+
+ OperationType getOperation() { return operation; }
+
+private:
+
+ Ref annotRef; // Annotation
+ GooString *annotTitle; // T
+
+ OperationType operation; // Operation
+};
+
+
+//------------------------------------------------------------------------
+// LinkRendition
+//------------------------------------------------------------------------
+
+class LinkRendition: public LinkAction {
+public:
+ /**
+ * Describes the possible rendition operations.
+ */
+ enum RenditionOperation {
+ NoRendition,
+ PlayRendition,
+ StopRendition,
+ PauseRendition,
+ ResumeRendition
+ };
+
+ LinkRendition(Object *Obj);
+
+ virtual ~LinkRendition();
+
+ virtual GBool isOk() { return true; }
+
+ virtual LinkActionKind getKind() { return actionRendition; }
+
+ GBool hasRenditionObject() { return renditionObj.isDict(); }
+ Object* getRenditionObject() { return &renditionObj; }
+
+ GBool hasScreenAnnot() { return screenRef.isRef(); }
+ Ref getScreenAnnot() { return screenRef.getRef(); }
+
+ RenditionOperation getOperation() { return operation; }
+
+ MediaRendition* getMedia() { return media; }
+
+ GooString *getScript() { return js; }
+
+private:
+
+ Object screenRef;
+ Object renditionObj;
+ RenditionOperation operation;
+
+ MediaRendition* media;
+
+ GooString *js;
+};
+
+//------------------------------------------------------------------------
+// LinkSound
+//------------------------------------------------------------------------
+
+class LinkSound: public LinkAction {
+public:
+
+ LinkSound(Object *soundObj);
+
+ virtual ~LinkSound();
+
+ virtual GBool isOk() { return sound != NULL; }
+
+ virtual LinkActionKind getKind() { return actionSound; }
+
+ double getVolume() { return volume; }
+ GBool getSynchronous() { return sync; }
+ GBool getRepeat() { return repeat; }
+ GBool getMix() { return mix; }
+ Sound *getSound() { return sound; }
+
+private:
+
+ double volume;
+ GBool sync;
+ GBool repeat;
+ GBool mix;
+ Sound *sound;
+};
+
+//------------------------------------------------------------------------
+// LinkJavaScript
+//------------------------------------------------------------------------
+
+class LinkJavaScript: public LinkAction {
+public:
+
+ // Build a LinkJavaScript given the action name.
+ LinkJavaScript(Object *jsObj);
+
+ virtual ~LinkJavaScript();
+
+ virtual GBool isOk() { return js != NULL; }
+
+ virtual LinkActionKind getKind() { return actionJavaScript; }
+ GooString *getScript() { return js; }
+
+private:
+
+ GooString *js;
+};
+
+//------------------------------------------------------------------------
+// LinkOCGState
+//------------------------------------------------------------------------
+class LinkOCGState: public LinkAction {
+public:
+ LinkOCGState(Object *obj);
+
+ virtual ~LinkOCGState();
+
+ virtual GBool isOk() { return stateList != NULL; }
+
+ virtual LinkActionKind getKind() { return actionOCGState; }
+
+ enum State { On, Off, Toggle};
+ struct StateList {
+ StateList() { list = NULL; }
+ ~StateList();
+ State st;
+ GooList *list;
+ };
+
+ GooList *getStateList() { return stateList; }
+ GBool getPreserveRB() { return preserveRB; }
+
+private:
+ GooList *stateList;
+ GBool preserveRB;
+};
+
+//------------------------------------------------------------------------
+// LinkUnknown
+//------------------------------------------------------------------------
+
+class LinkUnknown: public LinkAction {
+public:
+
+ // Build a LinkUnknown with the specified action type.
+ LinkUnknown(char *actionA);
+
+ // Destructor.
+ virtual ~LinkUnknown();
+
+ // Was the LinkUnknown create successfully?
+ virtual GBool isOk() { return action != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionUnknown; }
+ GooString *getAction() { return action; }
+
+private:
+
+ GooString *action; // action subtype
+};
+
+//------------------------------------------------------------------------
+// Links
+//------------------------------------------------------------------------
+
+class Links {
+public:
+
+ // Extract links from array of annotations.
+ Links(Annots *annots);
+
+ // Destructor.
+ ~Links();
+
+ // Iterate through list of links.
+ int getNumLinks() const { return numLinks; }
+ AnnotLink *getLink(int i) const { return links[i]; }
+
+ // If point <x>,<y> is in a link, return the associated action;
+ // else return NULL.
+ LinkAction *find(double x, double y) const;
+
+ // Return true if <x>,<y> is in a link.
+ GBool onLink(double x, double y) const;
+
+private:
+
+ AnnotLink **links;
+ int numLinks;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/LocalPDFDocBuilder.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/LocalPDFDocBuilder.cc
new file mode 100644
index 00000000000..6f6f1fca9f7
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/LocalPDFDocBuilder.cc
@@ -0,0 +1,46 @@
+//========================================================================
+//
+// LocalPDFDocBuilder.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "LocalPDFDocBuilder.h"
+
+//------------------------------------------------------------------------
+// LocalPDFDocBuilder
+//------------------------------------------------------------------------
+
+PDFDoc *
+LocalPDFDocBuilder::buildPDFDoc(
+ const GooString &uri, GooString *ownerPassword, GooString
+ *userPassword, void *guiDataA)
+{
+ if (uri.cmpN("file://", 7) == 0) {
+ GooString *fileName = uri.copy();
+ fileName->del(0, 7);
+ return new PDFDoc(fileName, ownerPassword, userPassword, guiDataA);
+ } else {
+ GooString *fileName = uri.copy();
+ return new PDFDoc(fileName, ownerPassword, userPassword, guiDataA);
+ }
+}
+
+GBool LocalPDFDocBuilder::supports(const GooString &uri)
+{
+ if (uri.cmpN("file://", 7) == 0) {
+ return gTrue;
+ } else if (!strstr(uri.getCString(), "://")) {
+ return gTrue;
+ } else {
+ return gFalse;
+ }
+}
+
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/LocalPDFDocBuilder.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/LocalPDFDocBuilder.h
new file mode 100644
index 00000000000..c2b1d903885
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/LocalPDFDocBuilder.h
@@ -0,0 +1,33 @@
+//========================================================================
+//
+// LocalPDFDocBuilder.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef LOCALPDFDOCBUILDER_H
+#define LOCALPDFDOCBUILDER_H
+
+#include "PDFDocBuilder.h"
+
+//------------------------------------------------------------------------
+// LocalPDFDocBuilder
+//
+// The LocalPDFDocBuilder implements a PDFDocBuilder for local files.
+//------------------------------------------------------------------------
+
+class LocalPDFDocBuilder : public PDFDocBuilder {
+
+public:
+
+ PDFDoc *buildPDFDoc(const GooString &uri, GooString *ownerPassword = NULL,
+ GooString *userPassword = NULL, void *guiDataA = NULL);
+ GBool supports(const GooString &uri);
+
+};
+
+#endif /* LOCALPDFDOCBUILDER_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Makefile.am b/Build/source/libs/poppler/poppler-0.36.0/poppler/Makefile.am
new file mode 100644
index 00000000000..9a5d0267401
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Makefile.am
@@ -0,0 +1,317 @@
+CFLAGS+=$(PTHREAD_CFLAGS)
+CXXFLAGS+=$(PTHREAD_CFLAGS)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/goo
+
+lib_LTLIBRARIES = libpoppler.la
+
+if BUILD_CAIRO_OUTPUT
+noinst_LTLIBRARIES = libpoppler-cairo.la
+endif
+
+if BUILD_SPLASH_OUTPUT
+
+splash_sources = \
+ SplashOutputDev.cc
+
+splash_headers = \
+ SplashOutputDev.h
+
+splash_includes = \
+ $(SPLASH_CFLAGS)
+
+splash_libs = \
+ $(SPLASH_LIBS) \
+ $(top_builddir)/splash/libsplash.la
+
+endif
+
+if BUILD_LIBJPEG
+
+libjpeg_sources = \
+ DCTStream.h \
+ DCTStream.cc
+
+libjpeg_libs = \
+ $(LIBJPEG_LIBS)
+libjpeg_includes = \
+ $(LIBJPEG_CFLAGS)
+
+endif
+
+if BUILD_LIBPNG
+
+libpng_libs = \
+ $(LIBPNG_LIBS)
+libpng_includes = \
+ $(LIBPNG_CFLAGS)
+
+endif
+
+if BUILD_LIBTIFF
+
+libtiff_libs = \
+ $(LIBTIFF_LIBS)
+libtiff_includes = \
+ $(LIBTIFF_CFLAGS)
+
+endif
+
+if BUILD_LIBOPENJPEG
+
+libjpeg2000_sources = \
+ JPEG2000Stream.h \
+ JPEG2000Stream.cc
+
+libjpeg2000_libs = \
+ $(LIBOPENJPEG_LIBS)
+libjpeg2000_includes = \
+ $(LIBOPENJPEG_CFLAGS)
+
+else
+
+libjpeg2000_sources = \
+ JPXStream.h \
+ JPXStream.cc
+
+endif
+
+
+if BUILD_ZLIB
+
+zlib_sources = \
+ FlateStream.h \
+ FlateStream.cc
+
+zlib_libs = \
+ $(ZLIB_LIBS)
+
+endif
+
+if BUILD_LIBCURL
+
+libcurl_libs = \
+ $(LIBCURL_LIBS)
+
+libcurl_includes = \
+ $(LIBCURL_CFLAGS)
+
+curl_headers = \
+ CurlCachedFile.h \
+ CurlPDFDocBuilder.h
+
+curl_sources = \
+ CurlCachedFile.cc \
+ CurlPDFDocBuilder.cc
+
+endif
+
+if USE_CMS
+cms_includes = $(LCMS_CFLAGS)
+cms_libs = $(LCMS_LIBS)
+endif
+
+if ENABLE_XPDF_HEADERS
+
+poppler_includedir = $(includedir)/poppler
+poppler_include_HEADERS = \
+ $(splash_headers) \
+ $(curl_headers) \
+ Annot.h \
+ Array.h \
+ BuiltinFont.h \
+ BuiltinFontTables.h \
+ CachedFile.h \
+ Catalog.h \
+ CharCodeToUnicode.h \
+ CMap.h \
+ DateInfo.h \
+ Decrypt.h \
+ Dict.h \
+ Error.h \
+ FileSpec.h \
+ FontEncodingTables.h \
+ FontInfo.h \
+ Form.h \
+ Function.h \
+ Gfx.h \
+ GfxFont.h \
+ GfxState.h \
+ GfxState_helpers.h \
+ GlobalParams.h \
+ Hints.h \
+ JArithmeticDecoder.h \
+ JBIG2Stream.h \
+ Lexer.h \
+ Linearization.h \
+ Link.h \
+ LocalPDFDocBuilder.h \
+ Movie.h \
+ NameToCharCode.h \
+ Object.h \
+ OptionalContent.h \
+ Outline.h \
+ OutputDev.h \
+ Page.h \
+ PageTransition.h \
+ Parser.h \
+ PDFDoc.h \
+ PDFDocBuilder.h \
+ PDFDocEncoding.h \
+ PDFDocFactory.h \
+ PopplerCache.h \
+ ProfileData.h \
+ PreScanOutputDev.h \
+ PSTokenizer.h \
+ Rendition.h \
+ StdinCachedFile.h \
+ StdinPDFDocBuilder.h \
+ Stream-CCITT.h \
+ Stream.h \
+ StructElement.h \
+ StructTreeRoot.h \
+ UnicodeMap.h \
+ UnicodeMapTables.h \
+ UnicodeTypeTable.h \
+ UnicodeCClassTables.h \
+ UnicodeCompTables.h \
+ UnicodeDecompTables.h \
+ ViewerPreferences.h \
+ XRef.h \
+ CharTypes.h \
+ CompactFontTables.h \
+ ErrorCodes.h \
+ NameToUnicodeTable.h \
+ PSOutputDev.h \
+ TextOutputDev.h \
+ MarkedContentOutputDev.h \
+ SecurityHandler.h \
+ UTF.h \
+ UTF8.h \
+ XpdfPluginAPI.h \
+ Sound.h
+nodist_poppler_include_HEADERS = poppler-config.h
+
+endif
+
+libpoppler_la_SOURCES = \
+ $(splash_sources) \
+ $(libjpeg_sources) \
+ $(zlib_sources) \
+ $(libjpeg2000_sources) \
+ $(curl_sources) \
+ Annot.cc \
+ Array.cc \
+ BuiltinFont.cc \
+ BuiltinFontTables.cc \
+ CachedFile.cc \
+ Catalog.cc \
+ CharCodeToUnicode.cc \
+ CMap.cc \
+ DateInfo.cc \
+ Decrypt.cc \
+ Dict.cc \
+ Error.cc \
+ FileSpec.cc \
+ FontEncodingTables.cc \
+ Form.cc \
+ FontInfo.cc \
+ Function.cc \
+ Gfx.cc \
+ GfxFont.cc \
+ GfxState.cc \
+ GlobalParams.cc \
+ Hints.cc \
+ JArithmeticDecoder.cc \
+ JBIG2Stream.cc \
+ Lexer.cc \
+ Linearization.cc \
+ Link.cc \
+ LocalPDFDocBuilder.cc \
+ Movie.cc \
+ NameToCharCode.cc \
+ Object.cc \
+ OptionalContent.cc \
+ Outline.cc \
+ OutputDev.cc \
+ Page.cc \
+ PageTransition.cc \
+ Parser.cc \
+ PDFDoc.cc \
+ PDFDocEncoding.cc \
+ PDFDocFactory.cc \
+ PopplerCache.cc \
+ ProfileData.cc \
+ PreScanOutputDev.cc \
+ PSTokenizer.cc \
+ Rendition.cc \
+ StdinCachedFile.cc \
+ StdinPDFDocBuilder.cc \
+ Stream.cc \
+ StructTreeRoot.cc \
+ StructElement.cc \
+ strtok_r.cpp \
+ UnicodeMap.cc \
+ UnicodeTypeTable.cc \
+ UTF.cc \
+ ViewerPreferences.cc \
+ XRef.cc \
+ PSOutputDev.cc \
+ TextOutputDev.cc \
+ MarkedContentOutputDev.cc \
+ PageLabelInfo.h \
+ PageLabelInfo.cc \
+ SecurityHandler.cc \
+ Sound.cc \
+ XpdfPluginAPI.cc
+
+libpoppler_la_CPPFLAGS = \
+ $(cms_includes) \
+ $(splash_includes) \
+ $(libjpeg_includes) \
+ $(libtiff_includes) \
+ $(libjpeg2000_includes) \
+ $(libpng_includes) \
+ $(libcurl_includes) \
+ $(FREETYPE_CFLAGS) \
+ $(FONTCONFIG_CFLAGS) \
+ $(AM_CPPFLAGS)
+
+libpoppler_la_LIBADD = \
+ $(top_builddir)/goo/libgoo.la \
+ $(top_builddir)/fofi/libfofi.la \
+ $(cms_libs) \
+ $(splash_libs) \
+ $(libtiff_libs) \
+ $(libjpeg_libs) \
+ $(libpng_libs) \
+ $(zlib_libs) \
+ $(libcurl_libs) \
+ $(libjpeg2000_libs) \
+ $(FREETYPE_LIBS) \
+ $(FONTCONFIG_LIBS) \
+ $(PTHREAD_LIBS) \
+ $(win32_libs)
+
+libpoppler_la_LDFLAGS = \
+ -version-info 55:0:0 \
+ @create_shared_lib@ \
+ @auto_import_flags@
+
+libpoppler_cairo_la_SOURCES = \
+ CairoFontEngine.cc \
+ CairoFontEngine.h \
+ CairoOutputDev.cc \
+ CairoOutputDev.h \
+ CairoRescaleBox.cc \
+ CairoRescaleBox.h
+
+libpoppler_cairo_la_CPPFLAGS = \
+ $(CAIRO_CFLAGS) \
+ $(AM_CPPFLAGS)
+
+EXTRA_DIST = gen-unicode-tables.py \
+ GlobalParamsWin.cc \
+ PageLabelInfo_p.h
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/MarkedContentOutputDev.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/MarkedContentOutputDev.cc
new file mode 100644
index 00000000000..7fdd8f54c53
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/MarkedContentOutputDev.cc
@@ -0,0 +1,212 @@
+//========================================================================
+//
+// MarkedContentOutputDev.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2013 Igalia S.L.
+//
+//========================================================================
+
+#include "MarkedContentOutputDev.h"
+#include "GlobalParams.h"
+#include "UnicodeMap.h"
+#include "GfxState.h"
+#include "GfxFont.h"
+#include "Annot.h"
+#include <vector>
+
+
+MarkedContentOutputDev::MarkedContentOutputDev(int mcidA):
+ currentFont(NULL),
+ currentText(NULL),
+ mcid(mcidA),
+ pageWidth(0.0),
+ pageHeight(0.0),
+ unicodeMap(NULL)
+{
+ currentColor.r = currentColor.g = currentColor.b = 0;
+}
+
+
+MarkedContentOutputDev::~MarkedContentOutputDev()
+{
+ if (unicodeMap)
+ unicodeMap->decRefCnt();
+ if (currentFont)
+ currentFont->decRefCnt();
+ delete currentText;
+}
+
+
+void MarkedContentOutputDev::endSpan()
+{
+ if (currentText && currentText->getLength()) {
+ // The TextSpan takes ownership of currentText and
+ // increases the reference count for currentFont.
+ textSpans.push_back(TextSpan(currentText,
+ currentFont,
+ currentColor));
+ }
+ currentText = NULL;
+}
+
+
+void MarkedContentOutputDev::startPage(int pageNum, GfxState *state, XRef *xref)
+{
+ if (state) {
+ pageWidth = state->getPageWidth();
+ pageHeight = state->getPageHeight();
+ } else {
+ pageWidth = pageHeight = 0.0;
+ }
+}
+
+
+void MarkedContentOutputDev::endPage()
+{
+ pageWidth = pageHeight = 0.0;
+}
+
+
+void MarkedContentOutputDev::beginMarkedContent(char *name, Dict *properties)
+{
+ int id = -1;
+ if (properties)
+ properties->lookupInt("MCID", NULL, &id);
+
+ if (id == -1)
+ return;
+
+ // The stack keep track of MCIDs of nested marked content.
+ if (inMarkedContent() || id == mcid)
+ mcidStack.push_back(id);
+}
+
+
+void MarkedContentOutputDev::endMarkedContent(GfxState *state)
+{
+ if (inMarkedContent()) {
+ mcidStack.pop_back();
+ // The outer marked content sequence MCID was popped, ensure
+ // that the last piece of text collected ends up in a TextSpan.
+ if (!inMarkedContent())
+ endSpan();
+ }
+}
+
+
+bool MarkedContentOutputDev::needFontChange(GfxFont* font) const
+{
+ if (currentFont == font)
+ return gFalse;
+
+ if (!currentFont)
+ return font != NULL && font->isOk();
+
+ if (font == NULL)
+ return gTrue;
+
+ // Two non-null valid fonts are the same if they point to the same Ref
+ if (currentFont->getID()->num == font->getID()->num &&
+ currentFont->getID()->gen == font->getID()->gen)
+ return gFalse;
+
+ return gTrue;
+}
+
+
+void MarkedContentOutputDev::drawChar(GfxState *state,
+ double xx, double yy,
+ double dx, double dy,
+ double ox, double oy,
+ CharCode c, int nBytes,
+ Unicode *u, int uLen)
+{
+ if (!inMarkedContent() || !uLen)
+ return;
+
+
+ // Color changes are tracked here so the color can be chosen depending on
+ // the render mode (for mode 1 stroke color is used), so there is no need
+ // to implement both updateFillColor() and updateStrokeColor().
+ GBool colorChange = gFalse;
+ GfxRGB color;
+ if ((state->getRender() & 3) == 1)
+ state->getStrokeRGB(&color);
+ else
+ state->getFillRGB(&color);
+
+ colorChange = (color.r != currentColor.r ||
+ color.g != currentColor.g ||
+ color.b != currentColor.b);
+
+ // Check also for font changes.
+ GBool fontChange = needFontChange(state->getFont());
+
+ // Save a span with the current changes.
+ if (colorChange || fontChange) {
+ endSpan();
+ }
+
+ // Perform the color/font changes.
+ if (colorChange)
+ currentColor = color;
+
+ if (fontChange) {
+ if (currentFont != NULL) {
+ currentFont->decRefCnt();
+ currentFont = NULL;
+ }
+ if (state->getFont() != NULL) {
+ currentFont = state->getFont();
+ currentFont->incRefCnt();
+ }
+ }
+
+
+ double sp, dx2, dy2, w1, h1, x1, y1;
+
+ // Subtract char and word spacing from the (dx,dy) values
+ sp = state->getCharSpace();
+ if (c == (CharCode) 0x20)
+ sp += state->getWordSpace();
+ state->textTransformDelta(sp * state->getHorizScaling(), 0, &dx2, &dy2);
+ dx -= dx2;
+ dy -= dy2;
+ state->transformDelta(dx, dy, &w1, &h1);
+ state->transform(xx, yy, &x1, &y1);
+
+ // Throw away characters that are not inside the page boundaries.
+ if (x1 + w1 < 0 || x1 > pageWidth || y1 + h1 < 0 || y1 > pageHeight)
+ return;
+
+ // Make a sanity check on character size. Note: (x != x) <-> isnan(x)
+ if (x1 != x1 || y1 != y1 || w1 != w1 || h1 != h1)
+ return;
+
+ for (int i = 0; i < uLen; i++) {
+ // Soft hyphen markers are skipped, as they are invisible unless
+ // rendering is done to an actual device and the hyphenation hint
+ // used. MarkedContentOutputDev extracts the *visible* text content.
+ if (u[i] != 0x00AD) {
+ // Add the UTF-8 sequence to the current text span.
+ if (!unicodeMap)
+ unicodeMap = globalParams->getTextEncoding();
+
+ char buf[8];
+ int n = unicodeMap->mapUnicode(u[i], buf, sizeof(buf));
+ if (n > 0) {
+ if (currentText == NULL)
+ currentText = new GooString();
+ currentText->append(buf, n);
+ }
+ }
+ }
+}
+
+
+const TextSpanArray& MarkedContentOutputDev::getTextSpans() const
+{
+ return textSpans;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/MarkedContentOutputDev.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/MarkedContentOutputDev.h
new file mode 100644
index 00000000000..4ea60c255a1
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/MarkedContentOutputDev.h
@@ -0,0 +1,130 @@
+//========================================================================
+//
+// MarkedContentOutputDev.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2013 Igalia S.L.
+//
+//========================================================================
+
+#ifndef MARKEDCONTENTOUTPUTDEV_H
+#define MARKEDCONTENTOUTPUTDEV_H
+
+#include "goo/gtypes.h"
+#include "goo/gmem.h"
+#include "OutputDev.h"
+#include "GfxState.h"
+#include "GfxFont.h"
+#include <vector>
+
+class Dict;
+class UnicodeMap;
+
+
+class TextSpan {
+public:
+ TextSpan(const TextSpan& other): data(other.data) {
+ data->refcount++;
+ }
+
+ TextSpan& operator=(const TextSpan& other) {
+ if (this != &other) {
+ data = other.data;
+ data->refcount++;
+ }
+ return *this;
+ }
+
+ ~TextSpan() {
+ if (data && --data->refcount == 0)
+ delete data;
+ }
+
+ GfxFont* getFont() const { return data->font; }
+ GooString* getText() const { return data->text; }
+ GfxRGB& getColor() const { return data->color; }
+
+private:
+ // Note: Takes ownership of strings, increases refcount for font.
+ TextSpan(GooString *text,
+ GfxFont *font,
+ const GfxRGB& color)
+ : data(new Data) {
+ data->text = text;
+ data->font = font;
+ data->color = color;
+ if (data->font)
+ data->font->incRefCnt();
+ }
+
+ struct Data {
+ GfxFont *font;
+ GooString *text;
+ GfxRGB color;
+ unsigned refcount;
+
+ Data(): refcount(1) {}
+
+ ~Data() {
+ assert(refcount == 0);
+ if (font)
+ font->decRefCnt();
+ delete text;
+ }
+ };
+
+ Data *data;
+
+ friend class MarkedContentOutputDev;
+};
+
+
+typedef std::vector<TextSpan> TextSpanArray;
+
+
+class MarkedContentOutputDev: public OutputDev {
+public:
+ MarkedContentOutputDev(int mcidA);
+ virtual ~MarkedContentOutputDev();
+
+ virtual GBool isOk() { return gTrue; }
+ virtual GBool upsideDown() { return gTrue; }
+ virtual GBool useDrawChar() { return gTrue; }
+ virtual GBool interpretType3Chars() { return gFalse; }
+ virtual GBool needNonText() { return gFalse; }
+ virtual GBool needCharCount() { return gFalse; }
+
+ virtual void startPage(int pageNum, GfxState *state, XRef *xref);
+ virtual void endPage();
+
+ virtual void drawChar(GfxState *state,
+ double xx, double yy,
+ double dx, double dy,
+ double ox, double oy,
+ CharCode c, int nBytes,
+ Unicode *u, int uLen);
+
+ virtual void beginMarkedContent(char *name, Dict *properties);
+ virtual void endMarkedContent(GfxState *state);
+
+ const TextSpanArray& getTextSpans() const;
+
+private:
+
+ void endSpan();
+ bool inMarkedContent() const { return mcidStack.size() > 0; }
+ bool needFontChange(GfxFont* font) const;
+
+ GfxFont *currentFont;
+ GooString *currentText;
+ GfxRGB currentColor;
+ TextSpanArray textSpans;
+ int mcid;
+ std::vector<int> mcidStack;
+ double pageWidth;
+ double pageHeight;
+ UnicodeMap *unicodeMap;
+};
+
+#endif /* !MARKEDCONTENTOUTPUTDEV_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Movie.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Movie.cc
new file mode 100644
index 00000000000..f68b6adcd4d
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Movie.cc
@@ -0,0 +1,285 @@
+//*********************************************************************************
+// Movie.cc
+//---------------------------------------------------------------------------------
+//
+//---------------------------------------------------------------------------------
+// Hugo Mercier <hmercier31[at]gmail.com> (c) 2008
+// Pino Toscano <pino@kde.org> (c) 2008
+// Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
+// Albert Astals Cid <aacid@kde.org> (c) 2010
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//*********************************************************************************
+
+#include <math.h>
+#include "Movie.h"
+#include "FileSpec.h"
+
+MovieActivationParameters::MovieActivationParameters() {
+ // default values
+ floatingWindow = gFalse;
+ xPosition = 0.5;
+ yPosition = 0.5;
+ rate = 1.0;
+ volume = 100;
+ showControls = gFalse;
+ synchronousPlay = gFalse;
+ repeatMode = repeatModeOnce;
+ start.units = 0;
+ duration.units = 0;
+ znum = 1;
+ zdenum = 1;
+}
+
+MovieActivationParameters::~MovieActivationParameters() {
+}
+
+void MovieActivationParameters::parseMovieActivation(Object* aDict) {
+ Object obj1;
+
+ if (!aDict->dictLookup("Start", &obj1)->isNull()) {
+ if (obj1.isInt()) {
+ // If it is representable as an integer (subject to the implementation limit for
+ // integers, as described in Appendix C), it should be specified as such.
+
+ start.units = obj1.getInt();
+ } else if (obj1.isString()) {
+ // If it is not representable as an integer, it should be specified as an 8-byte
+ // string representing a 64-bit twos-complement integer, most significant
+ // byte first.
+
+ // UNSUPPORTED
+ } else if (obj1.isArray()) {
+ Array* a = obj1.getArray();
+
+ Object tmp;
+ a->get(0, &tmp);
+ if (tmp.isInt()) {
+ start.units = tmp.getInt();
+ }
+ if (tmp.isString()) {
+ // UNSUPPORTED
+ }
+ tmp.free();
+
+ a->get(1, &tmp);
+ if (tmp.isInt()) {
+ start.units_per_second = tmp.getInt();
+ }
+ tmp.free();
+ }
+ }
+ obj1.free();
+
+ if (!aDict->dictLookup("Duration", &obj1)->isNull()) {
+ if (obj1.isInt()) {
+ duration.units = obj1.getInt();
+ } else if (obj1.isString()) {
+ // UNSUPPORTED
+ } else if (obj1.isArray()) {
+ Array* a = obj1.getArray();
+
+ Object tmp;
+ a->get(0, &tmp);
+ if (tmp.isInt()) {
+ duration.units = tmp.getInt();
+ }
+ if (tmp.isString()) {
+ // UNSUPPORTED
+ }
+ tmp.free();
+
+ a->get(1, &tmp);
+ if (tmp.isInt()) {
+ duration.units_per_second = tmp.getInt();
+ }
+ tmp.free();
+ }
+ }
+ obj1.free();
+
+ if (aDict->dictLookup("Rate", &obj1)->isNum()) {
+ rate = obj1.getNum();
+ }
+ obj1.free();
+
+ if (aDict->dictLookup("Volume", &obj1)->isNum()) {
+ // convert volume to [0 100]
+ volume = int((obj1.getNum() + 1.0) * 50);
+ }
+ obj1.free();
+
+ if (aDict->dictLookup("ShowControls", &obj1)->isBool()) {
+ showControls = obj1.getBool();
+ }
+ obj1.free();
+
+ if (aDict->dictLookup("Synchronous", &obj1)->isBool()) {
+ synchronousPlay = obj1.getBool();
+ }
+ obj1.free();
+
+ if (aDict->dictLookup("Mode", &obj1)->isName()) {
+ char* name = obj1.getName();
+ if (!strcmp(name, "Once")) {
+ repeatMode = repeatModeOnce;
+ } else if (!strcmp(name, "Open")) {
+ repeatMode = repeatModeOpen;
+ } else if (!strcmp(name, "Repeat")) {
+ repeatMode = repeatModeRepeat;
+ } else if (!strcmp(name,"Palindrome")) {
+ repeatMode = repeatModePalindrome;
+ }
+ }
+ obj1.free();
+
+ if (aDict->dictLookup("FWScale", &obj1)->isArray()) {
+ // the presence of that entry implies that the movie is to be played
+ // in a floating window
+ floatingWindow = gTrue;
+
+ Array* scale = obj1.getArray();
+ if (scale->getLength() >= 2) {
+ Object tmp;
+ if (scale->get(0, &tmp)->isInt()) {
+ znum = tmp.getInt();
+ }
+ tmp.free();
+ if (scale->get(1, &tmp)->isInt()) {
+ zdenum = tmp.getInt();
+ }
+ tmp.free();
+ }
+ }
+ obj1.free();
+
+ if (aDict->dictLookup("FWPosition", &obj1)->isArray()) {
+ Array* pos = obj1.getArray();
+ if (pos->getLength() >= 2) {
+ Object tmp;
+ if (pos->get(0, &tmp)->isNum()) {
+ xPosition = tmp.getNum();
+ }
+ tmp.free();
+ if (pos->get(1, &tmp)->isNum()) {
+ yPosition = tmp.getNum();
+ }
+ tmp.free();
+ }
+ }
+ obj1.free();
+}
+
+void Movie::parseMovie (Object *movieDict) {
+ fileName = NULL;
+ rotationAngle = 0;
+ width = -1;
+ height = -1;
+ showPoster = gFalse;
+
+ Object obj1, obj2;
+ if (getFileSpecNameForPlatform(movieDict->dictLookup("F", &obj1), &obj2)) {
+ fileName = obj2.getString()->copy();
+ obj2.free();
+ } else {
+ error (errSyntaxError, -1, "Invalid Movie");
+ ok = gFalse;
+ obj1.free();
+ return;
+ }
+ obj1.free();
+
+ if (movieDict->dictLookup("Aspect", &obj1)->isArray()) {
+ Array* aspect = obj1.getArray();
+ if (aspect->getLength() >= 2) {
+ Object tmp;
+ if( aspect->get(0, &tmp)->isNum() ) {
+ width = (int)floor( aspect->get(0, &tmp)->getNum() + 0.5 );
+ }
+ tmp.free();
+ if( aspect->get(1, &tmp)->isNum() ) {
+ height = (int)floor( aspect->get(1, &tmp)->getNum() + 0.5 );
+ }
+ tmp.free();
+ }
+ }
+ obj1.free();
+
+ if (movieDict->dictLookup("Rotate", &obj1)->isInt()) {
+ // round up to 90°
+ rotationAngle = (((obj1.getInt() + 360) % 360) % 90) * 90;
+ }
+ obj1.free();
+
+ //
+ // movie poster
+ //
+ if (!movieDict->dictLookupNF("Poster", &poster)->isNull()) {
+ if (poster.isRef() || poster.isStream()) {
+ showPoster = gTrue;
+ } else if (poster.isBool()) {
+ showPoster = poster.getBool();
+ poster.free();
+ } else {
+ poster.free();
+ }
+ }
+}
+
+Movie::~Movie() {
+ if (fileName)
+ delete fileName;
+ poster.free();
+}
+
+Movie::Movie(Object *movieDict) {
+ ok = gTrue;
+
+ if (movieDict->isDict())
+ parseMovie(movieDict);
+ else
+ ok = gFalse;
+}
+
+Movie::Movie(Object *movieDict, Object *aDict) {
+ ok = gTrue;
+
+ if (movieDict->isDict()) {
+ parseMovie(movieDict);
+ if (aDict->isDict())
+ MA.parseMovieActivation(aDict);
+ } else {
+ ok = gFalse;
+ }
+}
+
+void Movie::getFloatingWindowSize(int *widthA, int *heightA)
+{
+ *widthA = int(width * double(MA.znum) / MA.zdenum);
+ *heightA = int(height * double(MA.znum) / MA.zdenum);
+}
+
+Movie* Movie::copy() {
+
+ // call default copy constructor
+ Movie* new_movie = new Movie(*this);
+
+ if (fileName)
+ new_movie->fileName = fileName->copy();
+
+ poster.copy(&new_movie->poster);
+
+ return new_movie;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Movie.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Movie.h
new file mode 100644
index 00000000000..1a162659179
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Movie.h
@@ -0,0 +1,110 @@
+//*********************************************************************************
+// Movie.h
+//---------------------------------------------------------------------------------
+//
+//---------------------------------------------------------------------------------
+// Hugo Mercier <hmercier31[at]gmail.com> (c) 2008
+// Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//*********************************************************************************
+
+#ifndef _MOVIE_H_
+#define _MOVIE_H_
+
+#include "Object.h"
+
+struct MovieActivationParameters {
+
+ MovieActivationParameters();
+ ~MovieActivationParameters();
+
+ // parse from a "Movie Activation" dictionary
+ void parseMovieActivation(Object* actObj);
+
+ enum MovieRepeatMode {
+ repeatModeOnce,
+ repeatModeOpen,
+ repeatModeRepeat,
+ repeatModePalindrome
+ };
+
+ struct MovieTime {
+ MovieTime() { units_per_second = 0; }
+ Gulong units;
+ int units_per_second; // 0 : defined by movie
+ };
+
+ MovieTime start; // 0
+ MovieTime duration; // 0
+
+ double rate; // 1.0
+
+ int volume; // 100
+
+ GBool showControls; // false
+
+ GBool synchronousPlay; // false
+ MovieRepeatMode repeatMode; // repeatModeOnce
+
+ // floating window position
+ GBool floatingWindow;
+ double xPosition; // 0.5
+ double yPosition; // 0.5
+ int znum; // 1
+ int zdenum; // 1
+};
+
+class Movie {
+ public:
+ Movie(Object *objMovie, Object *objAct);
+ Movie(Object *objMovie);
+ ~Movie();
+
+ GBool isOk() { return ok; }
+ MovieActivationParameters* getActivationParameters() { return &MA; }
+
+ GooString* getFileName() { return fileName; }
+
+ Gushort getRotationAngle() { return rotationAngle; }
+ void getAspect (int *widthA, int *heightA) { *widthA = width; *heightA = height; }
+
+ Object *getPoster(Object *obj) { return poster.copy(obj); }
+ GBool getShowPoster() { return showPoster; }
+
+ GBool getUseFloatingWindow() { return MA.floatingWindow; }
+ void getFloatingWindowSize(int *width, int *height);
+
+ Movie* copy();
+
+ private:
+ void parseMovie (Object *movieDict);
+
+ GBool ok;
+
+ Gushort rotationAngle; // 0
+ int width; // Aspect
+ int height; // Aspect
+
+ Object poster;
+ GBool showPoster;
+
+ GooString* fileName;
+
+ MovieActivationParameters MA;
+};
+
+#endif
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToCharCode.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToCharCode.cc
new file mode 100644
index 00000000000..5448dc4ce10
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToCharCode.cc
@@ -0,0 +1,116 @@
+//========================================================================
+//
+// NameToCharCode.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "goo/gmem.h"
+#include "NameToCharCode.h"
+
+//------------------------------------------------------------------------
+
+struct NameToCharCodeEntry {
+ char *name;
+ CharCode c;
+};
+
+//------------------------------------------------------------------------
+
+NameToCharCode::NameToCharCode() {
+ int i;
+
+ size = 31;
+ len = 0;
+ tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry));
+ for (i = 0; i < size; ++i) {
+ tab[i].name = NULL;
+ }
+}
+
+NameToCharCode::~NameToCharCode() {
+ int i;
+
+ for (i = 0; i < size; ++i) {
+ if (tab[i].name) {
+ gfree(tab[i].name);
+ }
+ }
+ gfree(tab);
+}
+
+void NameToCharCode::add(const char *name, CharCode c) {
+ NameToCharCodeEntry *oldTab;
+ int h, i, oldSize;
+
+ // expand the table if necessary
+ if (len >= size / 2) {
+ oldSize = size;
+ oldTab = tab;
+ size = 2*size + 1;
+ tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry));
+ for (h = 0; h < size; ++h) {
+ tab[h].name = NULL;
+ }
+ for (i = 0; i < oldSize; ++i) {
+ if (oldTab[i].name) {
+ h = hash(oldTab[i].name);
+ while (tab[h].name) {
+ if (++h == size) {
+ h = 0;
+ }
+ }
+ tab[h] = oldTab[i];
+ }
+ }
+ gfree(oldTab);
+ }
+
+ // add the new name
+ h = hash(name);
+ while (tab[h].name && strcmp(tab[h].name, name)) {
+ if (++h == size) {
+ h = 0;
+ }
+ }
+ if (!tab[h].name) {
+ tab[h].name = copyString(name);
+ }
+ tab[h].c = c;
+
+ ++len;
+}
+
+CharCode NameToCharCode::lookup(const char *name) {
+ int h;
+
+ h = hash(name);
+ while (tab[h].name) {
+ if (!strcmp(tab[h].name, name)) {
+ return tab[h].c;
+ }
+ if (++h == size) {
+ h = 0;
+ }
+ }
+ return 0;
+}
+
+int NameToCharCode::hash(const char *name) {
+ const char *p;
+ unsigned int h;
+
+ h = 0;
+ for (p = name; *p; ++p) {
+ h = 17 * h + (int)(*p & 0xff);
+ }
+ return (int)(h % size);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToCharCode.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToCharCode.h
new file mode 100644
index 00000000000..5b1092bb96b
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToCharCode.h
@@ -0,0 +1,40 @@
+//========================================================================
+//
+// NameToCharCode.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef NAMETOCHARCODE_H
+#define NAMETOCHARCODE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "CharTypes.h"
+
+struct NameToCharCodeEntry;
+
+//------------------------------------------------------------------------
+
+class NameToCharCode {
+public:
+
+ NameToCharCode();
+ ~NameToCharCode();
+
+ void add(const char *name, CharCode c);
+ CharCode lookup(const char *name);
+
+private:
+
+ int hash(const char *name);
+
+ NameToCharCodeEntry *tab;
+ int size;
+ int len;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToUnicodeTable.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToUnicodeTable.h
new file mode 100644
index 00000000000..827edbaee60
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/NameToUnicodeTable.h
@@ -0,0 +1,4484 @@
+//========================================================================
+//
+// NameToUnicodeTable.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2011, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Jason Crain <jason@aquaticape.us>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include "CharTypes.h"
+
+#include <stddef.h>
+
+struct NameToUnicodeTab {
+ Unicode u;
+ const char *name;
+};
+
+// map character names to Unicode
+static struct NameToUnicodeTab nameToUnicodeTextTab[] = {
+ {0x0021, "!"},
+ {0x0023, "#"},
+ {0x0024, "$"},
+ {0x0025, "%"},
+ {0x0026, "&"},
+ {0x0027, "'"},
+ {0x0028, "("},
+ {0x0029, ")"},
+ {0x002a, "*"},
+ {0x002b, "+"},
+ {0x002c, ","},
+ {0x002d, "-"},
+ {0x002e, "."},
+ {0x002f, "/"},
+ {0x0030, "0"},
+ {0x0031, "1"},
+ {0x0032, "2"},
+ {0x0033, "3"},
+ {0x0034, "4"},
+ {0x0035, "5"},
+ {0x0036, "6"},
+ {0x0037, "7"},
+ {0x0038, "8"},
+ {0x0039, "9"},
+ {0x003a, ":"},
+ {0x003b, ";"},
+ {0x003c, "<"},
+ {0x003d, "="},
+ {0x003e, ">"},
+ {0x003f, "?"},
+ {0x0040, "@"},
+ {0x0041, "A"},
+ {0x00c6, "AE"},
+ {0x01fc, "AEacute"},
+ {0x01e2, "AEmacron"},
+ {0xf7e6, "AEsmall"},
+ {0x00c1, "Aacute"},
+ {0xf7e1, "Aacutesmall"},
+ {0x0102, "Abreve"},
+ {0x1eae, "Abreveacute"},
+ {0x04d0, "Abrevecyrillic"},
+ {0x1eb6, "Abrevedotbelow"},
+ {0x1eb0, "Abrevegrave"},
+ {0x1eb2, "Abrevehookabove"},
+ {0x1eb4, "Abrevetilde"},
+ {0x01cd, "Acaron"},
+ {0x24b6, "Acircle"},
+ {0x00c2, "Acircumflex"},
+ {0x1ea4, "Acircumflexacute"},
+ {0x1eac, "Acircumflexdotbelow"},
+ {0x1ea6, "Acircumflexgrave"},
+ {0x1ea8, "Acircumflexhookabove"},
+ {0xf7e2, "Acircumflexsmall"},
+ {0x1eaa, "Acircumflextilde"},
+ {0xf6c9, "Acute"},
+ {0xf7b4, "Acutesmall"},
+ {0x0410, "Acyrillic"},
+ {0x0200, "Adblgrave"},
+ {0x00c4, "Adieresis"},
+ {0x04d2, "Adieresiscyrillic"},
+ {0x01de, "Adieresismacron"},
+ {0xf7e4, "Adieresissmall"},
+ {0x1ea0, "Adotbelow"},
+ {0x01e0, "Adotmacron"},
+ {0x00c0, "Agrave"},
+ {0xf7e0, "Agravesmall"},
+ {0x1ea2, "Ahookabove"},
+ {0x04d4, "Aiecyrillic"},
+ {0x0202, "Ainvertedbreve"},
+ {0x0391, "Alpha"},
+ {0x0386, "Alphatonos"},
+ {0x0100, "Amacron"},
+ {0xff21, "Amonospace"},
+ {0x0104, "Aogonek"},
+ {0x00c5, "Aring"},
+ {0x01fa, "Aringacute"},
+ {0x1e00, "Aringbelow"},
+ {0xf7e5, "Aringsmall"},
+ {0xf761, "Asmall"},
+ {0x00c3, "Atilde"},
+ {0xf7e3, "Atildesmall"},
+ {0x0531, "Aybarmenian"},
+ {0x0042, "B"},
+ {0x24b7, "Bcircle"},
+ {0x1e02, "Bdotaccent"},
+ {0x1e04, "Bdotbelow"},
+ {0x0411, "Becyrillic"},
+ {0x0532, "Benarmenian"},
+ {0x0392, "Beta"},
+ {0x0181, "Bhook"},
+ {0x1e06, "Blinebelow"},
+ {0xff22, "Bmonospace"},
+ {0xf6f4, "Brevesmall"},
+ {0xf762, "Bsmall"},
+ {0x0182, "Btopbar"},
+ {0x0043, "C"},
+ {0x053e, "Caarmenian"},
+ {0x0106, "Cacute"},
+ {0xf6ca, "Caron"},
+ {0xf6f5, "Caronsmall"},
+ {0x010c, "Ccaron"},
+ {0x00c7, "Ccedilla"},
+ {0x1e08, "Ccedillaacute"},
+ {0xf7e7, "Ccedillasmall"},
+ {0x24b8, "Ccircle"},
+ {0x0108, "Ccircumflex"},
+ {0x010a, "Cdot"},
+ {0x010a, "Cdotaccent"},
+ {0xf7b8, "Cedillasmall"},
+ {0x0549, "Chaarmenian"},
+ {0x04bc, "Cheabkhasiancyrillic"},
+ {0x0427, "Checyrillic"},
+ {0x04be, "Chedescenderabkhasiancyrillic"},
+ {0x04b6, "Chedescendercyrillic"},
+ {0x04f4, "Chedieresiscyrillic"},
+ {0x0543, "Cheharmenian"},
+ {0x04cb, "Chekhakassiancyrillic"},
+ {0x04b8, "Cheverticalstrokecyrillic"},
+ {0x03a7, "Chi"},
+ {0x0187, "Chook"},
+ {0xf6f6, "Circumflexsmall"},
+ {0xff23, "Cmonospace"},
+ {0x0551, "Coarmenian"},
+ {0xf763, "Csmall"},
+ {0x0044, "D"},
+ {0x01f1, "DZ"},
+ {0x01c4, "DZcaron"},
+ {0x0534, "Daarmenian"},
+ {0x0189, "Dafrican"},
+ {0x010e, "Dcaron"},
+ {0x1e10, "Dcedilla"},
+ {0x24b9, "Dcircle"},
+ {0x1e12, "Dcircumflexbelow"},
+ {0x0110, "Dcroat"},
+ {0x1e0a, "Ddotaccent"},
+ {0x1e0c, "Ddotbelow"},
+ {0x0414, "Decyrillic"},
+ {0x03ee, "Deicoptic"},
+ {0x2206, "Delta"},
+ {0x0394, "Deltagreek"},
+ {0x018a, "Dhook"},
+ {0xf6cb, "Dieresis"},
+ {0xf6cc, "DieresisAcute"},
+ {0xf6cd, "DieresisGrave"},
+ {0xf7a8, "Dieresissmall"},
+ {0x03dc, "Digammagreek"},
+ {0x0402, "Djecyrillic"},
+ {0x1e0e, "Dlinebelow"},
+ {0xff24, "Dmonospace"},
+ {0xf6f7, "Dotaccentsmall"},
+ {0x0110, "Dslash"},
+ {0xf764, "Dsmall"},
+ {0x018b, "Dtopbar"},
+ {0x01f2, "Dz"},
+ {0x01c5, "Dzcaron"},
+ {0x04e0, "Dzeabkhasiancyrillic"},
+ {0x0405, "Dzecyrillic"},
+ {0x040f, "Dzhecyrillic"},
+ {0x0045, "E"},
+ {0x00c9, "Eacute"},
+ {0xf7e9, "Eacutesmall"},
+ {0x0114, "Ebreve"},
+ {0x011a, "Ecaron"},
+ {0x1e1c, "Ecedillabreve"},
+ {0x0535, "Echarmenian"},
+ {0x24ba, "Ecircle"},
+ {0x00ca, "Ecircumflex"},
+ {0x1ebe, "Ecircumflexacute"},
+ {0x1e18, "Ecircumflexbelow"},
+ {0x1ec6, "Ecircumflexdotbelow"},
+ {0x1ec0, "Ecircumflexgrave"},
+ {0x1ec2, "Ecircumflexhookabove"},
+ {0xf7ea, "Ecircumflexsmall"},
+ {0x1ec4, "Ecircumflextilde"},
+ {0x0404, "Ecyrillic"},
+ {0x0204, "Edblgrave"},
+ {0x00cb, "Edieresis"},
+ {0xf7eb, "Edieresissmall"},
+ {0x0116, "Edot"},
+ {0x0116, "Edotaccent"},
+ {0x1eb8, "Edotbelow"},
+ {0x0424, "Efcyrillic"},
+ {0x00c8, "Egrave"},
+ {0xf7e8, "Egravesmall"},
+ {0x0537, "Eharmenian"},
+ {0x1eba, "Ehookabove"},
+ {0x2167, "Eightroman"},
+ {0x0206, "Einvertedbreve"},
+ {0x0464, "Eiotifiedcyrillic"},
+ {0x041b, "Elcyrillic"},
+ {0x216a, "Elevenroman"},
+ {0x0112, "Emacron"},
+ {0x1e16, "Emacronacute"},
+ {0x1e14, "Emacrongrave"},
+ {0x041c, "Emcyrillic"},
+ {0xff25, "Emonospace"},
+ {0x041d, "Encyrillic"},
+ {0x04a2, "Endescendercyrillic"},
+ {0x014a, "Eng"},
+ {0x04a4, "Enghecyrillic"},
+ {0x04c7, "Enhookcyrillic"},
+ {0x0118, "Eogonek"},
+ {0x0190, "Eopen"},
+ {0x0395, "Epsilon"},
+ {0x0388, "Epsilontonos"},
+ {0x0420, "Ercyrillic"},
+ {0x018e, "Ereversed"},
+ {0x042d, "Ereversedcyrillic"},
+ {0x0421, "Escyrillic"},
+ {0x04aa, "Esdescendercyrillic"},
+ {0x01a9, "Esh"},
+ {0xf765, "Esmall"},
+ {0x0397, "Eta"},
+ {0x0538, "Etarmenian"},
+ {0x0389, "Etatonos"},
+ {0x00d0, "Eth"},
+ {0xf7f0, "Ethsmall"},
+ {0x1ebc, "Etilde"},
+ {0x1e1a, "Etildebelow"},
+ {0x20ac, "Euro"},
+ {0x01b7, "Ezh"},
+ {0x01ee, "Ezhcaron"},
+ {0x01b8, "Ezhreversed"},
+ {0x0046, "F"},
+ {0x24bb, "Fcircle"},
+ {0x1e1e, "Fdotaccent"},
+ {0x0556, "Feharmenian"},
+ {0x03e4, "Feicoptic"},
+ {0x0191, "Fhook"},
+ {0x0472, "Fitacyrillic"},
+ {0x2164, "Fiveroman"},
+ {0xff26, "Fmonospace"},
+ {0x2163, "Fourroman"},
+ {0xf766, "Fsmall"},
+ {0x0047, "G"},
+ {0x3387, "GBsquare"},
+ {0x01f4, "Gacute"},
+ {0x0393, "Gamma"},
+ {0x0194, "Gammaafrican"},
+ {0x03ea, "Gangiacoptic"},
+ {0x011e, "Gbreve"},
+ {0x01e6, "Gcaron"},
+ {0x0122, "Gcedilla"},
+ {0x24bc, "Gcircle"},
+ {0x011c, "Gcircumflex"},
+ {0x0122, "Gcommaaccent"},
+ {0x0120, "Gdot"},
+ {0x0120, "Gdotaccent"},
+ {0x0413, "Gecyrillic"},
+ {0x0542, "Ghadarmenian"},
+ {0x0494, "Ghemiddlehookcyrillic"},
+ {0x0492, "Ghestrokecyrillic"},
+ {0x0490, "Gheupturncyrillic"},
+ {0x0193, "Ghook"},
+ {0x0533, "Gimarmenian"},
+ {0x0403, "Gjecyrillic"},
+ {0x1e20, "Gmacron"},
+ {0xff27, "Gmonospace"},
+ {0xf6ce, "Grave"},
+ {0xf760, "Gravesmall"},
+ {0xf767, "Gsmall"},
+ {0x029b, "Gsmallhook"},
+ {0x01e4, "Gstroke"},
+ {0x0048, "H"},
+ {0x25cf, "H18533"},
+ {0x25aa, "H18543"},
+ {0x25ab, "H18551"},
+ {0x25a1, "H22073"},
+ {0x33cb, "HPsquare"},
+ {0x04a8, "Haabkhasiancyrillic"},
+ {0x04b2, "Hadescendercyrillic"},
+ {0x042a, "Hardsigncyrillic"},
+ {0x0126, "Hbar"},
+ {0x1e2a, "Hbrevebelow"},
+ {0x1e28, "Hcedilla"},
+ {0x24bd, "Hcircle"},
+ {0x0124, "Hcircumflex"},
+ {0x1e26, "Hdieresis"},
+ {0x1e22, "Hdotaccent"},
+ {0x1e24, "Hdotbelow"},
+ {0xff28, "Hmonospace"},
+ {0x0540, "Hoarmenian"},
+ {0x03e8, "Horicoptic"},
+ {0xf768, "Hsmall"},
+ {0xf6cf, "Hungarumlaut"},
+ {0xf6f8, "Hungarumlautsmall"},
+ {0x3390, "Hzsquare"},
+ {0x0049, "I"},
+ {0x042f, "IAcyrillic"},
+ {0x0132, "IJ"},
+ {0x042e, "IUcyrillic"},
+ {0x00cd, "Iacute"},
+ {0xf7ed, "Iacutesmall"},
+ {0x012c, "Ibreve"},
+ {0x01cf, "Icaron"},
+ {0x24be, "Icircle"},
+ {0x00ce, "Icircumflex"},
+ {0xf7ee, "Icircumflexsmall"},
+ {0x0406, "Icyrillic"},
+ {0x0208, "Idblgrave"},
+ {0x00cf, "Idieresis"},
+ {0x1e2e, "Idieresisacute"},
+ {0x04e4, "Idieresiscyrillic"},
+ {0xf7ef, "Idieresissmall"},
+ {0x0130, "Idot"},
+ {0x0130, "Idotaccent"},
+ {0x1eca, "Idotbelow"},
+ {0x04d6, "Iebrevecyrillic"},
+ {0x0415, "Iecyrillic"},
+ {0x2111, "Ifraktur"},
+ {0x00cc, "Igrave"},
+ {0xf7ec, "Igravesmall"},
+ {0x1ec8, "Ihookabove"},
+ {0x0418, "Iicyrillic"},
+ {0x020a, "Iinvertedbreve"},
+ {0x0419, "Iishortcyrillic"},
+ {0x012a, "Imacron"},
+ {0x04e2, "Imacroncyrillic"},
+ {0xff29, "Imonospace"},
+ {0x053b, "Iniarmenian"},
+ {0x0401, "Iocyrillic"},
+ {0x012e, "Iogonek"},
+ {0x0399, "Iota"},
+ {0x0196, "Iotaafrican"},
+ {0x03aa, "Iotadieresis"},
+ {0x038a, "Iotatonos"},
+ {0xf769, "Ismall"},
+ {0x0197, "Istroke"},
+ {0x0128, "Itilde"},
+ {0x1e2c, "Itildebelow"},
+ {0x0474, "Izhitsacyrillic"},
+ {0x0476, "Izhitsadblgravecyrillic"},
+ {0x004a, "J"},
+ {0x0541, "Jaarmenian"},
+ {0x24bf, "Jcircle"},
+ {0x0134, "Jcircumflex"},
+ {0x0408, "Jecyrillic"},
+ {0x054b, "Jheharmenian"},
+ {0xff2a, "Jmonospace"},
+ {0xf76a, "Jsmall"},
+ {0x004b, "K"},
+ {0x3385, "KBsquare"},
+ {0x33cd, "KKsquare"},
+ {0x04a0, "Kabashkircyrillic"},
+ {0x1e30, "Kacute"},
+ {0x041a, "Kacyrillic"},
+ {0x049a, "Kadescendercyrillic"},
+ {0x04c3, "Kahookcyrillic"},
+ {0x039a, "Kappa"},
+ {0x049e, "Kastrokecyrillic"},
+ {0x049c, "Kaverticalstrokecyrillic"},
+ {0x01e8, "Kcaron"},
+ {0x0136, "Kcedilla"},
+ {0x24c0, "Kcircle"},
+ {0x0136, "Kcommaaccent"},
+ {0x1e32, "Kdotbelow"},
+ {0x0554, "Keharmenian"},
+ {0x053f, "Kenarmenian"},
+ {0x0425, "Khacyrillic"},
+ {0x03e6, "Kheicoptic"},
+ {0x0198, "Khook"},
+ {0x040c, "Kjecyrillic"},
+ {0x1e34, "Klinebelow"},
+ {0xff2b, "Kmonospace"},
+ {0x0480, "Koppacyrillic"},
+ {0x03de, "Koppagreek"},
+ {0x046e, "Ksicyrillic"},
+ {0xf76b, "Ksmall"},
+ {0x004c, "L"},
+ {0x01c7, "LJ"},
+ {0xf6bf, "LL"},
+ {0x0139, "Lacute"},
+ {0x039b, "Lambda"},
+ {0x013d, "Lcaron"},
+ {0x013b, "Lcedilla"},
+ {0x24c1, "Lcircle"},
+ {0x1e3c, "Lcircumflexbelow"},
+ {0x013b, "Lcommaaccent"},
+ {0x013f, "Ldot"},
+ {0x013f, "Ldotaccent"},
+ {0x1e36, "Ldotbelow"},
+ {0x1e38, "Ldotbelowmacron"},
+ {0x053c, "Liwnarmenian"},
+ {0x01c8, "Lj"},
+ {0x0409, "Ljecyrillic"},
+ {0x1e3a, "Llinebelow"},
+ {0xff2c, "Lmonospace"},
+ {0x0141, "Lslash"},
+ {0xf6f9, "Lslashsmall"},
+ {0xf76c, "Lsmall"},
+ {0x004d, "M"},
+ {0x3386, "MBsquare"},
+ {0xf6d0, "Macron"},
+ {0xf7af, "Macronsmall"},
+ {0x1e3e, "Macute"},
+ {0x24c2, "Mcircle"},
+ {0x1e40, "Mdotaccent"},
+ {0x1e42, "Mdotbelow"},
+ {0x0544, "Menarmenian"},
+ {0xff2d, "Mmonospace"},
+ {0xf76d, "Msmall"},
+ {0x019c, "Mturned"},
+ {0x039c, "Mu"},
+ {0x004e, "N"},
+ {0x01ca, "NJ"},
+ {0x0143, "Nacute"},
+ {0x0147, "Ncaron"},
+ {0x0145, "Ncedilla"},
+ {0x24c3, "Ncircle"},
+ {0x1e4a, "Ncircumflexbelow"},
+ {0x0145, "Ncommaaccent"},
+ {0x1e44, "Ndotaccent"},
+ {0x1e46, "Ndotbelow"},
+ {0x019d, "Nhookleft"},
+ {0x2168, "Nineroman"},
+ {0x01cb, "Nj"},
+ {0x040a, "Njecyrillic"},
+ {0x1e48, "Nlinebelow"},
+ {0xff2e, "Nmonospace"},
+ {0x0546, "Nowarmenian"},
+ {0xf76e, "Nsmall"},
+ {0x00d1, "Ntilde"},
+ {0xf7f1, "Ntildesmall"},
+ {0x039d, "Nu"},
+ {0x004f, "O"},
+ {0x0152, "OE"},
+ {0xf6fa, "OEsmall"},
+ {0x00d3, "Oacute"},
+ {0xf7f3, "Oacutesmall"},
+ {0x04e8, "Obarredcyrillic"},
+ {0x04ea, "Obarreddieresiscyrillic"},
+ {0x014e, "Obreve"},
+ {0x01d1, "Ocaron"},
+ {0x019f, "Ocenteredtilde"},
+ {0x24c4, "Ocircle"},
+ {0x00d4, "Ocircumflex"},
+ {0x1ed0, "Ocircumflexacute"},
+ {0x1ed8, "Ocircumflexdotbelow"},
+ {0x1ed2, "Ocircumflexgrave"},
+ {0x1ed4, "Ocircumflexhookabove"},
+ {0xf7f4, "Ocircumflexsmall"},
+ {0x1ed6, "Ocircumflextilde"},
+ {0x041e, "Ocyrillic"},
+ {0x0150, "Odblacute"},
+ {0x020c, "Odblgrave"},
+ {0x00d6, "Odieresis"},
+ {0x04e6, "Odieresiscyrillic"},
+ {0xf7f6, "Odieresissmall"},
+ {0x1ecc, "Odotbelow"},
+ {0xf6fb, "Ogoneksmall"},
+ {0x00d2, "Ograve"},
+ {0xf7f2, "Ogravesmall"},
+ {0x0555, "Oharmenian"},
+ {0x2126, "Ohm"},
+ {0x1ece, "Ohookabove"},
+ {0x01a0, "Ohorn"},
+ {0x1eda, "Ohornacute"},
+ {0x1ee2, "Ohorndotbelow"},
+ {0x1edc, "Ohorngrave"},
+ {0x1ede, "Ohornhookabove"},
+ {0x1ee0, "Ohorntilde"},
+ {0x0150, "Ohungarumlaut"},
+ {0x01a2, "Oi"},
+ {0x020e, "Oinvertedbreve"},
+ {0x014c, "Omacron"},
+ {0x1e52, "Omacronacute"},
+ {0x1e50, "Omacrongrave"},
+ {0x2126, "Omega"},
+ {0x0460, "Omegacyrillic"},
+ {0x03a9, "Omegagreek"},
+ {0x047a, "Omegaroundcyrillic"},
+ {0x047c, "Omegatitlocyrillic"},
+ {0x038f, "Omegatonos"},
+ {0x039f, "Omicron"},
+ {0x038c, "Omicrontonos"},
+ {0xff2f, "Omonospace"},
+ {0x2160, "Oneroman"},
+ {0x01ea, "Oogonek"},
+ {0x01ec, "Oogonekmacron"},
+ {0x0186, "Oopen"},
+ {0x00d8, "Oslash"},
+ {0x01fe, "Oslashacute"},
+ {0xf7f8, "Oslashsmall"},
+ {0xf76f, "Osmall"},
+ {0x01fe, "Ostrokeacute"},
+ {0x047e, "Otcyrillic"},
+ {0x00d5, "Otilde"},
+ {0x1e4c, "Otildeacute"},
+ {0x1e4e, "Otildedieresis"},
+ {0xf7f5, "Otildesmall"},
+ {0x0050, "P"},
+ {0x1e54, "Pacute"},
+ {0x24c5, "Pcircle"},
+ {0x1e56, "Pdotaccent"},
+ {0x041f, "Pecyrillic"},
+ {0x054a, "Peharmenian"},
+ {0x04a6, "Pemiddlehookcyrillic"},
+ {0x03a6, "Phi"},
+ {0x01a4, "Phook"},
+ {0x03a0, "Pi"},
+ {0x0553, "Piwrarmenian"},
+ {0xff30, "Pmonospace"},
+ {0x03a8, "Psi"},
+ {0x0470, "Psicyrillic"},
+ {0xf770, "Psmall"},
+ {0x0051, "Q"},
+ {0x24c6, "Qcircle"},
+ {0xff31, "Qmonospace"},
+ {0xf771, "Qsmall"},
+ {0x0052, "R"},
+ {0x054c, "Raarmenian"},
+ {0x0154, "Racute"},
+ {0x0158, "Rcaron"},
+ {0x0156, "Rcedilla"},
+ {0x24c7, "Rcircle"},
+ {0x0156, "Rcommaaccent"},
+ {0x0210, "Rdblgrave"},
+ {0x1e58, "Rdotaccent"},
+ {0x1e5a, "Rdotbelow"},
+ {0x1e5c, "Rdotbelowmacron"},
+ {0x0550, "Reharmenian"},
+ {0x211c, "Rfraktur"},
+ {0x03a1, "Rho"},
+ {0xf6fc, "Ringsmall"},
+ {0x0212, "Rinvertedbreve"},
+ {0x1e5e, "Rlinebelow"},
+ {0xff32, "Rmonospace"},
+ {0xf772, "Rsmall"},
+ {0x0281, "Rsmallinverted"},
+ {0x02b6, "Rsmallinvertedsuperior"},
+ {0x0053, "S"},
+ {0x250c, "SF010000"},
+ {0x2514, "SF020000"},
+ {0x2510, "SF030000"},
+ {0x2518, "SF040000"},
+ {0x253c, "SF050000"},
+ {0x252c, "SF060000"},
+ {0x2534, "SF070000"},
+ {0x251c, "SF080000"},
+ {0x2524, "SF090000"},
+ {0x2500, "SF100000"},
+ {0x2502, "SF110000"},
+ {0x2561, "SF190000"},
+ {0x2562, "SF200000"},
+ {0x2556, "SF210000"},
+ {0x2555, "SF220000"},
+ {0x2563, "SF230000"},
+ {0x2551, "SF240000"},
+ {0x2557, "SF250000"},
+ {0x255d, "SF260000"},
+ {0x255c, "SF270000"},
+ {0x255b, "SF280000"},
+ {0x255e, "SF360000"},
+ {0x255f, "SF370000"},
+ {0x255a, "SF380000"},
+ {0x2554, "SF390000"},
+ {0x2569, "SF400000"},
+ {0x2566, "SF410000"},
+ {0x2560, "SF420000"},
+ {0x2550, "SF430000"},
+ {0x256c, "SF440000"},
+ {0x2567, "SF450000"},
+ {0x2568, "SF460000"},
+ {0x2564, "SF470000"},
+ {0x2565, "SF480000"},
+ {0x2559, "SF490000"},
+ {0x2558, "SF500000"},
+ {0x2552, "SF510000"},
+ {0x2553, "SF520000"},
+ {0x256b, "SF530000"},
+ {0x256a, "SF540000"},
+ {0x015a, "Sacute"},
+ {0x1e64, "Sacutedotaccent"},
+ {0x03e0, "Sampigreek"},
+ {0x0160, "Scaron"},
+ {0x1e66, "Scarondotaccent"},
+ {0xf6fd, "Scaronsmall"},
+ {0x015e, "Scedilla"},
+ {0x018f, "Schwa"},
+ {0x04d8, "Schwacyrillic"},
+ {0x04da, "Schwadieresiscyrillic"},
+ {0x24c8, "Scircle"},
+ {0x015c, "Scircumflex"},
+ {0x0218, "Scommaaccent"},
+ {0x1e60, "Sdotaccent"},
+ {0x1e62, "Sdotbelow"},
+ {0x1e68, "Sdotbelowdotaccent"},
+ {0x054d, "Seharmenian"},
+ {0x2166, "Sevenroman"},
+ {0x0547, "Shaarmenian"},
+ {0x0428, "Shacyrillic"},
+ {0x0429, "Shchacyrillic"},
+ {0x03e2, "Sheicoptic"},
+ {0x04ba, "Shhacyrillic"},
+ {0x03ec, "Shimacoptic"},
+ {0x03a3, "Sigma"},
+ {0x2165, "Sixroman"},
+ {0xff33, "Smonospace"},
+ {0x042c, "Softsigncyrillic"},
+ {0xf773, "Ssmall"},
+ {0x03da, "Stigmagreek"},
+ {0x0054, "T"},
+ {0x03a4, "Tau"},
+ {0x0166, "Tbar"},
+ {0x0164, "Tcaron"},
+ {0x0162, "Tcedilla"},
+ {0x24c9, "Tcircle"},
+ {0x1e70, "Tcircumflexbelow"},
+ {0x0162, "Tcommaaccent"},
+ {0x1e6a, "Tdotaccent"},
+ {0x1e6c, "Tdotbelow"},
+ {0x0422, "Tecyrillic"},
+ {0x04ac, "Tedescendercyrillic"},
+ {0x2169, "Tenroman"},
+ {0x04b4, "Tetsecyrillic"},
+ {0x0398, "Theta"},
+ {0x01ac, "Thook"},
+ {0x00de, "Thorn"},
+ {0xf7fe, "Thornsmall"},
+ {0x2162, "Threeroman"},
+ {0xf6fe, "Tildesmall"},
+ {0x054f, "Tiwnarmenian"},
+ {0x1e6e, "Tlinebelow"},
+ {0xff34, "Tmonospace"},
+ {0x0539, "Toarmenian"},
+ {0x01bc, "Tonefive"},
+ {0x0184, "Tonesix"},
+ {0x01a7, "Tonetwo"},
+ {0x01ae, "Tretroflexhook"},
+ {0x0426, "Tsecyrillic"},
+ {0x040b, "Tshecyrillic"},
+ {0xf774, "Tsmall"},
+ {0x216b, "Twelveroman"},
+ {0x2161, "Tworoman"},
+ {0x0055, "U"},
+ {0x00da, "Uacute"},
+ {0xf7fa, "Uacutesmall"},
+ {0x016c, "Ubreve"},
+ {0x01d3, "Ucaron"},
+ {0x24ca, "Ucircle"},
+ {0x00db, "Ucircumflex"},
+ {0x1e76, "Ucircumflexbelow"},
+ {0xf7fb, "Ucircumflexsmall"},
+ {0x0423, "Ucyrillic"},
+ {0x0170, "Udblacute"},
+ {0x0214, "Udblgrave"},
+ {0x00dc, "Udieresis"},
+ {0x01d7, "Udieresisacute"},
+ {0x1e72, "Udieresisbelow"},
+ {0x01d9, "Udieresiscaron"},
+ {0x04f0, "Udieresiscyrillic"},
+ {0x01db, "Udieresisgrave"},
+ {0x01d5, "Udieresismacron"},
+ {0xf7fc, "Udieresissmall"},
+ {0x1ee4, "Udotbelow"},
+ {0x00d9, "Ugrave"},
+ {0xf7f9, "Ugravesmall"},
+ {0x1ee6, "Uhookabove"},
+ {0x01af, "Uhorn"},
+ {0x1ee8, "Uhornacute"},
+ {0x1ef0, "Uhorndotbelow"},
+ {0x1eea, "Uhorngrave"},
+ {0x1eec, "Uhornhookabove"},
+ {0x1eee, "Uhorntilde"},
+ {0x0170, "Uhungarumlaut"},
+ {0x04f2, "Uhungarumlautcyrillic"},
+ {0x0216, "Uinvertedbreve"},
+ {0x0478, "Ukcyrillic"},
+ {0x016a, "Umacron"},
+ {0x04ee, "Umacroncyrillic"},
+ {0x1e7a, "Umacrondieresis"},
+ {0xff35, "Umonospace"},
+ {0x0172, "Uogonek"},
+ {0x03a5, "Upsilon"},
+ {0x03d2, "Upsilon1"},
+ {0x03d3, "Upsilonacutehooksymbolgreek"},
+ {0x01b1, "Upsilonafrican"},
+ {0x03ab, "Upsilondieresis"},
+ {0x03d4, "Upsilondieresishooksymbolgreek"},
+ {0x03d2, "Upsilonhooksymbol"},
+ {0x038e, "Upsilontonos"},
+ {0x016e, "Uring"},
+ {0x040e, "Ushortcyrillic"},
+ {0xf775, "Usmall"},
+ {0x04ae, "Ustraightcyrillic"},
+ {0x04b0, "Ustraightstrokecyrillic"},
+ {0x0168, "Utilde"},
+ {0x1e78, "Utildeacute"},
+ {0x1e74, "Utildebelow"},
+ {0x0056, "V"},
+ {0x24cb, "Vcircle"},
+ {0x1e7e, "Vdotbelow"},
+ {0x0412, "Vecyrillic"},
+ {0x054e, "Vewarmenian"},
+ {0x01b2, "Vhook"},
+ {0xff36, "Vmonospace"},
+ {0x0548, "Voarmenian"},
+ {0xf776, "Vsmall"},
+ {0x1e7c, "Vtilde"},
+ {0x0057, "W"},
+ {0x1e82, "Wacute"},
+ {0x24cc, "Wcircle"},
+ {0x0174, "Wcircumflex"},
+ {0x1e84, "Wdieresis"},
+ {0x1e86, "Wdotaccent"},
+ {0x1e88, "Wdotbelow"},
+ {0x1e80, "Wgrave"},
+ {0xff37, "Wmonospace"},
+ {0xf777, "Wsmall"},
+ {0x0058, "X"},
+ {0x24cd, "Xcircle"},
+ {0x1e8c, "Xdieresis"},
+ {0x1e8a, "Xdotaccent"},
+ {0x053d, "Xeharmenian"},
+ {0x039e, "Xi"},
+ {0xff38, "Xmonospace"},
+ {0xf778, "Xsmall"},
+ {0x0059, "Y"},
+ {0x00dd, "Yacute"},
+ {0xf7fd, "Yacutesmall"},
+ {0x0462, "Yatcyrillic"},
+ {0x24ce, "Ycircle"},
+ {0x0176, "Ycircumflex"},
+ {0x0178, "Ydieresis"},
+ {0xf7ff, "Ydieresissmall"},
+ {0x1e8e, "Ydotaccent"},
+ {0x1ef4, "Ydotbelow"},
+ {0x042b, "Yericyrillic"},
+ {0x04f8, "Yerudieresiscyrillic"},
+ {0x1ef2, "Ygrave"},
+ {0x01b3, "Yhook"},
+ {0x1ef6, "Yhookabove"},
+ {0x0545, "Yiarmenian"},
+ {0x0407, "Yicyrillic"},
+ {0x0552, "Yiwnarmenian"},
+ {0xff39, "Ymonospace"},
+ {0xf779, "Ysmall"},
+ {0x1ef8, "Ytilde"},
+ {0x046a, "Yusbigcyrillic"},
+ {0x046c, "Yusbigiotifiedcyrillic"},
+ {0x0466, "Yuslittlecyrillic"},
+ {0x0468, "Yuslittleiotifiedcyrillic"},
+ {0x005a, "Z"},
+ {0x0536, "Zaarmenian"},
+ {0x0179, "Zacute"},
+ {0x017d, "Zcaron"},
+ {0xf6ff, "Zcaronsmall"},
+ {0x24cf, "Zcircle"},
+ {0x1e90, "Zcircumflex"},
+ {0x017b, "Zdot"},
+ {0x017b, "Zdotaccent"},
+ {0x1e92, "Zdotbelow"},
+ {0x0417, "Zecyrillic"},
+ {0x0498, "Zedescendercyrillic"},
+ {0x04de, "Zedieresiscyrillic"},
+ {0x0396, "Zeta"},
+ {0x053a, "Zhearmenian"},
+ {0x04c1, "Zhebrevecyrillic"},
+ {0x0416, "Zhecyrillic"},
+ {0x0496, "Zhedescendercyrillic"},
+ {0x04dc, "Zhedieresiscyrillic"},
+ {0x1e94, "Zlinebelow"},
+ {0xff3a, "Zmonospace"},
+ {0xf77a, "Zsmall"},
+ {0x01b5, "Zstroke"},
+ {0x0022, "\""},
+ {0x005c, "\\"},
+ {0x005d, "]"},
+ {0x005e, "^"},
+ {0x005f, "_"},
+ {0x0060, "`"},
+ {0x0061, "a"},
+ {0x0986, "aabengali"},
+ {0x00e1, "aacute"},
+ {0x0906, "aadeva"},
+ {0x0a86, "aagujarati"},
+ {0x0a06, "aagurmukhi"},
+ {0x0a3e, "aamatragurmukhi"},
+ {0x3303, "aarusquare"},
+ {0x09be, "aavowelsignbengali"},
+ {0x093e, "aavowelsigndeva"},
+ {0x0abe, "aavowelsigngujarati"},
+ {0x055f, "abbreviationmarkarmenian"},
+ {0x0970, "abbreviationsigndeva"},
+ {0x0985, "abengali"},
+ {0x311a, "abopomofo"},
+ {0x0103, "abreve"},
+ {0x1eaf, "abreveacute"},
+ {0x04d1, "abrevecyrillic"},
+ {0x1eb7, "abrevedotbelow"},
+ {0x1eb1, "abrevegrave"},
+ {0x1eb3, "abrevehookabove"},
+ {0x1eb5, "abrevetilde"},
+ {0x01ce, "acaron"},
+ {0x24d0, "acircle"},
+ {0x00e2, "acircumflex"},
+ {0x1ea5, "acircumflexacute"},
+ {0x1ead, "acircumflexdotbelow"},
+ {0x1ea7, "acircumflexgrave"},
+ {0x1ea9, "acircumflexhookabove"},
+ {0x1eab, "acircumflextilde"},
+ {0x00b4, "acute"},
+ {0x0317, "acutebelowcmb"},
+ {0x0301, "acutecmb"},
+ {0x0301, "acutecomb"},
+ {0x0954, "acutedeva"},
+ {0x02cf, "acutelowmod"},
+ {0x0341, "acutetonecmb"},
+ {0x0430, "acyrillic"},
+ {0x0201, "adblgrave"},
+ {0x0a71, "addakgurmukhi"},
+ {0x0905, "adeva"},
+ {0x00e4, "adieresis"},
+ {0x04d3, "adieresiscyrillic"},
+ {0x01df, "adieresismacron"},
+ {0x1ea1, "adotbelow"},
+ {0x01e1, "adotmacron"},
+ {0x00e6, "ae"},
+ {0x01fd, "aeacute"},
+ {0x3150, "aekorean"},
+ {0x01e3, "aemacron"},
+ {0x2015, "afii00208"},
+ {0x20a4, "afii08941"},
+ {0x0410, "afii10017"},
+ {0x0411, "afii10018"},
+ {0x0412, "afii10019"},
+ {0x0413, "afii10020"},
+ {0x0414, "afii10021"},
+ {0x0415, "afii10022"},
+ {0x0401, "afii10023"},
+ {0x0416, "afii10024"},
+ {0x0417, "afii10025"},
+ {0x0418, "afii10026"},
+ {0x0419, "afii10027"},
+ {0x041a, "afii10028"},
+ {0x041b, "afii10029"},
+ {0x041c, "afii10030"},
+ {0x041d, "afii10031"},
+ {0x041e, "afii10032"},
+ {0x041f, "afii10033"},
+ {0x0420, "afii10034"},
+ {0x0421, "afii10035"},
+ {0x0422, "afii10036"},
+ {0x0423, "afii10037"},
+ {0x0424, "afii10038"},
+ {0x0425, "afii10039"},
+ {0x0426, "afii10040"},
+ {0x0427, "afii10041"},
+ {0x0428, "afii10042"},
+ {0x0429, "afii10043"},
+ {0x042a, "afii10044"},
+ {0x042b, "afii10045"},
+ {0x042c, "afii10046"},
+ {0x042d, "afii10047"},
+ {0x042e, "afii10048"},
+ {0x042f, "afii10049"},
+ {0x0490, "afii10050"},
+ {0x0402, "afii10051"},
+ {0x0403, "afii10052"},
+ {0x0404, "afii10053"},
+ {0x0405, "afii10054"},
+ {0x0406, "afii10055"},
+ {0x0407, "afii10056"},
+ {0x0408, "afii10057"},
+ {0x0409, "afii10058"},
+ {0x040a, "afii10059"},
+ {0x040b, "afii10060"},
+ {0x040c, "afii10061"},
+ {0x040e, "afii10062"},
+ {0xf6c4, "afii10063"},
+ {0xf6c5, "afii10064"},
+ {0x0430, "afii10065"},
+ {0x0431, "afii10066"},
+ {0x0432, "afii10067"},
+ {0x0433, "afii10068"},
+ {0x0434, "afii10069"},
+ {0x0435, "afii10070"},
+ {0x0451, "afii10071"},
+ {0x0436, "afii10072"},
+ {0x0437, "afii10073"},
+ {0x0438, "afii10074"},
+ {0x0439, "afii10075"},
+ {0x043a, "afii10076"},
+ {0x043b, "afii10077"},
+ {0x043c, "afii10078"},
+ {0x043d, "afii10079"},
+ {0x043e, "afii10080"},
+ {0x043f, "afii10081"},
+ {0x0440, "afii10082"},
+ {0x0441, "afii10083"},
+ {0x0442, "afii10084"},
+ {0x0443, "afii10085"},
+ {0x0444, "afii10086"},
+ {0x0445, "afii10087"},
+ {0x0446, "afii10088"},
+ {0x0447, "afii10089"},
+ {0x0448, "afii10090"},
+ {0x0449, "afii10091"},
+ {0x044a, "afii10092"},
+ {0x044b, "afii10093"},
+ {0x044c, "afii10094"},
+ {0x044d, "afii10095"},
+ {0x044e, "afii10096"},
+ {0x044f, "afii10097"},
+ {0x0491, "afii10098"},
+ {0x0452, "afii10099"},
+ {0x0453, "afii10100"},
+ {0x0454, "afii10101"},
+ {0x0455, "afii10102"},
+ {0x0456, "afii10103"},
+ {0x0457, "afii10104"},
+ {0x0458, "afii10105"},
+ {0x0459, "afii10106"},
+ {0x045a, "afii10107"},
+ {0x045b, "afii10108"},
+ {0x045c, "afii10109"},
+ {0x045e, "afii10110"},
+ {0x040f, "afii10145"},
+ {0x0462, "afii10146"},
+ {0x0472, "afii10147"},
+ {0x0474, "afii10148"},
+ {0xf6c6, "afii10192"},
+ {0x045f, "afii10193"},
+ {0x0463, "afii10194"},
+ {0x0473, "afii10195"},
+ {0x0475, "afii10196"},
+ {0xf6c7, "afii10831"},
+ {0xf6c8, "afii10832"},
+ {0x04d9, "afii10846"},
+ {0x200e, "afii299"},
+ {0x200f, "afii300"},
+ {0x200d, "afii301"},
+ {0x066a, "afii57381"},
+ {0x060c, "afii57388"},
+ {0x0660, "afii57392"},
+ {0x0661, "afii57393"},
+ {0x0662, "afii57394"},
+ {0x0663, "afii57395"},
+ {0x0664, "afii57396"},
+ {0x0665, "afii57397"},
+ {0x0666, "afii57398"},
+ {0x0667, "afii57399"},
+ {0x0668, "afii57400"},
+ {0x0669, "afii57401"},
+ {0x061b, "afii57403"},
+ {0x061f, "afii57407"},
+ {0x0621, "afii57409"},
+ {0x0622, "afii57410"},
+ {0x0623, "afii57411"},
+ {0x0624, "afii57412"},
+ {0x0625, "afii57413"},
+ {0x0626, "afii57414"},
+ {0x0627, "afii57415"},
+ {0x0628, "afii57416"},
+ {0x0629, "afii57417"},
+ {0x062a, "afii57418"},
+ {0x062b, "afii57419"},
+ {0x062c, "afii57420"},
+ {0x062d, "afii57421"},
+ {0x062e, "afii57422"},
+ {0x062f, "afii57423"},
+ {0x0630, "afii57424"},
+ {0x0631, "afii57425"},
+ {0x0632, "afii57426"},
+ {0x0633, "afii57427"},
+ {0x0634, "afii57428"},
+ {0x0635, "afii57429"},
+ {0x0636, "afii57430"},
+ {0x0637, "afii57431"},
+ {0x0638, "afii57432"},
+ {0x0639, "afii57433"},
+ {0x063a, "afii57434"},
+ {0x0640, "afii57440"},
+ {0x0641, "afii57441"},
+ {0x0642, "afii57442"},
+ {0x0643, "afii57443"},
+ {0x0644, "afii57444"},
+ {0x0645, "afii57445"},
+ {0x0646, "afii57446"},
+ {0x0648, "afii57448"},
+ {0x0649, "afii57449"},
+ {0x064a, "afii57450"},
+ {0x064b, "afii57451"},
+ {0x064c, "afii57452"},
+ {0x064d, "afii57453"},
+ {0x064e, "afii57454"},
+ {0x064f, "afii57455"},
+ {0x0650, "afii57456"},
+ {0x0651, "afii57457"},
+ {0x0652, "afii57458"},
+ {0x0647, "afii57470"},
+ {0x06a4, "afii57505"},
+ {0x067e, "afii57506"},
+ {0x0686, "afii57507"},
+ {0x0698, "afii57508"},
+ {0x06af, "afii57509"},
+ {0x0679, "afii57511"},
+ {0x0688, "afii57512"},
+ {0x0691, "afii57513"},
+ {0x06ba, "afii57514"},
+ {0x06d2, "afii57519"},
+ {0x06d5, "afii57534"},
+ {0x20aa, "afii57636"},
+ {0x05be, "afii57645"},
+ {0x05c3, "afii57658"},
+ {0x05d0, "afii57664"},
+ {0x05d1, "afii57665"},
+ {0x05d2, "afii57666"},
+ {0x05d3, "afii57667"},
+ {0x05d4, "afii57668"},
+ {0x05d5, "afii57669"},
+ {0x05d6, "afii57670"},
+ {0x05d7, "afii57671"},
+ {0x05d8, "afii57672"},
+ {0x05d9, "afii57673"},
+ {0x05da, "afii57674"},
+ {0x05db, "afii57675"},
+ {0x05dc, "afii57676"},
+ {0x05dd, "afii57677"},
+ {0x05de, "afii57678"},
+ {0x05df, "afii57679"},
+ {0x05e0, "afii57680"},
+ {0x05e1, "afii57681"},
+ {0x05e2, "afii57682"},
+ {0x05e3, "afii57683"},
+ {0x05e4, "afii57684"},
+ {0x05e5, "afii57685"},
+ {0x05e6, "afii57686"},
+ {0x05e7, "afii57687"},
+ {0x05e8, "afii57688"},
+ {0x05e9, "afii57689"},
+ {0x05ea, "afii57690"},
+ {0xfb2a, "afii57694"},
+ {0xfb2b, "afii57695"},
+ {0xfb4b, "afii57700"},
+ {0xfb1f, "afii57705"},
+ {0x05f0, "afii57716"},
+ {0x05f1, "afii57717"},
+ {0x05f2, "afii57718"},
+ {0xfb35, "afii57723"},
+ {0x05b4, "afii57793"},
+ {0x05b5, "afii57794"},
+ {0x05b6, "afii57795"},
+ {0x05bb, "afii57796"},
+ {0x05b8, "afii57797"},
+ {0x05b7, "afii57798"},
+ {0x05b0, "afii57799"},
+ {0x05b2, "afii57800"},
+ {0x05b1, "afii57801"},
+ {0x05b3, "afii57802"},
+ {0x05c2, "afii57803"},
+ {0x05c1, "afii57804"},
+ {0x05b9, "afii57806"},
+ {0x05bc, "afii57807"},
+ {0x05bd, "afii57839"},
+ {0x05bf, "afii57841"},
+ {0x05c0, "afii57842"},
+ {0x02bc, "afii57929"},
+ {0x2105, "afii61248"},
+ {0x2113, "afii61289"},
+ {0x2116, "afii61352"},
+ {0x202c, "afii61573"},
+ {0x202d, "afii61574"},
+ {0x202e, "afii61575"},
+ {0x200c, "afii61664"},
+ {0x066d, "afii63167"},
+ {0x02bd, "afii64937"},
+ {0x00e0, "agrave"},
+ {0x0a85, "agujarati"},
+ {0x0a05, "agurmukhi"},
+ {0x3042, "ahiragana"},
+ {0x1ea3, "ahookabove"},
+ {0x0990, "aibengali"},
+ {0x311e, "aibopomofo"},
+ {0x0910, "aideva"},
+ {0x04d5, "aiecyrillic"},
+ {0x0a90, "aigujarati"},
+ {0x0a10, "aigurmukhi"},
+ {0x0a48, "aimatragurmukhi"},
+ {0x0639, "ainarabic"},
+ {0xfeca, "ainfinalarabic"},
+ {0xfecb, "aininitialarabic"},
+ {0xfecc, "ainmedialarabic"},
+ {0x0203, "ainvertedbreve"},
+ {0x09c8, "aivowelsignbengali"},
+ {0x0948, "aivowelsigndeva"},
+ {0x0ac8, "aivowelsigngujarati"},
+ {0x30a2, "akatakana"},
+ {0xff71, "akatakanahalfwidth"},
+ {0x314f, "akorean"},
+ {0x05d0, "alef"},
+ {0x0627, "alefarabic"},
+ {0xfb30, "alefdageshhebrew"},
+ {0xfe8e, "aleffinalarabic"},
+ {0x0623, "alefhamzaabovearabic"},
+ {0xfe84, "alefhamzaabovefinalarabic"},
+ {0x0625, "alefhamzabelowarabic"},
+ {0xfe88, "alefhamzabelowfinalarabic"},
+ {0x05d0, "alefhebrew"},
+ {0xfb4f, "aleflamedhebrew"},
+ {0x0622, "alefmaddaabovearabic"},
+ {0xfe82, "alefmaddaabovefinalarabic"},
+ {0x0649, "alefmaksuraarabic"},
+ {0xfef0, "alefmaksurafinalarabic"},
+ {0xfef3, "alefmaksurainitialarabic"},
+ {0xfef4, "alefmaksuramedialarabic"},
+ {0xfb2e, "alefpatahhebrew"},
+ {0xfb2f, "alefqamatshebrew"},
+ {0x2135, "aleph"},
+ {0x224c, "allequal"},
+ {0x03b1, "alpha"},
+ {0x03ac, "alphatonos"},
+ {0x0101, "amacron"},
+ {0xff41, "amonospace"},
+ {0x0026, "ampersand"},
+ {0xff06, "ampersandmonospace"},
+ {0xf726, "ampersandsmall"},
+ {0x33c2, "amsquare"},
+ {0x3122, "anbopomofo"},
+ {0x3124, "angbopomofo"},
+ {0x0e5a, "angkhankhuthai"},
+ {0x2220, "angle"},
+ {0x3008, "anglebracketleft"},
+ {0xfe3f, "anglebracketleftvertical"},
+ {0x3009, "anglebracketright"},
+ {0xfe40, "anglebracketrightvertical"},
+ {0x2329, "angleleft"},
+ {0x232a, "angleright"},
+ {0x212b, "angstrom"},
+ {0x0387, "anoteleia"},
+ {0x0952, "anudattadeva"},
+ {0x0982, "anusvarabengali"},
+ {0x0902, "anusvaradeva"},
+ {0x0a82, "anusvaragujarati"},
+ {0x0105, "aogonek"},
+ {0x3300, "apaatosquare"},
+ {0x249c, "aparen"},
+ {0x055a, "apostrophearmenian"},
+ {0x02bc, "apostrophemod"},
+ {0xf8ff, "apple"},
+ {0x2250, "approaches"},
+ {0x2248, "approxequal"},
+ {0x2252, "approxequalorimage"},
+ {0x2245, "approximatelyequal"},
+ {0x318e, "araeaekorean"},
+ {0x318d, "araeakorean"},
+ {0x2312, "arc"},
+ {0x1e9a, "arighthalfring"},
+ {0x00e5, "aring"},
+ {0x01fb, "aringacute"},
+ {0x1e01, "aringbelow"},
+ {0x2194, "arrowboth"},
+ {0x21e3, "arrowdashdown"},
+ {0x21e0, "arrowdashleft"},
+ {0x21e2, "arrowdashright"},
+ {0x21e1, "arrowdashup"},
+ {0x21d4, "arrowdblboth"},
+ {0x21d3, "arrowdbldown"},
+ {0x21d0, "arrowdblleft"},
+ {0x21d2, "arrowdblright"},
+ {0x21d1, "arrowdblup"},
+ {0x2193, "arrowdown"},
+ {0x2199, "arrowdownleft"},
+ {0x2198, "arrowdownright"},
+ {0x21e9, "arrowdownwhite"},
+ {0x02c5, "arrowheaddownmod"},
+ {0x02c2, "arrowheadleftmod"},
+ {0x02c3, "arrowheadrightmod"},
+ {0x02c4, "arrowheadupmod"},
+ {0xf8e7, "arrowhorizex"},
+ {0x2190, "arrowleft"},
+ {0x21d0, "arrowleftdbl"},
+ {0x21cd, "arrowleftdblstroke"},
+ {0x21c6, "arrowleftoverright"},
+ {0x21e6, "arrowleftwhite"},
+ {0x2192, "arrowright"},
+ {0x21cf, "arrowrightdblstroke"},
+ {0x279e, "arrowrightheavy"},
+ {0x21c4, "arrowrightoverleft"},
+ {0x21e8, "arrowrightwhite"},
+ {0x21e4, "arrowtableft"},
+ {0x21e5, "arrowtabright"},
+ {0x2191, "arrowup"},
+ {0x2195, "arrowupdn"},
+ {0x21a8, "arrowupdnbse"},
+ {0x21a8, "arrowupdownbase"},
+ {0x2196, "arrowupleft"},
+ {0x21c5, "arrowupleftofdown"},
+ {0x2197, "arrowupright"},
+ {0x21e7, "arrowupwhite"},
+ {0xf8e6, "arrowvertex"},
+ {0x005e, "asciicircum"},
+ {0xff3e, "asciicircummonospace"},
+ {0x007e, "asciitilde"},
+ {0xff5e, "asciitildemonospace"},
+ {0x0251, "ascript"},
+ {0x0252, "ascriptturned"},
+ {0x3041, "asmallhiragana"},
+ {0x30a1, "asmallkatakana"},
+ {0xff67, "asmallkatakanahalfwidth"},
+ {0x002a, "asterisk"},
+ {0x066d, "asteriskaltonearabic"},
+ {0x066d, "asteriskarabic"},
+ {0x2217, "asteriskmath"},
+ {0xff0a, "asteriskmonospace"},
+ {0xfe61, "asterisksmall"},
+ {0x2042, "asterism"},
+ {0xf6e9, "asuperior"},
+ {0x2243, "asymptoticallyequal"},
+ {0x0040, "at"},
+ {0x00e3, "atilde"},
+ {0xff20, "atmonospace"},
+ {0xfe6b, "atsmall"},
+ {0x0250, "aturned"},
+ {0x0994, "aubengali"},
+ {0x3120, "aubopomofo"},
+ {0x0914, "audeva"},
+ {0x0a94, "augujarati"},
+ {0x0a14, "augurmukhi"},
+ {0x09d7, "aulengthmarkbengali"},
+ {0x0a4c, "aumatragurmukhi"},
+ {0x09cc, "auvowelsignbengali"},
+ {0x094c, "auvowelsigndeva"},
+ {0x0acc, "auvowelsigngujarati"},
+ {0x093d, "avagrahadeva"},
+ {0x0561, "aybarmenian"},
+ {0x05e2, "ayin"},
+ {0xfb20, "ayinaltonehebrew"},
+ {0x05e2, "ayinhebrew"},
+ {0x0062, "b"},
+ {0x09ac, "babengali"},
+ {0x005c, "backslash"},
+ {0xff3c, "backslashmonospace"},
+ {0x092c, "badeva"},
+ {0x0aac, "bagujarati"},
+ {0x0a2c, "bagurmukhi"},
+ {0x3070, "bahiragana"},
+ {0x0e3f, "bahtthai"},
+ {0x30d0, "bakatakana"},
+ {0x007c, "bar"},
+ {0xff5c, "barmonospace"},
+ {0x3105, "bbopomofo"},
+ {0x24d1, "bcircle"},
+ {0x1e03, "bdotaccent"},
+ {0x1e05, "bdotbelow"},
+ {0x266c, "beamedsixteenthnotes"},
+ {0x2235, "because"},
+ {0x0431, "becyrillic"},
+ {0x0628, "beharabic"},
+ {0xfe90, "behfinalarabic"},
+ {0xfe91, "behinitialarabic"},
+ {0x3079, "behiragana"},
+ {0xfe92, "behmedialarabic"},
+ {0xfc9f, "behmeeminitialarabic"},
+ {0xfc08, "behmeemisolatedarabic"},
+ {0xfc6d, "behnoonfinalarabic"},
+ {0x30d9, "bekatakana"},
+ {0x0562, "benarmenian"},
+ {0x05d1, "bet"},
+ {0x03b2, "beta"},
+ {0x03d0, "betasymbolgreek"},
+ {0xfb31, "betdagesh"},
+ {0xfb31, "betdageshhebrew"},
+ {0x05d1, "bethebrew"},
+ {0xfb4c, "betrafehebrew"},
+ {0x09ad, "bhabengali"},
+ {0x092d, "bhadeva"},
+ {0x0aad, "bhagujarati"},
+ {0x0a2d, "bhagurmukhi"},
+ {0x0253, "bhook"},
+ {0x3073, "bihiragana"},
+ {0x30d3, "bikatakana"},
+ {0x0298, "bilabialclick"},
+ {0x0a02, "bindigurmukhi"},
+ {0x3331, "birusquare"},
+ {0x25cf, "blackcircle"},
+ {0x25c6, "blackdiamond"},
+ {0x25bc, "blackdownpointingtriangle"},
+ {0x25c4, "blackleftpointingpointer"},
+ {0x25c0, "blackleftpointingtriangle"},
+ {0x3010, "blacklenticularbracketleft"},
+ {0xfe3b, "blacklenticularbracketleftvertical"},
+ {0x3011, "blacklenticularbracketright"},
+ {0xfe3c, "blacklenticularbracketrightvertical"},
+ {0x25e3, "blacklowerlefttriangle"},
+ {0x25e2, "blacklowerrighttriangle"},
+ {0x25ac, "blackrectangle"},
+ {0x25ba, "blackrightpointingpointer"},
+ {0x25b6, "blackrightpointingtriangle"},
+ {0x25aa, "blacksmallsquare"},
+ {0x263b, "blacksmilingface"},
+ {0x25a0, "blacksquare"},
+ {0x2605, "blackstar"},
+ {0x25e4, "blackupperlefttriangle"},
+ {0x25e5, "blackupperrighttriangle"},
+ {0x25b4, "blackuppointingsmalltriangle"},
+ {0x25b2, "blackuppointingtriangle"},
+ {0x2423, "blank"},
+ {0x1e07, "blinebelow"},
+ {0x2588, "block"},
+ {0xff42, "bmonospace"},
+ {0x0e1a, "bobaimaithai"},
+ {0x307c, "bohiragana"},
+ {0x30dc, "bokatakana"},
+ {0x249d, "bparen"},
+ {0x33c3, "bqsquare"},
+ {0xf8f4, "braceex"},
+ {0x007b, "braceleft"},
+ {0xf8f3, "braceleftbt"},
+ {0xf8f2, "braceleftmid"},
+ {0xff5b, "braceleftmonospace"},
+ {0xfe5b, "braceleftsmall"},
+ {0xf8f1, "bracelefttp"},
+ {0xfe37, "braceleftvertical"},
+ {0x007d, "braceright"},
+ {0xf8fe, "bracerightbt"},
+ {0xf8fd, "bracerightmid"},
+ {0xff5d, "bracerightmonospace"},
+ {0xfe5c, "bracerightsmall"},
+ {0xf8fc, "bracerighttp"},
+ {0xfe38, "bracerightvertical"},
+ {0x005b, "bracketleft"},
+ {0xf8f0, "bracketleftbt"},
+ {0xf8ef, "bracketleftex"},
+ {0xff3b, "bracketleftmonospace"},
+ {0xf8ee, "bracketlefttp"},
+ {0x005d, "bracketright"},
+ {0xf8fb, "bracketrightbt"},
+ {0xf8fa, "bracketrightex"},
+ {0xff3d, "bracketrightmonospace"},
+ {0xf8f9, "bracketrighttp"},
+ {0x02d8, "breve"},
+ {0x032e, "brevebelowcmb"},
+ {0x0306, "brevecmb"},
+ {0x032f, "breveinvertedbelowcmb"},
+ {0x0311, "breveinvertedcmb"},
+ {0x0361, "breveinverteddoublecmb"},
+ {0x032a, "bridgebelowcmb"},
+ {0x033a, "bridgeinvertedbelowcmb"},
+ {0x00a6, "brokenbar"},
+ {0x0180, "bstroke"},
+ {0xf6ea, "bsuperior"},
+ {0x0183, "btopbar"},
+ {0x3076, "buhiragana"},
+ {0x30d6, "bukatakana"},
+ {0x2022, "bullet"},
+ {0x25d8, "bulletinverse"},
+ {0x2219, "bulletoperator"},
+ {0x25ce, "bullseye"},
+ {0x0063, "c"},
+ {0x056e, "caarmenian"},
+ {0x099a, "cabengali"},
+ {0x0107, "cacute"},
+ {0x091a, "cadeva"},
+ {0x0a9a, "cagujarati"},
+ {0x0a1a, "cagurmukhi"},
+ {0x3388, "calsquare"},
+ {0x0981, "candrabindubengali"},
+ {0x0310, "candrabinducmb"},
+ {0x0901, "candrabindudeva"},
+ {0x0a81, "candrabindugujarati"},
+ {0x21ea, "capslock"},
+ {0x2105, "careof"},
+ {0x02c7, "caron"},
+ {0x032c, "caronbelowcmb"},
+ {0x030c, "caroncmb"},
+ {0x21b5, "carriagereturn"},
+ {0x3118, "cbopomofo"},
+ {0x010d, "ccaron"},
+ {0x00e7, "ccedilla"},
+ {0x1e09, "ccedillaacute"},
+ {0x24d2, "ccircle"},
+ {0x0109, "ccircumflex"},
+ {0x0255, "ccurl"},
+ {0x010b, "cdot"},
+ {0x010b, "cdotaccent"},
+ {0x33c5, "cdsquare"},
+ {0x00b8, "cedilla"},
+ {0x0327, "cedillacmb"},
+ {0x00a2, "cent"},
+ {0x2103, "centigrade"},
+ {0xf6df, "centinferior"},
+ {0xffe0, "centmonospace"},
+ {0xf7a2, "centoldstyle"},
+ {0xf6e0, "centsuperior"},
+ {0x0579, "chaarmenian"},
+ {0x099b, "chabengali"},
+ {0x091b, "chadeva"},
+ {0x0a9b, "chagujarati"},
+ {0x0a1b, "chagurmukhi"},
+ {0x3114, "chbopomofo"},
+ {0x04bd, "cheabkhasiancyrillic"},
+ {0x2713, "checkmark"},
+ {0x0447, "checyrillic"},
+ {0x04bf, "chedescenderabkhasiancyrillic"},
+ {0x04b7, "chedescendercyrillic"},
+ {0x04f5, "chedieresiscyrillic"},
+ {0x0573, "cheharmenian"},
+ {0x04cc, "chekhakassiancyrillic"},
+ {0x04b9, "cheverticalstrokecyrillic"},
+ {0x03c7, "chi"},
+ {0x3277, "chieuchacirclekorean"},
+ {0x3217, "chieuchaparenkorean"},
+ {0x3269, "chieuchcirclekorean"},
+ {0x314a, "chieuchkorean"},
+ {0x3209, "chieuchparenkorean"},
+ {0x0e0a, "chochangthai"},
+ {0x0e08, "chochanthai"},
+ {0x0e09, "chochingthai"},
+ {0x0e0c, "chochoethai"},
+ {0x0188, "chook"},
+ {0x3276, "cieucacirclekorean"},
+ {0x3216, "cieucaparenkorean"},
+ {0x3268, "cieuccirclekorean"},
+ {0x3148, "cieuckorean"},
+ {0x3208, "cieucparenkorean"},
+ {0x321c, "cieucuparenkorean"},
+ {0x25cb, "circle"},
+ {0x2297, "circlemultiply"},
+ {0x2299, "circleot"},
+ {0x2295, "circleplus"},
+ {0x3036, "circlepostalmark"},
+ {0x25d0, "circlewithlefthalfblack"},
+ {0x25d1, "circlewithrighthalfblack"},
+ {0x02c6, "circumflex"},
+ {0x032d, "circumflexbelowcmb"},
+ {0x0302, "circumflexcmb"},
+ {0x2327, "clear"},
+ {0x01c2, "clickalveolar"},
+ {0x01c0, "clickdental"},
+ {0x01c1, "clicklateral"},
+ {0x01c3, "clickretroflex"},
+ {0x2663, "club"},
+ {0x2663, "clubsuitblack"},
+ {0x2667, "clubsuitwhite"},
+ {0x33a4, "cmcubedsquare"},
+ {0xff43, "cmonospace"},
+ {0x33a0, "cmsquaredsquare"},
+ {0x0581, "coarmenian"},
+ {0x003a, "colon"},
+ {0x20a1, "colonmonetary"},
+ {0xff1a, "colonmonospace"},
+ {0x20a1, "colonsign"},
+ {0xfe55, "colonsmall"},
+ {0x02d1, "colontriangularhalfmod"},
+ {0x02d0, "colontriangularmod"},
+ {0x002c, "comma"},
+ {0x0313, "commaabovecmb"},
+ {0x0315, "commaaboverightcmb"},
+ {0xf6c3, "commaaccent"},
+ {0x060c, "commaarabic"},
+ {0x055d, "commaarmenian"},
+ {0xf6e1, "commainferior"},
+ {0xff0c, "commamonospace"},
+ {0x0314, "commareversedabovecmb"},
+ {0x02bd, "commareversedmod"},
+ {0xfe50, "commasmall"},
+ {0xf6e2, "commasuperior"},
+ {0x0312, "commaturnedabovecmb"},
+ {0x02bb, "commaturnedmod"},
+ {0x263c, "compass"},
+ {0x2245, "congruent"},
+ {0x222e, "contourintegral"},
+ {0x2303, "control"},
+ {0x0006, "controlACK"},
+ {0x0007, "controlBEL"},
+ {0x0008, "controlBS"},
+ {0x0018, "controlCAN"},
+ {0x000d, "controlCR"},
+ {0x0011, "controlDC1"},
+ {0x0012, "controlDC2"},
+ {0x0013, "controlDC3"},
+ {0x0014, "controlDC4"},
+ {0x007f, "controlDEL"},
+ {0x0010, "controlDLE"},
+ {0x0019, "controlEM"},
+ {0x0005, "controlENQ"},
+ {0x0004, "controlEOT"},
+ {0x001b, "controlESC"},
+ {0x0017, "controlETB"},
+ {0x0003, "controlETX"},
+ {0x000c, "controlFF"},
+ {0x001c, "controlFS"},
+ {0x001d, "controlGS"},
+ {0x0009, "controlHT"},
+ {0x000a, "controlLF"},
+ {0x0015, "controlNAK"},
+ {0x001e, "controlRS"},
+ {0x000f, "controlSI"},
+ {0x000e, "controlSO"},
+ {0x0002, "controlSOT"},
+ {0x0001, "controlSTX"},
+ {0x001a, "controlSUB"},
+ {0x0016, "controlSYN"},
+ {0x001f, "controlUS"},
+ {0x000b, "controlVT"},
+ {0x00a9, "copyright"},
+ {0xf8e9, "copyrightsans"},
+ {0xf6d9, "copyrightserif"},
+ {0x300c, "cornerbracketleft"},
+ {0xff62, "cornerbracketlefthalfwidth"},
+ {0xfe41, "cornerbracketleftvertical"},
+ {0x300d, "cornerbracketright"},
+ {0xff63, "cornerbracketrighthalfwidth"},
+ {0xfe42, "cornerbracketrightvertical"},
+ {0x337f, "corporationsquare"},
+ {0x33c7, "cosquare"},
+ {0x33c6, "coverkgsquare"},
+ {0x249e, "cparen"},
+ {0x20a2, "cruzeiro"},
+ {0x0297, "cstretched"},
+ {0x22cf, "curlyand"},
+ {0x22ce, "curlyor"},
+ {0x00a4, "currency"},
+ {0xf6d1, "cyrBreve"},
+ {0xf6d2, "cyrFlex"},
+ {0xf6d4, "cyrbreve"},
+ {0xf6d5, "cyrflex"},
+ {0x0064, "d"},
+ {0x0564, "daarmenian"},
+ {0x09a6, "dabengali"},
+ {0x0636, "dadarabic"},
+ {0x0926, "dadeva"},
+ {0xfebe, "dadfinalarabic"},
+ {0xfebf, "dadinitialarabic"},
+ {0xfec0, "dadmedialarabic"},
+ {0x05bc, "dagesh"},
+ {0x05bc, "dageshhebrew"},
+ {0x2020, "dagger"},
+ {0x2021, "daggerdbl"},
+ {0x0aa6, "dagujarati"},
+ {0x0a26, "dagurmukhi"},
+ {0x3060, "dahiragana"},
+ {0x30c0, "dakatakana"},
+ {0x062f, "dalarabic"},
+ {0x05d3, "dalet"},
+ {0xfb33, "daletdagesh"},
+ {0xfb33, "daletdageshhebrew"},
+ {0x05d3, "dalethebrew"},
+ {0xfeaa, "dalfinalarabic"},
+ {0x064f, "dammaarabic"},
+ {0x064f, "dammalowarabic"},
+ {0x064c, "dammatanaltonearabic"},
+ {0x064c, "dammatanarabic"},
+ {0x0964, "danda"},
+ {0x05a7, "dargahebrew"},
+ {0x05a7, "dargalefthebrew"},
+ {0x0485, "dasiapneumatacyrilliccmb"},
+ {0xf6d3, "dblGrave"},
+ {0x300a, "dblanglebracketleft"},
+ {0xfe3d, "dblanglebracketleftvertical"},
+ {0x300b, "dblanglebracketright"},
+ {0xfe3e, "dblanglebracketrightvertical"},
+ {0x032b, "dblarchinvertedbelowcmb"},
+ {0x21d4, "dblarrowleft"},
+ {0x21d2, "dblarrowright"},
+ {0x0965, "dbldanda"},
+ {0xf6d6, "dblgrave"},
+ {0x030f, "dblgravecmb"},
+ {0x222c, "dblintegral"},
+ {0x2017, "dbllowline"},
+ {0x0333, "dbllowlinecmb"},
+ {0x033f, "dbloverlinecmb"},
+ {0x02ba, "dblprimemod"},
+ {0x2016, "dblverticalbar"},
+ {0x030e, "dblverticallineabovecmb"},
+ {0x3109, "dbopomofo"},
+ {0x33c8, "dbsquare"},
+ {0x010f, "dcaron"},
+ {0x1e11, "dcedilla"},
+ {0x24d3, "dcircle"},
+ {0x1e13, "dcircumflexbelow"},
+ {0x0111, "dcroat"},
+ {0x09a1, "ddabengali"},
+ {0x0921, "ddadeva"},
+ {0x0aa1, "ddagujarati"},
+ {0x0a21, "ddagurmukhi"},
+ {0x0688, "ddalarabic"},
+ {0xfb89, "ddalfinalarabic"},
+ {0x095c, "dddhadeva"},
+ {0x09a2, "ddhabengali"},
+ {0x0922, "ddhadeva"},
+ {0x0aa2, "ddhagujarati"},
+ {0x0a22, "ddhagurmukhi"},
+ {0x1e0b, "ddotaccent"},
+ {0x1e0d, "ddotbelow"},
+ {0x066b, "decimalseparatorarabic"},
+ {0x066b, "decimalseparatorpersian"},
+ {0x0434, "decyrillic"},
+ {0x00b0, "degree"},
+ {0x05ad, "dehihebrew"},
+ {0x3067, "dehiragana"},
+ {0x03ef, "deicoptic"},
+ {0x30c7, "dekatakana"},
+ {0x232b, "deleteleft"},
+ {0x2326, "deleteright"},
+ {0x03b4, "delta"},
+ {0x018d, "deltaturned"},
+ {0x09f8, "denominatorminusonenumeratorbengali"},
+ {0x02a4, "dezh"},
+ {0x09a7, "dhabengali"},
+ {0x0927, "dhadeva"},
+ {0x0aa7, "dhagujarati"},
+ {0x0a27, "dhagurmukhi"},
+ {0x0257, "dhook"},
+ {0x0385, "dialytikatonos"},
+ {0x0344, "dialytikatonoscmb"},
+ {0x2666, "diamond"},
+ {0x2662, "diamondsuitwhite"},
+ {0x00a8, "dieresis"},
+ {0xf6d7, "dieresisacute"},
+ {0x0324, "dieresisbelowcmb"},
+ {0x0308, "dieresiscmb"},
+ {0xf6d8, "dieresisgrave"},
+ {0x0385, "dieresistonos"},
+ {0x3062, "dihiragana"},
+ {0x30c2, "dikatakana"},
+ {0x3003, "dittomark"},
+ {0x00f7, "divide"},
+ {0x2223, "divides"},
+ {0x2215, "divisionslash"},
+ {0x0452, "djecyrillic"},
+ {0x2593, "dkshade"},
+ {0x1e0f, "dlinebelow"},
+ {0x3397, "dlsquare"},
+ {0x0111, "dmacron"},
+ {0xff44, "dmonospace"},
+ {0x2584, "dnblock"},
+ {0x0e0e, "dochadathai"},
+ {0x0e14, "dodekthai"},
+ {0x3069, "dohiragana"},
+ {0x30c9, "dokatakana"},
+ {0x0024, "dollar"},
+ {0xf6e3, "dollarinferior"},
+ {0xff04, "dollarmonospace"},
+ {0xf724, "dollaroldstyle"},
+ {0xfe69, "dollarsmall"},
+ {0xf6e4, "dollarsuperior"},
+ {0x20ab, "dong"},
+ {0x3326, "dorusquare"},
+ {0x02d9, "dotaccent"},
+ {0x0307, "dotaccentcmb"},
+ {0x0323, "dotbelowcmb"},
+ {0x0323, "dotbelowcomb"},
+ {0x30fb, "dotkatakana"},
+ {0x0131, "dotlessi"},
+ {0xf6be, "dotlessj"},
+ {0x0284, "dotlessjstrokehook"},
+ {0x22c5, "dotmath"},
+ {0x25cc, "dottedcircle"},
+ {0xfb1f, "doubleyodpatah"},
+ {0xfb1f, "doubleyodpatahhebrew"},
+ {0x031e, "downtackbelowcmb"},
+ {0x02d5, "downtackmod"},
+ {0x249f, "dparen"},
+ {0xf6eb, "dsuperior"},
+ {0x0256, "dtail"},
+ {0x018c, "dtopbar"},
+ {0x3065, "duhiragana"},
+ {0x30c5, "dukatakana"},
+ {0x01f3, "dz"},
+ {0x02a3, "dzaltone"},
+ {0x01c6, "dzcaron"},
+ {0x02a5, "dzcurl"},
+ {0x04e1, "dzeabkhasiancyrillic"},
+ {0x0455, "dzecyrillic"},
+ {0x045f, "dzhecyrillic"},
+ {0x0065, "e"},
+ {0x00e9, "eacute"},
+ {0x2641, "earth"},
+ {0x098f, "ebengali"},
+ {0x311c, "ebopomofo"},
+ {0x0115, "ebreve"},
+ {0x090d, "ecandradeva"},
+ {0x0a8d, "ecandragujarati"},
+ {0x0945, "ecandravowelsigndeva"},
+ {0x0ac5, "ecandravowelsigngujarati"},
+ {0x011b, "ecaron"},
+ {0x1e1d, "ecedillabreve"},
+ {0x0565, "echarmenian"},
+ {0x0587, "echyiwnarmenian"},
+ {0x24d4, "ecircle"},
+ {0x00ea, "ecircumflex"},
+ {0x1ebf, "ecircumflexacute"},
+ {0x1e19, "ecircumflexbelow"},
+ {0x1ec7, "ecircumflexdotbelow"},
+ {0x1ec1, "ecircumflexgrave"},
+ {0x1ec3, "ecircumflexhookabove"},
+ {0x1ec5, "ecircumflextilde"},
+ {0x0454, "ecyrillic"},
+ {0x0205, "edblgrave"},
+ {0x090f, "edeva"},
+ {0x00eb, "edieresis"},
+ {0x0117, "edot"},
+ {0x0117, "edotaccent"},
+ {0x1eb9, "edotbelow"},
+ {0x0a0f, "eegurmukhi"},
+ {0x0a47, "eematragurmukhi"},
+ {0x0444, "efcyrillic"},
+ {0x00e8, "egrave"},
+ {0x0a8f, "egujarati"},
+ {0x0567, "eharmenian"},
+ {0x311d, "ehbopomofo"},
+ {0x3048, "ehiragana"},
+ {0x1ebb, "ehookabove"},
+ {0x311f, "eibopomofo"},
+ {0x0038, "eight"},
+ {0x0668, "eightarabic"},
+ {0x09ee, "eightbengali"},
+ {0x2467, "eightcircle"},
+ {0x2791, "eightcircleinversesansserif"},
+ {0x096e, "eightdeva"},
+ {0x2471, "eighteencircle"},
+ {0x2485, "eighteenparen"},
+ {0x2499, "eighteenperiod"},
+ {0x0aee, "eightgujarati"},
+ {0x0a6e, "eightgurmukhi"},
+ {0x0668, "eighthackarabic"},
+ {0x3028, "eighthangzhou"},
+ {0x266b, "eighthnotebeamed"},
+ {0x3227, "eightideographicparen"},
+ {0x2088, "eightinferior"},
+ {0xff18, "eightmonospace"},
+ {0xf738, "eightoldstyle"},
+ {0x247b, "eightparen"},
+ {0x248f, "eightperiod"},
+ {0x06f8, "eightpersian"},
+ {0x2177, "eightroman"},
+ {0x2078, "eightsuperior"},
+ {0x0e58, "eightthai"},
+ {0x0207, "einvertedbreve"},
+ {0x0465, "eiotifiedcyrillic"},
+ {0x30a8, "ekatakana"},
+ {0xff74, "ekatakanahalfwidth"},
+ {0x0a74, "ekonkargurmukhi"},
+ {0x3154, "ekorean"},
+ {0x043b, "elcyrillic"},
+ {0x2208, "element"},
+ {0x246a, "elevencircle"},
+ {0x247e, "elevenparen"},
+ {0x2492, "elevenperiod"},
+ {0x217a, "elevenroman"},
+ {0x2026, "ellipsis"},
+ {0x22ee, "ellipsisvertical"},
+ {0x0113, "emacron"},
+ {0x1e17, "emacronacute"},
+ {0x1e15, "emacrongrave"},
+ {0x043c, "emcyrillic"},
+ {0x2014, "emdash"},
+ {0xfe31, "emdashvertical"},
+ {0xff45, "emonospace"},
+ {0x055b, "emphasismarkarmenian"},
+ {0x2205, "emptyset"},
+ {0x3123, "enbopomofo"},
+ {0x043d, "encyrillic"},
+ {0x2013, "endash"},
+ {0xfe32, "endashvertical"},
+ {0x04a3, "endescendercyrillic"},
+ {0x014b, "eng"},
+ {0x3125, "engbopomofo"},
+ {0x04a5, "enghecyrillic"},
+ {0x04c8, "enhookcyrillic"},
+ {0x2002, "enspace"},
+ {0x0119, "eogonek"},
+ {0x3153, "eokorean"},
+ {0x025b, "eopen"},
+ {0x029a, "eopenclosed"},
+ {0x025c, "eopenreversed"},
+ {0x025e, "eopenreversedclosed"},
+ {0x025d, "eopenreversedhook"},
+ {0x24a0, "eparen"},
+ {0x03b5, "epsilon"},
+ {0x03ad, "epsilontonos"},
+ {0x003d, "equal"},
+ {0xff1d, "equalmonospace"},
+ {0xfe66, "equalsmall"},
+ {0x207c, "equalsuperior"},
+ {0x2261, "equivalence"},
+ {0x3126, "erbopomofo"},
+ {0x0440, "ercyrillic"},
+ {0x0258, "ereversed"},
+ {0x044d, "ereversedcyrillic"},
+ {0x0441, "escyrillic"},
+ {0x04ab, "esdescendercyrillic"},
+ {0x0283, "esh"},
+ {0x0286, "eshcurl"},
+ {0x090e, "eshortdeva"},
+ {0x0946, "eshortvowelsigndeva"},
+ {0x01aa, "eshreversedloop"},
+ {0x0285, "eshsquatreversed"},
+ {0x3047, "esmallhiragana"},
+ {0x30a7, "esmallkatakana"},
+ {0xff6a, "esmallkatakanahalfwidth"},
+ {0x212e, "estimated"},
+ {0xf6ec, "esuperior"},
+ {0x03b7, "eta"},
+ {0x0568, "etarmenian"},
+ {0x03ae, "etatonos"},
+ {0x00f0, "eth"},
+ {0x1ebd, "etilde"},
+ {0x1e1b, "etildebelow"},
+ {0x0591, "etnahtafoukhhebrew"},
+ {0x0591, "etnahtafoukhlefthebrew"},
+ {0x0591, "etnahtahebrew"},
+ {0x0591, "etnahtalefthebrew"},
+ {0x01dd, "eturned"},
+ {0x3161, "eukorean"},
+ {0x20ac, "euro"},
+ {0x09c7, "evowelsignbengali"},
+ {0x0947, "evowelsigndeva"},
+ {0x0ac7, "evowelsigngujarati"},
+ {0x0021, "exclam"},
+ {0x055c, "exclamarmenian"},
+ {0x203c, "exclamdbl"},
+ {0x00a1, "exclamdown"},
+ {0xf7a1, "exclamdownsmall"},
+ {0x0021, "exclamleft"},
+ {0xff01, "exclammonospace"},
+ {0xf721, "exclamsmall"},
+ {0x2203, "existential"},
+ {0x0292, "ezh"},
+ {0x01ef, "ezhcaron"},
+ {0x0293, "ezhcurl"},
+ {0x01b9, "ezhreversed"},
+ {0x01ba, "ezhtail"},
+ {0x0066, "f"},
+ {0x095e, "fadeva"},
+ {0x0a5e, "fagurmukhi"},
+ {0x2109, "fahrenheit"},
+ {0x064e, "fathaarabic"},
+ {0x064e, "fathalowarabic"},
+ {0x064b, "fathatanarabic"},
+ {0x3108, "fbopomofo"},
+ {0x24d5, "fcircle"},
+ {0x1e1f, "fdotaccent"},
+ {0x0641, "feharabic"},
+ {0x0586, "feharmenian"},
+ {0xfed2, "fehfinalarabic"},
+ {0xfed3, "fehinitialarabic"},
+ {0xfed4, "fehmedialarabic"},
+ {0x03e5, "feicoptic"},
+ {0x2640, "female"},
+ {0xfb00, "ff"},
+ {0xfb03, "ffi"},
+ {0xfb04, "ffl"},
+ {0xfb01, "fi"},
+ {0x246e, "fifteencircle"},
+ {0x2482, "fifteenparen"},
+ {0x2496, "fifteenperiod"},
+ {0x2012, "figuredash"},
+ {0x25a0, "filledbox"},
+ {0x25ac, "filledrect"},
+ {0x05da, "finalkaf"},
+ {0xfb3a, "finalkafdagesh"},
+ {0xfb3a, "finalkafdageshhebrew"},
+ {0x05da, "finalkafhebrew"},
+ {0x05dd, "finalmem"},
+ {0x05dd, "finalmemhebrew"},
+ {0x05df, "finalnun"},
+ {0x05df, "finalnunhebrew"},
+ {0x05e3, "finalpe"},
+ {0x05e3, "finalpehebrew"},
+ {0x05e5, "finaltsadi"},
+ {0x05e5, "finaltsadihebrew"},
+ {0x02c9, "firsttonechinese"},
+ {0x25c9, "fisheye"},
+ {0x0473, "fitacyrillic"},
+ {0x0035, "five"},
+ {0x0665, "fivearabic"},
+ {0x09eb, "fivebengali"},
+ {0x2464, "fivecircle"},
+ {0x278e, "fivecircleinversesansserif"},
+ {0x096b, "fivedeva"},
+ {0x215d, "fiveeighths"},
+ {0x0aeb, "fivegujarati"},
+ {0x0a6b, "fivegurmukhi"},
+ {0x0665, "fivehackarabic"},
+ {0x3025, "fivehangzhou"},
+ {0x3224, "fiveideographicparen"},
+ {0x2085, "fiveinferior"},
+ {0xff15, "fivemonospace"},
+ {0xf735, "fiveoldstyle"},
+ {0x2478, "fiveparen"},
+ {0x248c, "fiveperiod"},
+ {0x06f5, "fivepersian"},
+ {0x2174, "fiveroman"},
+ {0x2075, "fivesuperior"},
+ {0x0e55, "fivethai"},
+ {0xfb02, "fl"},
+ {0x0192, "florin"},
+ {0xff46, "fmonospace"},
+ {0x3399, "fmsquare"},
+ {0x0e1f, "fofanthai"},
+ {0x0e1d, "fofathai"},
+ {0x0e4f, "fongmanthai"},
+ {0x2200, "forall"},
+ {0x0034, "four"},
+ {0x0664, "fourarabic"},
+ {0x09ea, "fourbengali"},
+ {0x2463, "fourcircle"},
+ {0x278d, "fourcircleinversesansserif"},
+ {0x096a, "fourdeva"},
+ {0x0aea, "fourgujarati"},
+ {0x0a6a, "fourgurmukhi"},
+ {0x0664, "fourhackarabic"},
+ {0x3024, "fourhangzhou"},
+ {0x3223, "fourideographicparen"},
+ {0x2084, "fourinferior"},
+ {0xff14, "fourmonospace"},
+ {0x09f7, "fournumeratorbengali"},
+ {0xf734, "fouroldstyle"},
+ {0x2477, "fourparen"},
+ {0x248b, "fourperiod"},
+ {0x06f4, "fourpersian"},
+ {0x2173, "fourroman"},
+ {0x2074, "foursuperior"},
+ {0x246d, "fourteencircle"},
+ {0x2481, "fourteenparen"},
+ {0x2495, "fourteenperiod"},
+ {0x0e54, "fourthai"},
+ {0x02cb, "fourthtonechinese"},
+ {0x24a1, "fparen"},
+ {0x2044, "fraction"},
+ {0x20a3, "franc"},
+ {0x0067, "g"},
+ {0x0997, "gabengali"},
+ {0x01f5, "gacute"},
+ {0x0917, "gadeva"},
+ {0x06af, "gafarabic"},
+ {0xfb93, "gaffinalarabic"},
+ {0xfb94, "gafinitialarabic"},
+ {0xfb95, "gafmedialarabic"},
+ {0x0a97, "gagujarati"},
+ {0x0a17, "gagurmukhi"},
+ {0x304c, "gahiragana"},
+ {0x30ac, "gakatakana"},
+ {0x03b3, "gamma"},
+ {0x0263, "gammalatinsmall"},
+ {0x02e0, "gammasuperior"},
+ {0x03eb, "gangiacoptic"},
+ {0x310d, "gbopomofo"},
+ {0x011f, "gbreve"},
+ {0x01e7, "gcaron"},
+ {0x0123, "gcedilla"},
+ {0x24d6, "gcircle"},
+ {0x011d, "gcircumflex"},
+ {0x0123, "gcommaaccent"},
+ {0x0121, "gdot"},
+ {0x0121, "gdotaccent"},
+ {0x0433, "gecyrillic"},
+ {0x3052, "gehiragana"},
+ {0x30b2, "gekatakana"},
+ {0x2251, "geometricallyequal"},
+ {0x059c, "gereshaccenthebrew"},
+ {0x05f3, "gereshhebrew"},
+ {0x059d, "gereshmuqdamhebrew"},
+ {0x00df, "germandbls"},
+ {0x059e, "gershayimaccenthebrew"},
+ {0x05f4, "gershayimhebrew"},
+ {0x3013, "getamark"},
+ {0x0998, "ghabengali"},
+ {0x0572, "ghadarmenian"},
+ {0x0918, "ghadeva"},
+ {0x0a98, "ghagujarati"},
+ {0x0a18, "ghagurmukhi"},
+ {0x063a, "ghainarabic"},
+ {0xfece, "ghainfinalarabic"},
+ {0xfecf, "ghaininitialarabic"},
+ {0xfed0, "ghainmedialarabic"},
+ {0x0495, "ghemiddlehookcyrillic"},
+ {0x0493, "ghestrokecyrillic"},
+ {0x0491, "gheupturncyrillic"},
+ {0x095a, "ghhadeva"},
+ {0x0a5a, "ghhagurmukhi"},
+ {0x0260, "ghook"},
+ {0x3393, "ghzsquare"},
+ {0x304e, "gihiragana"},
+ {0x30ae, "gikatakana"},
+ {0x0563, "gimarmenian"},
+ {0x05d2, "gimel"},
+ {0xfb32, "gimeldagesh"},
+ {0xfb32, "gimeldageshhebrew"},
+ {0x05d2, "gimelhebrew"},
+ {0x0453, "gjecyrillic"},
+ {0x01be, "glottalinvertedstroke"},
+ {0x0294, "glottalstop"},
+ {0x0296, "glottalstopinverted"},
+ {0x02c0, "glottalstopmod"},
+ {0x0295, "glottalstopreversed"},
+ {0x02c1, "glottalstopreversedmod"},
+ {0x02e4, "glottalstopreversedsuperior"},
+ {0x02a1, "glottalstopstroke"},
+ {0x02a2, "glottalstopstrokereversed"},
+ {0x1e21, "gmacron"},
+ {0xff47, "gmonospace"},
+ {0x3054, "gohiragana"},
+ {0x30b4, "gokatakana"},
+ {0x24a2, "gparen"},
+ {0x33ac, "gpasquare"},
+ {0x2207, "gradient"},
+ {0x0060, "grave"},
+ {0x0316, "gravebelowcmb"},
+ {0x0300, "gravecmb"},
+ {0x0300, "gravecomb"},
+ {0x0953, "gravedeva"},
+ {0x02ce, "gravelowmod"},
+ {0xff40, "gravemonospace"},
+ {0x0340, "gravetonecmb"},
+ {0x003e, "greater"},
+ {0x2265, "greaterequal"},
+ {0x22db, "greaterequalorless"},
+ {0xff1e, "greatermonospace"},
+ {0x2273, "greaterorequivalent"},
+ {0x2277, "greaterorless"},
+ {0x2267, "greateroverequal"},
+ {0xfe65, "greatersmall"},
+ {0x0261, "gscript"},
+ {0x01e5, "gstroke"},
+ {0x3050, "guhiragana"},
+ {0x00ab, "guillemotleft"},
+ {0x00bb, "guillemotright"},
+ {0x2039, "guilsinglleft"},
+ {0x203a, "guilsinglright"},
+ {0x30b0, "gukatakana"},
+ {0x3318, "guramusquare"},
+ {0x33c9, "gysquare"},
+ {0x0068, "h"},
+ {0x04a9, "haabkhasiancyrillic"},
+ {0x06c1, "haaltonearabic"},
+ {0x09b9, "habengali"},
+ {0x04b3, "hadescendercyrillic"},
+ {0x0939, "hadeva"},
+ {0x0ab9, "hagujarati"},
+ {0x0a39, "hagurmukhi"},
+ {0x062d, "haharabic"},
+ {0xfea2, "hahfinalarabic"},
+ {0xfea3, "hahinitialarabic"},
+ {0x306f, "hahiragana"},
+ {0xfea4, "hahmedialarabic"},
+ {0x332a, "haitusquare"},
+ {0x30cf, "hakatakana"},
+ {0xff8a, "hakatakanahalfwidth"},
+ {0x0a4d, "halantgurmukhi"},
+ {0x0621, "hamzaarabic"},
+ {0x0621, "hamzalowarabic"},
+ {0x3164, "hangulfiller"},
+ {0x044a, "hardsigncyrillic"},
+ {0x21bc, "harpoonleftbarbup"},
+ {0x21c0, "harpoonrightbarbup"},
+ {0x33ca, "hasquare"},
+ {0x05b2, "hatafpatah"},
+ {0x05b2, "hatafpatah16"},
+ {0x05b2, "hatafpatah23"},
+ {0x05b2, "hatafpatah2f"},
+ {0x05b2, "hatafpatahhebrew"},
+ {0x05b2, "hatafpatahnarrowhebrew"},
+ {0x05b2, "hatafpatahquarterhebrew"},
+ {0x05b2, "hatafpatahwidehebrew"},
+ {0x05b3, "hatafqamats"},
+ {0x05b3, "hatafqamats1b"},
+ {0x05b3, "hatafqamats28"},
+ {0x05b3, "hatafqamats34"},
+ {0x05b3, "hatafqamatshebrew"},
+ {0x05b3, "hatafqamatsnarrowhebrew"},
+ {0x05b3, "hatafqamatsquarterhebrew"},
+ {0x05b3, "hatafqamatswidehebrew"},
+ {0x05b1, "hatafsegol"},
+ {0x05b1, "hatafsegol17"},
+ {0x05b1, "hatafsegol24"},
+ {0x05b1, "hatafsegol30"},
+ {0x05b1, "hatafsegolhebrew"},
+ {0x05b1, "hatafsegolnarrowhebrew"},
+ {0x05b1, "hatafsegolquarterhebrew"},
+ {0x05b1, "hatafsegolwidehebrew"},
+ {0x0127, "hbar"},
+ {0x310f, "hbopomofo"},
+ {0x1e2b, "hbrevebelow"},
+ {0x1e29, "hcedilla"},
+ {0x24d7, "hcircle"},
+ {0x0125, "hcircumflex"},
+ {0x1e27, "hdieresis"},
+ {0x1e23, "hdotaccent"},
+ {0x1e25, "hdotbelow"},
+ {0x05d4, "he"},
+ {0x2665, "heart"},
+ {0x2665, "heartsuitblack"},
+ {0x2661, "heartsuitwhite"},
+ {0xfb34, "hedagesh"},
+ {0xfb34, "hedageshhebrew"},
+ {0x06c1, "hehaltonearabic"},
+ {0x0647, "heharabic"},
+ {0x05d4, "hehebrew"},
+ {0xfba7, "hehfinalaltonearabic"},
+ {0xfeea, "hehfinalalttwoarabic"},
+ {0xfeea, "hehfinalarabic"},
+ {0xfba5, "hehhamzaabovefinalarabic"},
+ {0xfba4, "hehhamzaaboveisolatedarabic"},
+ {0xfba8, "hehinitialaltonearabic"},
+ {0xfeeb, "hehinitialarabic"},
+ {0x3078, "hehiragana"},
+ {0xfba9, "hehmedialaltonearabic"},
+ {0xfeec, "hehmedialarabic"},
+ {0x337b, "heiseierasquare"},
+ {0x30d8, "hekatakana"},
+ {0xff8d, "hekatakanahalfwidth"},
+ {0x3336, "hekutaarusquare"},
+ {0x0267, "henghook"},
+ {0x3339, "herutusquare"},
+ {0x05d7, "het"},
+ {0x05d7, "hethebrew"},
+ {0x0266, "hhook"},
+ {0x02b1, "hhooksuperior"},
+ {0x327b, "hieuhacirclekorean"},
+ {0x321b, "hieuhaparenkorean"},
+ {0x326d, "hieuhcirclekorean"},
+ {0x314e, "hieuhkorean"},
+ {0x320d, "hieuhparenkorean"},
+ {0x3072, "hihiragana"},
+ {0x30d2, "hikatakana"},
+ {0xff8b, "hikatakanahalfwidth"},
+ {0x05b4, "hiriq"},
+ {0x05b4, "hiriq14"},
+ {0x05b4, "hiriq21"},
+ {0x05b4, "hiriq2d"},
+ {0x05b4, "hiriqhebrew"},
+ {0x05b4, "hiriqnarrowhebrew"},
+ {0x05b4, "hiriqquarterhebrew"},
+ {0x05b4, "hiriqwidehebrew"},
+ {0x1e96, "hlinebelow"},
+ {0xff48, "hmonospace"},
+ {0x0570, "hoarmenian"},
+ {0x0e2b, "hohipthai"},
+ {0x307b, "hohiragana"},
+ {0x30db, "hokatakana"},
+ {0xff8e, "hokatakanahalfwidth"},
+ {0x05b9, "holam"},
+ {0x05b9, "holam19"},
+ {0x05b9, "holam26"},
+ {0x05b9, "holam32"},
+ {0x05b9, "holamhebrew"},
+ {0x05b9, "holamnarrowhebrew"},
+ {0x05b9, "holamquarterhebrew"},
+ {0x05b9, "holamwidehebrew"},
+ {0x0e2e, "honokhukthai"},
+ {0x0309, "hookabovecomb"},
+ {0x0309, "hookcmb"},
+ {0x0321, "hookpalatalizedbelowcmb"},
+ {0x0322, "hookretroflexbelowcmb"},
+ {0x3342, "hoonsquare"},
+ {0x03e9, "horicoptic"},
+ {0x2015, "horizontalbar"},
+ {0x031b, "horncmb"},
+ {0x2668, "hotsprings"},
+ {0x2302, "house"},
+ {0x24a3, "hparen"},
+ {0x02b0, "hsuperior"},
+ {0x0265, "hturned"},
+ {0x3075, "huhiragana"},
+ {0x3333, "huiitosquare"},
+ {0x30d5, "hukatakana"},
+ {0xff8c, "hukatakanahalfwidth"},
+ {0x02dd, "hungarumlaut"},
+ {0x030b, "hungarumlautcmb"},
+ {0x0195, "hv"},
+ {0x002d, "hyphen"},
+ {0xf6e5, "hypheninferior"},
+ {0xff0d, "hyphenmonospace"},
+ {0xfe63, "hyphensmall"},
+ {0xf6e6, "hyphensuperior"},
+ {0x2010, "hyphentwo"},
+ {0x0069, "i"},
+ {0x00ed, "iacute"},
+ {0x044f, "iacyrillic"},
+ {0x0987, "ibengali"},
+ {0x3127, "ibopomofo"},
+ {0x012d, "ibreve"},
+ {0x01d0, "icaron"},
+ {0x24d8, "icircle"},
+ {0x00ee, "icircumflex"},
+ {0x0456, "icyrillic"},
+ {0x0209, "idblgrave"},
+ {0x328f, "ideographearthcircle"},
+ {0x328b, "ideographfirecircle"},
+ {0x323f, "ideographicallianceparen"},
+ {0x323a, "ideographiccallparen"},
+ {0x32a5, "ideographiccentrecircle"},
+ {0x3006, "ideographicclose"},
+ {0x3001, "ideographiccomma"},
+ {0xff64, "ideographiccommaleft"},
+ {0x3237, "ideographiccongratulationparen"},
+ {0x32a3, "ideographiccorrectcircle"},
+ {0x322f, "ideographicearthparen"},
+ {0x323d, "ideographicenterpriseparen"},
+ {0x329d, "ideographicexcellentcircle"},
+ {0x3240, "ideographicfestivalparen"},
+ {0x3296, "ideographicfinancialcircle"},
+ {0x3236, "ideographicfinancialparen"},
+ {0x322b, "ideographicfireparen"},
+ {0x3232, "ideographichaveparen"},
+ {0x32a4, "ideographichighcircle"},
+ {0x3005, "ideographiciterationmark"},
+ {0x3298, "ideographiclaborcircle"},
+ {0x3238, "ideographiclaborparen"},
+ {0x32a7, "ideographicleftcircle"},
+ {0x32a6, "ideographiclowcircle"},
+ {0x32a9, "ideographicmedicinecircle"},
+ {0x322e, "ideographicmetalparen"},
+ {0x322a, "ideographicmoonparen"},
+ {0x3234, "ideographicnameparen"},
+ {0x3002, "ideographicperiod"},
+ {0x329e, "ideographicprintcircle"},
+ {0x3243, "ideographicreachparen"},
+ {0x3239, "ideographicrepresentparen"},
+ {0x323e, "ideographicresourceparen"},
+ {0x32a8, "ideographicrightcircle"},
+ {0x3299, "ideographicsecretcircle"},
+ {0x3242, "ideographicselfparen"},
+ {0x3233, "ideographicsocietyparen"},
+ {0x3000, "ideographicspace"},
+ {0x3235, "ideographicspecialparen"},
+ {0x3231, "ideographicstockparen"},
+ {0x323b, "ideographicstudyparen"},
+ {0x3230, "ideographicsunparen"},
+ {0x323c, "ideographicsuperviseparen"},
+ {0x322c, "ideographicwaterparen"},
+ {0x322d, "ideographicwoodparen"},
+ {0x3007, "ideographiczero"},
+ {0x328e, "ideographmetalcircle"},
+ {0x328a, "ideographmooncircle"},
+ {0x3294, "ideographnamecircle"},
+ {0x3290, "ideographsuncircle"},
+ {0x328c, "ideographwatercircle"},
+ {0x328d, "ideographwoodcircle"},
+ {0x0907, "ideva"},
+ {0x00ef, "idieresis"},
+ {0x1e2f, "idieresisacute"},
+ {0x04e5, "idieresiscyrillic"},
+ {0x1ecb, "idotbelow"},
+ {0x04d7, "iebrevecyrillic"},
+ {0x0435, "iecyrillic"},
+ {0x3275, "ieungacirclekorean"},
+ {0x3215, "ieungaparenkorean"},
+ {0x3267, "ieungcirclekorean"},
+ {0x3147, "ieungkorean"},
+ {0x3207, "ieungparenkorean"},
+ {0x00ec, "igrave"},
+ {0x0a87, "igujarati"},
+ {0x0a07, "igurmukhi"},
+ {0x3044, "ihiragana"},
+ {0x1ec9, "ihookabove"},
+ {0x0988, "iibengali"},
+ {0x0438, "iicyrillic"},
+ {0x0908, "iideva"},
+ {0x0a88, "iigujarati"},
+ {0x0a08, "iigurmukhi"},
+ {0x0a40, "iimatragurmukhi"},
+ {0x020b, "iinvertedbreve"},
+ {0x0439, "iishortcyrillic"},
+ {0x09c0, "iivowelsignbengali"},
+ {0x0940, "iivowelsigndeva"},
+ {0x0ac0, "iivowelsigngujarati"},
+ {0x0133, "ij"},
+ {0x30a4, "ikatakana"},
+ {0xff72, "ikatakanahalfwidth"},
+ {0x3163, "ikorean"},
+ {0x02dc, "ilde"},
+ {0x05ac, "iluyhebrew"},
+ {0x012b, "imacron"},
+ {0x04e3, "imacroncyrillic"},
+ {0x2253, "imageorapproximatelyequal"},
+ {0x0a3f, "imatragurmukhi"},
+ {0xff49, "imonospace"},
+ {0x2206, "increment"},
+ {0x221e, "infinity"},
+ {0x056b, "iniarmenian"},
+ {0x222b, "integral"},
+ {0x2321, "integralbottom"},
+ {0x2321, "integralbt"},
+ {0xf8f5, "integralex"},
+ {0x2320, "integraltop"},
+ {0x2320, "integraltp"},
+ {0x2229, "intersection"},
+ {0x3305, "intisquare"},
+ {0x25d8, "invbullet"},
+ {0x25d9, "invcircle"},
+ {0x263b, "invsmileface"},
+ {0x0451, "iocyrillic"},
+ {0x012f, "iogonek"},
+ {0x03b9, "iota"},
+ {0x03ca, "iotadieresis"},
+ {0x0390, "iotadieresistonos"},
+ {0x0269, "iotalatin"},
+ {0x03af, "iotatonos"},
+ {0x24a4, "iparen"},
+ {0x0a72, "irigurmukhi"},
+ {0x3043, "ismallhiragana"},
+ {0x30a3, "ismallkatakana"},
+ {0xff68, "ismallkatakanahalfwidth"},
+ {0x09fa, "issharbengali"},
+ {0x0268, "istroke"},
+ {0xf6ed, "isuperior"},
+ {0x309d, "iterationhiragana"},
+ {0x30fd, "iterationkatakana"},
+ {0x0129, "itilde"},
+ {0x1e2d, "itildebelow"},
+ {0x3129, "iubopomofo"},
+ {0x044e, "iucyrillic"},
+ {0x09bf, "ivowelsignbengali"},
+ {0x093f, "ivowelsigndeva"},
+ {0x0abf, "ivowelsigngujarati"},
+ {0x0475, "izhitsacyrillic"},
+ {0x0477, "izhitsadblgravecyrillic"},
+ {0x006a, "j"},
+ {0x0571, "jaarmenian"},
+ {0x099c, "jabengali"},
+ {0x091c, "jadeva"},
+ {0x0a9c, "jagujarati"},
+ {0x0a1c, "jagurmukhi"},
+ {0x3110, "jbopomofo"},
+ {0x01f0, "jcaron"},
+ {0x24d9, "jcircle"},
+ {0x0135, "jcircumflex"},
+ {0x029d, "jcrossedtail"},
+ {0x025f, "jdotlessstroke"},
+ {0x0458, "jecyrillic"},
+ {0x062c, "jeemarabic"},
+ {0xfe9e, "jeemfinalarabic"},
+ {0xfe9f, "jeeminitialarabic"},
+ {0xfea0, "jeemmedialarabic"},
+ {0x0698, "jeharabic"},
+ {0xfb8b, "jehfinalarabic"},
+ {0x099d, "jhabengali"},
+ {0x091d, "jhadeva"},
+ {0x0a9d, "jhagujarati"},
+ {0x0a1d, "jhagurmukhi"},
+ {0x057b, "jheharmenian"},
+ {0x3004, "jis"},
+ {0xff4a, "jmonospace"},
+ {0x24a5, "jparen"},
+ {0x02b2, "jsuperior"},
+ {0x006b, "k"},
+ {0x04a1, "kabashkircyrillic"},
+ {0x0995, "kabengali"},
+ {0x1e31, "kacute"},
+ {0x043a, "kacyrillic"},
+ {0x049b, "kadescendercyrillic"},
+ {0x0915, "kadeva"},
+ {0x05db, "kaf"},
+ {0x0643, "kafarabic"},
+ {0xfb3b, "kafdagesh"},
+ {0xfb3b, "kafdageshhebrew"},
+ {0xfeda, "kaffinalarabic"},
+ {0x05db, "kafhebrew"},
+ {0xfedb, "kafinitialarabic"},
+ {0xfedc, "kafmedialarabic"},
+ {0xfb4d, "kafrafehebrew"},
+ {0x0a95, "kagujarati"},
+ {0x0a15, "kagurmukhi"},
+ {0x304b, "kahiragana"},
+ {0x04c4, "kahookcyrillic"},
+ {0x30ab, "kakatakana"},
+ {0xff76, "kakatakanahalfwidth"},
+ {0x03ba, "kappa"},
+ {0x03f0, "kappasymbolgreek"},
+ {0x3171, "kapyeounmieumkorean"},
+ {0x3184, "kapyeounphieuphkorean"},
+ {0x3178, "kapyeounpieupkorean"},
+ {0x3179, "kapyeounssangpieupkorean"},
+ {0x330d, "karoriisquare"},
+ {0x0640, "kashidaautoarabic"},
+ {0x0640, "kashidaautonosidebearingarabic"},
+ {0x30f5, "kasmallkatakana"},
+ {0x3384, "kasquare"},
+ {0x0650, "kasraarabic"},
+ {0x064d, "kasratanarabic"},
+ {0x049f, "kastrokecyrillic"},
+ {0xff70, "katahiraprolongmarkhalfwidth"},
+ {0x049d, "kaverticalstrokecyrillic"},
+ {0x310e, "kbopomofo"},
+ {0x3389, "kcalsquare"},
+ {0x01e9, "kcaron"},
+ {0x0137, "kcedilla"},
+ {0x24da, "kcircle"},
+ {0x0137, "kcommaaccent"},
+ {0x1e33, "kdotbelow"},
+ {0x0584, "keharmenian"},
+ {0x3051, "kehiragana"},
+ {0x30b1, "kekatakana"},
+ {0xff79, "kekatakanahalfwidth"},
+ {0x056f, "kenarmenian"},
+ {0x30f6, "kesmallkatakana"},
+ {0x0138, "kgreenlandic"},
+ {0x0996, "khabengali"},
+ {0x0445, "khacyrillic"},
+ {0x0916, "khadeva"},
+ {0x0a96, "khagujarati"},
+ {0x0a16, "khagurmukhi"},
+ {0x062e, "khaharabic"},
+ {0xfea6, "khahfinalarabic"},
+ {0xfea7, "khahinitialarabic"},
+ {0xfea8, "khahmedialarabic"},
+ {0x03e7, "kheicoptic"},
+ {0x0959, "khhadeva"},
+ {0x0a59, "khhagurmukhi"},
+ {0x3278, "khieukhacirclekorean"},
+ {0x3218, "khieukhaparenkorean"},
+ {0x326a, "khieukhcirclekorean"},
+ {0x314b, "khieukhkorean"},
+ {0x320a, "khieukhparenkorean"},
+ {0x0e02, "khokhaithai"},
+ {0x0e05, "khokhonthai"},
+ {0x0e03, "khokhuatthai"},
+ {0x0e04, "khokhwaithai"},
+ {0x0e5b, "khomutthai"},
+ {0x0199, "khook"},
+ {0x0e06, "khorakhangthai"},
+ {0x3391, "khzsquare"},
+ {0x304d, "kihiragana"},
+ {0x30ad, "kikatakana"},
+ {0xff77, "kikatakanahalfwidth"},
+ {0x3315, "kiroguramusquare"},
+ {0x3316, "kiromeetorusquare"},
+ {0x3314, "kirosquare"},
+ {0x326e, "kiyeokacirclekorean"},
+ {0x320e, "kiyeokaparenkorean"},
+ {0x3260, "kiyeokcirclekorean"},
+ {0x3131, "kiyeokkorean"},
+ {0x3200, "kiyeokparenkorean"},
+ {0x3133, "kiyeoksioskorean"},
+ {0x045c, "kjecyrillic"},
+ {0x1e35, "klinebelow"},
+ {0x3398, "klsquare"},
+ {0x33a6, "kmcubedsquare"},
+ {0xff4b, "kmonospace"},
+ {0x33a2, "kmsquaredsquare"},
+ {0x3053, "kohiragana"},
+ {0x33c0, "kohmsquare"},
+ {0x0e01, "kokaithai"},
+ {0x30b3, "kokatakana"},
+ {0xff7a, "kokatakanahalfwidth"},
+ {0x331e, "kooposquare"},
+ {0x0481, "koppacyrillic"},
+ {0x327f, "koreanstandardsymbol"},
+ {0x0343, "koroniscmb"},
+ {0x24a6, "kparen"},
+ {0x33aa, "kpasquare"},
+ {0x046f, "ksicyrillic"},
+ {0x33cf, "ktsquare"},
+ {0x029e, "kturned"},
+ {0x304f, "kuhiragana"},
+ {0x30af, "kukatakana"},
+ {0xff78, "kukatakanahalfwidth"},
+ {0x33b8, "kvsquare"},
+ {0x33be, "kwsquare"},
+ {0x006c, "l"},
+ {0x09b2, "labengali"},
+ {0x013a, "lacute"},
+ {0x0932, "ladeva"},
+ {0x0ab2, "lagujarati"},
+ {0x0a32, "lagurmukhi"},
+ {0x0e45, "lakkhangyaothai"},
+ {0xfefc, "lamaleffinalarabic"},
+ {0xfef8, "lamalefhamzaabovefinalarabic"},
+ {0xfef7, "lamalefhamzaaboveisolatedarabic"},
+ {0xfefa, "lamalefhamzabelowfinalarabic"},
+ {0xfef9, "lamalefhamzabelowisolatedarabic"},
+ {0xfefb, "lamalefisolatedarabic"},
+ {0xfef6, "lamalefmaddaabovefinalarabic"},
+ {0xfef5, "lamalefmaddaaboveisolatedarabic"},
+ {0x0644, "lamarabic"},
+ {0x03bb, "lambda"},
+ {0x019b, "lambdastroke"},
+ {0x05dc, "lamed"},
+ {0xfb3c, "lameddagesh"},
+ {0xfb3c, "lameddageshhebrew"},
+ {0x05dc, "lamedhebrew"},
+ {0xfede, "lamfinalarabic"},
+ {0xfcca, "lamhahinitialarabic"},
+ {0xfedf, "laminitialarabic"},
+ {0xfcc9, "lamjeeminitialarabic"},
+ {0xfccb, "lamkhahinitialarabic"},
+ {0xfdf2, "lamlamhehisolatedarabic"},
+ {0xfee0, "lammedialarabic"},
+ {0xfd88, "lammeemhahinitialarabic"},
+ {0xfccc, "lammeeminitialarabic"},
+ {0x25ef, "largecircle"},
+ {0x019a, "lbar"},
+ {0x026c, "lbelt"},
+ {0x310c, "lbopomofo"},
+ {0x013e, "lcaron"},
+ {0x013c, "lcedilla"},
+ {0x24db, "lcircle"},
+ {0x1e3d, "lcircumflexbelow"},
+ {0x013c, "lcommaaccent"},
+ {0x0140, "ldot"},
+ {0x0140, "ldotaccent"},
+ {0x1e37, "ldotbelow"},
+ {0x1e39, "ldotbelowmacron"},
+ {0x031a, "leftangleabovecmb"},
+ {0x0318, "lefttackbelowcmb"},
+ {0x003c, "less"},
+ {0x2264, "lessequal"},
+ {0x22da, "lessequalorgreater"},
+ {0xff1c, "lessmonospace"},
+ {0x2272, "lessorequivalent"},
+ {0x2276, "lessorgreater"},
+ {0x2266, "lessoverequal"},
+ {0xfe64, "lesssmall"},
+ {0x026e, "lezh"},
+ {0x258c, "lfblock"},
+ {0x026d, "lhookretroflex"},
+ {0x20a4, "lira"},
+ {0x056c, "liwnarmenian"},
+ {0x01c9, "lj"},
+ {0x0459, "ljecyrillic"},
+ {0xf6c0, "ll"},
+ {0x0933, "lladeva"},
+ {0x0ab3, "llagujarati"},
+ {0x1e3b, "llinebelow"},
+ {0x0934, "llladeva"},
+ {0x09e1, "llvocalicbengali"},
+ {0x0961, "llvocalicdeva"},
+ {0x09e3, "llvocalicvowelsignbengali"},
+ {0x0963, "llvocalicvowelsigndeva"},
+ {0x026b, "lmiddletilde"},
+ {0xff4c, "lmonospace"},
+ {0x33d0, "lmsquare"},
+ {0x0e2c, "lochulathai"},
+ {0x2227, "logicaland"},
+ {0x00ac, "logicalnot"},
+ {0x2310, "logicalnotreversed"},
+ {0x2228, "logicalor"},
+ {0x0e25, "lolingthai"},
+ {0x017f, "longs"},
+ {0xfe4e, "lowlinecenterline"},
+ {0x0332, "lowlinecmb"},
+ {0xfe4d, "lowlinedashed"},
+ {0x25ca, "lozenge"},
+ {0x24a7, "lparen"},
+ {0x0142, "lslash"},
+ {0x2113, "lsquare"},
+ {0xf6ee, "lsuperior"},
+ {0x2591, "ltshade"},
+ {0x0e26, "luthai"},
+ {0x098c, "lvocalicbengali"},
+ {0x090c, "lvocalicdeva"},
+ {0x09e2, "lvocalicvowelsignbengali"},
+ {0x0962, "lvocalicvowelsigndeva"},
+ {0x33d3, "lxsquare"},
+ {0x006d, "m"},
+ {0x09ae, "mabengali"},
+ {0x00af, "macron"},
+ {0x0331, "macronbelowcmb"},
+ {0x0304, "macroncmb"},
+ {0x02cd, "macronlowmod"},
+ {0xffe3, "macronmonospace"},
+ {0x1e3f, "macute"},
+ {0x092e, "madeva"},
+ {0x0aae, "magujarati"},
+ {0x0a2e, "magurmukhi"},
+ {0x05a4, "mahapakhhebrew"},
+ {0x05a4, "mahapakhlefthebrew"},
+ {0x307e, "mahiragana"},
+ {0xf895, "maichattawalowleftthai"},
+ {0xf894, "maichattawalowrightthai"},
+ {0x0e4b, "maichattawathai"},
+ {0xf893, "maichattawaupperleftthai"},
+ {0xf88c, "maieklowleftthai"},
+ {0xf88b, "maieklowrightthai"},
+ {0x0e48, "maiekthai"},
+ {0xf88a, "maiekupperleftthai"},
+ {0xf884, "maihanakatleftthai"},
+ {0x0e31, "maihanakatthai"},
+ {0xf889, "maitaikhuleftthai"},
+ {0x0e47, "maitaikhuthai"},
+ {0xf88f, "maitholowleftthai"},
+ {0xf88e, "maitholowrightthai"},
+ {0x0e49, "maithothai"},
+ {0xf88d, "maithoupperleftthai"},
+ {0xf892, "maitrilowleftthai"},
+ {0xf891, "maitrilowrightthai"},
+ {0x0e4a, "maitrithai"},
+ {0xf890, "maitriupperleftthai"},
+ {0x0e46, "maiyamokthai"},
+ {0x30de, "makatakana"},
+ {0xff8f, "makatakanahalfwidth"},
+ {0x2642, "male"},
+ {0x3347, "mansyonsquare"},
+ {0x05be, "maqafhebrew"},
+ {0x2642, "mars"},
+ {0x05af, "masoracirclehebrew"},
+ {0x3383, "masquare"},
+ {0x3107, "mbopomofo"},
+ {0x33d4, "mbsquare"},
+ {0x24dc, "mcircle"},
+ {0x33a5, "mcubedsquare"},
+ {0x1e41, "mdotaccent"},
+ {0x1e43, "mdotbelow"},
+ {0x0645, "meemarabic"},
+ {0xfee2, "meemfinalarabic"},
+ {0xfee3, "meeminitialarabic"},
+ {0xfee4, "meemmedialarabic"},
+ {0xfcd1, "meemmeeminitialarabic"},
+ {0xfc48, "meemmeemisolatedarabic"},
+ {0x334d, "meetorusquare"},
+ {0x3081, "mehiragana"},
+ {0x337e, "meizierasquare"},
+ {0x30e1, "mekatakana"},
+ {0xff92, "mekatakanahalfwidth"},
+ {0x05de, "mem"},
+ {0xfb3e, "memdagesh"},
+ {0xfb3e, "memdageshhebrew"},
+ {0x05de, "memhebrew"},
+ {0x0574, "menarmenian"},
+ {0x05a5, "merkhahebrew"},
+ {0x05a6, "merkhakefulahebrew"},
+ {0x05a6, "merkhakefulalefthebrew"},
+ {0x05a5, "merkhalefthebrew"},
+ {0x0271, "mhook"},
+ {0x3392, "mhzsquare"},
+ {0xff65, "middledotkatakanahalfwidth"},
+ {0x00b7, "middot"},
+ {0x3272, "mieumacirclekorean"},
+ {0x3212, "mieumaparenkorean"},
+ {0x3264, "mieumcirclekorean"},
+ {0x3141, "mieumkorean"},
+ {0x3170, "mieumpansioskorean"},
+ {0x3204, "mieumparenkorean"},
+ {0x316e, "mieumpieupkorean"},
+ {0x316f, "mieumsioskorean"},
+ {0x307f, "mihiragana"},
+ {0x30df, "mikatakana"},
+ {0xff90, "mikatakanahalfwidth"},
+ {0x2212, "minus"},
+ {0x0320, "minusbelowcmb"},
+ {0x2296, "minuscircle"},
+ {0x02d7, "minusmod"},
+ {0x2213, "minusplus"},
+ {0x2032, "minute"},
+ {0x334a, "miribaarusquare"},
+ {0x3349, "mirisquare"},
+ {0x0270, "mlonglegturned"},
+ {0x3396, "mlsquare"},
+ {0x33a3, "mmcubedsquare"},
+ {0xff4d, "mmonospace"},
+ {0x339f, "mmsquaredsquare"},
+ {0x3082, "mohiragana"},
+ {0x33c1, "mohmsquare"},
+ {0x30e2, "mokatakana"},
+ {0xff93, "mokatakanahalfwidth"},
+ {0x33d6, "molsquare"},
+ {0x0e21, "momathai"},
+ {0x33a7, "moverssquare"},
+ {0x33a8, "moverssquaredsquare"},
+ {0x24a8, "mparen"},
+ {0x33ab, "mpasquare"},
+ {0x33b3, "mssquare"},
+ {0xf6ef, "msuperior"},
+ {0x026f, "mturned"},
+ {0x00b5, "mu"},
+ {0x00b5, "mu1"},
+ {0x3382, "muasquare"},
+ {0x226b, "muchgreater"},
+ {0x226a, "muchless"},
+ {0x338c, "mufsquare"},
+ {0x03bc, "mugreek"},
+ {0x338d, "mugsquare"},
+ {0x3080, "muhiragana"},
+ {0x30e0, "mukatakana"},
+ {0xff91, "mukatakanahalfwidth"},
+ {0x3395, "mulsquare"},
+ {0x00d7, "multiply"},
+ {0x339b, "mumsquare"},
+ {0x05a3, "munahhebrew"},
+ {0x05a3, "munahlefthebrew"},
+ {0x266a, "musicalnote"},
+ {0x266b, "musicalnotedbl"},
+ {0x266d, "musicflatsign"},
+ {0x266f, "musicsharpsign"},
+ {0x33b2, "mussquare"},
+ {0x33b6, "muvsquare"},
+ {0x33bc, "muwsquare"},
+ {0x33b9, "mvmegasquare"},
+ {0x33b7, "mvsquare"},
+ {0x33bf, "mwmegasquare"},
+ {0x33bd, "mwsquare"},
+ {0x006e, "n"},
+ {0x09a8, "nabengali"},
+ {0x2207, "nabla"},
+ {0x0144, "nacute"},
+ {0x0928, "nadeva"},
+ {0x0aa8, "nagujarati"},
+ {0x0a28, "nagurmukhi"},
+ {0x306a, "nahiragana"},
+ {0x30ca, "nakatakana"},
+ {0xff85, "nakatakanahalfwidth"},
+ {0x0149, "napostrophe"},
+ {0x3381, "nasquare"},
+ {0x310b, "nbopomofo"},
+ {0x00a0, "nbspace"},
+ {0x0148, "ncaron"},
+ {0x0146, "ncedilla"},
+ {0x24dd, "ncircle"},
+ {0x1e4b, "ncircumflexbelow"},
+ {0x0146, "ncommaaccent"},
+ {0x1e45, "ndotaccent"},
+ {0x1e47, "ndotbelow"},
+ {0x306d, "nehiragana"},
+ {0x30cd, "nekatakana"},
+ {0xff88, "nekatakanahalfwidth"},
+ {0x20aa, "newsheqelsign"},
+ {0x338b, "nfsquare"},
+ {0x0999, "ngabengali"},
+ {0x0919, "ngadeva"},
+ {0x0a99, "ngagujarati"},
+ {0x0a19, "ngagurmukhi"},
+ {0x0e07, "ngonguthai"},
+ {0x3093, "nhiragana"},
+ {0x0272, "nhookleft"},
+ {0x0273, "nhookretroflex"},
+ {0x326f, "nieunacirclekorean"},
+ {0x320f, "nieunaparenkorean"},
+ {0x3135, "nieuncieuckorean"},
+ {0x3261, "nieuncirclekorean"},
+ {0x3136, "nieunhieuhkorean"},
+ {0x3134, "nieunkorean"},
+ {0x3168, "nieunpansioskorean"},
+ {0x3201, "nieunparenkorean"},
+ {0x3167, "nieunsioskorean"},
+ {0x3166, "nieuntikeutkorean"},
+ {0x306b, "nihiragana"},
+ {0x30cb, "nikatakana"},
+ {0xff86, "nikatakanahalfwidth"},
+ {0xf899, "nikhahitleftthai"},
+ {0x0e4d, "nikhahitthai"},
+ {0x0039, "nine"},
+ {0x0669, "ninearabic"},
+ {0x09ef, "ninebengali"},
+ {0x2468, "ninecircle"},
+ {0x2792, "ninecircleinversesansserif"},
+ {0x096f, "ninedeva"},
+ {0x0aef, "ninegujarati"},
+ {0x0a6f, "ninegurmukhi"},
+ {0x0669, "ninehackarabic"},
+ {0x3029, "ninehangzhou"},
+ {0x3228, "nineideographicparen"},
+ {0x2089, "nineinferior"},
+ {0xff19, "ninemonospace"},
+ {0xf739, "nineoldstyle"},
+ {0x247c, "nineparen"},
+ {0x2490, "nineperiod"},
+ {0x06f9, "ninepersian"},
+ {0x2178, "nineroman"},
+ {0x2079, "ninesuperior"},
+ {0x2472, "nineteencircle"},
+ {0x2486, "nineteenparen"},
+ {0x249a, "nineteenperiod"},
+ {0x0e59, "ninethai"},
+ {0x01cc, "nj"},
+ {0x045a, "njecyrillic"},
+ {0x30f3, "nkatakana"},
+ {0xff9d, "nkatakanahalfwidth"},
+ {0x019e, "nlegrightlong"},
+ {0x1e49, "nlinebelow"},
+ {0xff4e, "nmonospace"},
+ {0x339a, "nmsquare"},
+ {0x09a3, "nnabengali"},
+ {0x0923, "nnadeva"},
+ {0x0aa3, "nnagujarati"},
+ {0x0a23, "nnagurmukhi"},
+ {0x0929, "nnnadeva"},
+ {0x306e, "nohiragana"},
+ {0x30ce, "nokatakana"},
+ {0xff89, "nokatakanahalfwidth"},
+ {0x00a0, "nonbreakingspace"},
+ {0x0e13, "nonenthai"},
+ {0x0e19, "nonuthai"},
+ {0x0646, "noonarabic"},
+ {0xfee6, "noonfinalarabic"},
+ {0x06ba, "noonghunnaarabic"},
+ {0xfb9f, "noonghunnafinalarabic"},
+ {0xfee7, "nooninitialarabic"},
+ {0xfcd2, "noonjeeminitialarabic"},
+ {0xfc4b, "noonjeemisolatedarabic"},
+ {0xfee8, "noonmedialarabic"},
+ {0xfcd5, "noonmeeminitialarabic"},
+ {0xfc4e, "noonmeemisolatedarabic"},
+ {0xfc8d, "noonnoonfinalarabic"},
+ {0x220c, "notcontains"},
+ {0x2209, "notelement"},
+ {0x2209, "notelementof"},
+ {0x2260, "notequal"},
+ {0x226f, "notgreater"},
+ {0x2271, "notgreaternorequal"},
+ {0x2279, "notgreaternorless"},
+ {0x2262, "notidentical"},
+ {0x226e, "notless"},
+ {0x2270, "notlessnorequal"},
+ {0x2226, "notparallel"},
+ {0x2280, "notprecedes"},
+ {0x2284, "notsubset"},
+ {0x2281, "notsucceeds"},
+ {0x2285, "notsuperset"},
+ {0x0576, "nowarmenian"},
+ {0x24a9, "nparen"},
+ {0x33b1, "nssquare"},
+ {0x207f, "nsuperior"},
+ {0x00f1, "ntilde"},
+ {0x03bd, "nu"},
+ {0x306c, "nuhiragana"},
+ {0x30cc, "nukatakana"},
+ {0xff87, "nukatakanahalfwidth"},
+ {0x09bc, "nuktabengali"},
+ {0x093c, "nuktadeva"},
+ {0x0abc, "nuktagujarati"},
+ {0x0a3c, "nuktagurmukhi"},
+ {0x0023, "numbersign"},
+ {0xff03, "numbersignmonospace"},
+ {0xfe5f, "numbersignsmall"},
+ {0x0374, "numeralsigngreek"},
+ {0x0375, "numeralsignlowergreek"},
+ {0x2116, "numero"},
+ {0x05e0, "nun"},
+ {0xfb40, "nundagesh"},
+ {0xfb40, "nundageshhebrew"},
+ {0x05e0, "nunhebrew"},
+ {0x33b5, "nvsquare"},
+ {0x33bb, "nwsquare"},
+ {0x099e, "nyabengali"},
+ {0x091e, "nyadeva"},
+ {0x0a9e, "nyagujarati"},
+ {0x0a1e, "nyagurmukhi"},
+ {0x006f, "o"},
+ {0x00f3, "oacute"},
+ {0x0e2d, "oangthai"},
+ {0x0275, "obarred"},
+ {0x04e9, "obarredcyrillic"},
+ {0x04eb, "obarreddieresiscyrillic"},
+ {0x0993, "obengali"},
+ {0x311b, "obopomofo"},
+ {0x014f, "obreve"},
+ {0x0911, "ocandradeva"},
+ {0x0a91, "ocandragujarati"},
+ {0x0949, "ocandravowelsigndeva"},
+ {0x0ac9, "ocandravowelsigngujarati"},
+ {0x01d2, "ocaron"},
+ {0x24de, "ocircle"},
+ {0x00f4, "ocircumflex"},
+ {0x1ed1, "ocircumflexacute"},
+ {0x1ed9, "ocircumflexdotbelow"},
+ {0x1ed3, "ocircumflexgrave"},
+ {0x1ed5, "ocircumflexhookabove"},
+ {0x1ed7, "ocircumflextilde"},
+ {0x043e, "ocyrillic"},
+ {0x0151, "odblacute"},
+ {0x020d, "odblgrave"},
+ {0x0913, "odeva"},
+ {0x00f6, "odieresis"},
+ {0x04e7, "odieresiscyrillic"},
+ {0x1ecd, "odotbelow"},
+ {0x0153, "oe"},
+ {0x315a, "oekorean"},
+ {0x02db, "ogonek"},
+ {0x0328, "ogonekcmb"},
+ {0x00f2, "ograve"},
+ {0x0a93, "ogujarati"},
+ {0x0585, "oharmenian"},
+ {0x304a, "ohiragana"},
+ {0x1ecf, "ohookabove"},
+ {0x01a1, "ohorn"},
+ {0x1edb, "ohornacute"},
+ {0x1ee3, "ohorndotbelow"},
+ {0x1edd, "ohorngrave"},
+ {0x1edf, "ohornhookabove"},
+ {0x1ee1, "ohorntilde"},
+ {0x0151, "ohungarumlaut"},
+ {0x01a3, "oi"},
+ {0x020f, "oinvertedbreve"},
+ {0x30aa, "okatakana"},
+ {0xff75, "okatakanahalfwidth"},
+ {0x3157, "okorean"},
+ {0x05ab, "olehebrew"},
+ {0x014d, "omacron"},
+ {0x1e53, "omacronacute"},
+ {0x1e51, "omacrongrave"},
+ {0x0950, "omdeva"},
+ {0x03c9, "omega"},
+ {0x03d6, "omega1"},
+ {0x0461, "omegacyrillic"},
+ {0x0277, "omegalatinclosed"},
+ {0x047b, "omegaroundcyrillic"},
+ {0x047d, "omegatitlocyrillic"},
+ {0x03ce, "omegatonos"},
+ {0x0ad0, "omgujarati"},
+ {0x03bf, "omicron"},
+ {0x03cc, "omicrontonos"},
+ {0xff4f, "omonospace"},
+ {0x0031, "one"},
+ {0x0661, "onearabic"},
+ {0x09e7, "onebengali"},
+ {0x2460, "onecircle"},
+ {0x278a, "onecircleinversesansserif"},
+ {0x0967, "onedeva"},
+ {0x2024, "onedotenleader"},
+ {0x215b, "oneeighth"},
+ {0xf6dc, "onefitted"},
+ {0x0ae7, "onegujarati"},
+ {0x0a67, "onegurmukhi"},
+ {0x0661, "onehackarabic"},
+ {0x00bd, "onehalf"},
+ {0x3021, "onehangzhou"},
+ {0x3220, "oneideographicparen"},
+ {0x2081, "oneinferior"},
+ {0xff11, "onemonospace"},
+ {0x09f4, "onenumeratorbengali"},
+ {0xf731, "oneoldstyle"},
+ {0x2474, "oneparen"},
+ {0x2488, "oneperiod"},
+ {0x06f1, "onepersian"},
+ {0x00bc, "onequarter"},
+ {0x2170, "oneroman"},
+ {0x00b9, "onesuperior"},
+ {0x0e51, "onethai"},
+ {0x2153, "onethird"},
+ {0x01eb, "oogonek"},
+ {0x01ed, "oogonekmacron"},
+ {0x0a13, "oogurmukhi"},
+ {0x0a4b, "oomatragurmukhi"},
+ {0x0254, "oopen"},
+ {0x24aa, "oparen"},
+ {0x25e6, "openbullet"},
+ {0x2325, "option"},
+ {0x00aa, "ordfeminine"},
+ {0x00ba, "ordmasculine"},
+ {0x221f, "orthogonal"},
+ {0x0912, "oshortdeva"},
+ {0x094a, "oshortvowelsigndeva"},
+ {0x00f8, "oslash"},
+ {0x01ff, "oslashacute"},
+ {0x3049, "osmallhiragana"},
+ {0x30a9, "osmallkatakana"},
+ {0xff6b, "osmallkatakanahalfwidth"},
+ {0x01ff, "ostrokeacute"},
+ {0xf6f0, "osuperior"},
+ {0x047f, "otcyrillic"},
+ {0x00f5, "otilde"},
+ {0x1e4d, "otildeacute"},
+ {0x1e4f, "otildedieresis"},
+ {0x3121, "oubopomofo"},
+ {0x203e, "overline"},
+ {0xfe4a, "overlinecenterline"},
+ {0x0305, "overlinecmb"},
+ {0xfe49, "overlinedashed"},
+ {0xfe4c, "overlinedblwavy"},
+ {0xfe4b, "overlinewavy"},
+ {0x00af, "overscore"},
+ {0x09cb, "ovowelsignbengali"},
+ {0x094b, "ovowelsigndeva"},
+ {0x0acb, "ovowelsigngujarati"},
+ {0x0070, "p"},
+ {0x3380, "paampssquare"},
+ {0x332b, "paasentosquare"},
+ {0x09aa, "pabengali"},
+ {0x1e55, "pacute"},
+ {0x092a, "padeva"},
+ {0x21df, "pagedown"},
+ {0x21de, "pageup"},
+ {0x0aaa, "pagujarati"},
+ {0x0a2a, "pagurmukhi"},
+ {0x3071, "pahiragana"},
+ {0x0e2f, "paiyannoithai"},
+ {0x30d1, "pakatakana"},
+ {0x0484, "palatalizationcyrilliccmb"},
+ {0x04c0, "palochkacyrillic"},
+ {0x317f, "pansioskorean"},
+ {0x00b6, "paragraph"},
+ {0x2225, "parallel"},
+ {0x0028, "parenleft"},
+ {0xfd3e, "parenleftaltonearabic"},
+ {0xf8ed, "parenleftbt"},
+ {0xf8ec, "parenleftex"},
+ {0x208d, "parenleftinferior"},
+ {0xff08, "parenleftmonospace"},
+ {0xfe59, "parenleftsmall"},
+ {0x207d, "parenleftsuperior"},
+ {0xf8eb, "parenlefttp"},
+ {0xfe35, "parenleftvertical"},
+ {0x0029, "parenright"},
+ {0xfd3f, "parenrightaltonearabic"},
+ {0xf8f8, "parenrightbt"},
+ {0xf8f7, "parenrightex"},
+ {0x208e, "parenrightinferior"},
+ {0xff09, "parenrightmonospace"},
+ {0xfe5a, "parenrightsmall"},
+ {0x207e, "parenrightsuperior"},
+ {0xf8f6, "parenrighttp"},
+ {0xfe36, "parenrightvertical"},
+ {0x2202, "partialdiff"},
+ {0x05c0, "paseqhebrew"},
+ {0x0599, "pashtahebrew"},
+ {0x33a9, "pasquare"},
+ {0x05b7, "patah"},
+ {0x05b7, "patah11"},
+ {0x05b7, "patah1d"},
+ {0x05b7, "patah2a"},
+ {0x05b7, "patahhebrew"},
+ {0x05b7, "patahnarrowhebrew"},
+ {0x05b7, "patahquarterhebrew"},
+ {0x05b7, "patahwidehebrew"},
+ {0x05a1, "pazerhebrew"},
+ {0x3106, "pbopomofo"},
+ {0x24df, "pcircle"},
+ {0x1e57, "pdotaccent"},
+ {0x05e4, "pe"},
+ {0x043f, "pecyrillic"},
+ {0xfb44, "pedagesh"},
+ {0xfb44, "pedageshhebrew"},
+ {0x333b, "peezisquare"},
+ {0xfb43, "pefinaldageshhebrew"},
+ {0x067e, "peharabic"},
+ {0x057a, "peharmenian"},
+ {0x05e4, "pehebrew"},
+ {0xfb57, "pehfinalarabic"},
+ {0xfb58, "pehinitialarabic"},
+ {0x307a, "pehiragana"},
+ {0xfb59, "pehmedialarabic"},
+ {0x30da, "pekatakana"},
+ {0x04a7, "pemiddlehookcyrillic"},
+ {0xfb4e, "perafehebrew"},
+ {0x0025, "percent"},
+ {0x066a, "percentarabic"},
+ {0xff05, "percentmonospace"},
+ {0xfe6a, "percentsmall"},
+ {0x002e, "period"},
+ {0x0589, "periodarmenian"},
+ {0x00b7, "periodcentered"},
+ {0xff61, "periodhalfwidth"},
+ {0xf6e7, "periodinferior"},
+ {0xff0e, "periodmonospace"},
+ {0xfe52, "periodsmall"},
+ {0xf6e8, "periodsuperior"},
+ {0x0342, "perispomenigreekcmb"},
+ {0x22a5, "perpendicular"},
+ {0x2030, "perthousand"},
+ {0x20a7, "peseta"},
+ {0x338a, "pfsquare"},
+ {0x09ab, "phabengali"},
+ {0x092b, "phadeva"},
+ {0x0aab, "phagujarati"},
+ {0x0a2b, "phagurmukhi"},
+ {0x03c6, "phi"},
+ {0x03d5, "phi1"},
+ {0x327a, "phieuphacirclekorean"},
+ {0x321a, "phieuphaparenkorean"},
+ {0x326c, "phieuphcirclekorean"},
+ {0x314d, "phieuphkorean"},
+ {0x320c, "phieuphparenkorean"},
+ {0x0278, "philatin"},
+ {0x0e3a, "phinthuthai"},
+ {0x03d5, "phisymbolgreek"},
+ {0x01a5, "phook"},
+ {0x0e1e, "phophanthai"},
+ {0x0e1c, "phophungthai"},
+ {0x0e20, "phosamphaothai"},
+ {0x03c0, "pi"},
+ {0x3273, "pieupacirclekorean"},
+ {0x3213, "pieupaparenkorean"},
+ {0x3176, "pieupcieuckorean"},
+ {0x3265, "pieupcirclekorean"},
+ {0x3172, "pieupkiyeokkorean"},
+ {0x3142, "pieupkorean"},
+ {0x3205, "pieupparenkorean"},
+ {0x3174, "pieupsioskiyeokkorean"},
+ {0x3144, "pieupsioskorean"},
+ {0x3175, "pieupsiostikeutkorean"},
+ {0x3177, "pieupthieuthkorean"},
+ {0x3173, "pieuptikeutkorean"},
+ {0x3074, "pihiragana"},
+ {0x30d4, "pikatakana"},
+ {0x03d6, "pisymbolgreek"},
+ {0x0583, "piwrarmenian"},
+ {0x002b, "plus"},
+ {0x031f, "plusbelowcmb"},
+ {0x2295, "pluscircle"},
+ {0x00b1, "plusminus"},
+ {0x02d6, "plusmod"},
+ {0xff0b, "plusmonospace"},
+ {0xfe62, "plussmall"},
+ {0x207a, "plussuperior"},
+ {0xff50, "pmonospace"},
+ {0x33d8, "pmsquare"},
+ {0x307d, "pohiragana"},
+ {0x261f, "pointingindexdownwhite"},
+ {0x261c, "pointingindexleftwhite"},
+ {0x261e, "pointingindexrightwhite"},
+ {0x261d, "pointingindexupwhite"},
+ {0x30dd, "pokatakana"},
+ {0x0e1b, "poplathai"},
+ {0x3012, "postalmark"},
+ {0x3020, "postalmarkface"},
+ {0x24ab, "pparen"},
+ {0x227a, "precedes"},
+ {0x211e, "prescription"},
+ {0x02b9, "primemod"},
+ {0x2035, "primereversed"},
+ {0x220f, "product"},
+ {0x2305, "projective"},
+ {0x30fc, "prolongedkana"},
+ {0x2318, "propellor"},
+ {0x2282, "propersubset"},
+ {0x2283, "propersuperset"},
+ {0x2237, "proportion"},
+ {0x221d, "proportional"},
+ {0x03c8, "psi"},
+ {0x0471, "psicyrillic"},
+ {0x0486, "psilipneumatacyrilliccmb"},
+ {0x33b0, "pssquare"},
+ {0x3077, "puhiragana"},
+ {0x30d7, "pukatakana"},
+ {0x33b4, "pvsquare"},
+ {0x33ba, "pwsquare"},
+ {0x0071, "q"},
+ {0x0958, "qadeva"},
+ {0x05a8, "qadmahebrew"},
+ {0x0642, "qafarabic"},
+ {0xfed6, "qaffinalarabic"},
+ {0xfed7, "qafinitialarabic"},
+ {0xfed8, "qafmedialarabic"},
+ {0x05b8, "qamats"},
+ {0x05b8, "qamats10"},
+ {0x05b8, "qamats1a"},
+ {0x05b8, "qamats1c"},
+ {0x05b8, "qamats27"},
+ {0x05b8, "qamats29"},
+ {0x05b8, "qamats33"},
+ {0x05b8, "qamatsde"},
+ {0x05b8, "qamatshebrew"},
+ {0x05b8, "qamatsnarrowhebrew"},
+ {0x05b8, "qamatsqatanhebrew"},
+ {0x05b8, "qamatsqatannarrowhebrew"},
+ {0x05b8, "qamatsqatanquarterhebrew"},
+ {0x05b8, "qamatsqatanwidehebrew"},
+ {0x05b8, "qamatsquarterhebrew"},
+ {0x05b8, "qamatswidehebrew"},
+ {0x059f, "qarneyparahebrew"},
+ {0x3111, "qbopomofo"},
+ {0x24e0, "qcircle"},
+ {0x02a0, "qhook"},
+ {0xff51, "qmonospace"},
+ {0x05e7, "qof"},
+ {0xfb47, "qofdagesh"},
+ {0xfb47, "qofdageshhebrew"},
+ {0x05e7, "qofhebrew"},
+ {0x24ac, "qparen"},
+ {0x2669, "quarternote"},
+ {0x05bb, "qubuts"},
+ {0x05bb, "qubuts18"},
+ {0x05bb, "qubuts25"},
+ {0x05bb, "qubuts31"},
+ {0x05bb, "qubutshebrew"},
+ {0x05bb, "qubutsnarrowhebrew"},
+ {0x05bb, "qubutsquarterhebrew"},
+ {0x05bb, "qubutswidehebrew"},
+ {0x003f, "question"},
+ {0x061f, "questionarabic"},
+ {0x055e, "questionarmenian"},
+ {0x00bf, "questiondown"},
+ {0xf7bf, "questiondownsmall"},
+ {0x037e, "questiongreek"},
+ {0xff1f, "questionmonospace"},
+ {0xf73f, "questionsmall"},
+ {0x0022, "quotedbl"},
+ {0x201e, "quotedblbase"},
+ {0x201c, "quotedblleft"},
+ {0xff02, "quotedblmonospace"},
+ {0x301e, "quotedblprime"},
+ {0x301d, "quotedblprimereversed"},
+ {0x201d, "quotedblright"},
+ {0x2018, "quoteleft"},
+ {0x201b, "quoteleftreversed"},
+ {0x201b, "quotereversed"},
+ {0x2019, "quoteright"},
+ {0x0149, "quoterightn"},
+ {0x201a, "quotesinglbase"},
+ {0x0027, "quotesingle"},
+ {0xff07, "quotesinglemonospace"},
+ {0x0072, "r"},
+ {0x057c, "raarmenian"},
+ {0x09b0, "rabengali"},
+ {0x0155, "racute"},
+ {0x0930, "radeva"},
+ {0x221a, "radical"},
+ {0xf8e5, "radicalex"},
+ {0x33ae, "radoverssquare"},
+ {0x33af, "radoverssquaredsquare"},
+ {0x33ad, "radsquare"},
+ {0x05bf, "rafe"},
+ {0x05bf, "rafehebrew"},
+ {0x0ab0, "ragujarati"},
+ {0x0a30, "ragurmukhi"},
+ {0x3089, "rahiragana"},
+ {0x30e9, "rakatakana"},
+ {0xff97, "rakatakanahalfwidth"},
+ {0x09f1, "ralowerdiagonalbengali"},
+ {0x09f0, "ramiddlediagonalbengali"},
+ {0x0264, "ramshorn"},
+ {0x2236, "ratio"},
+ {0x3116, "rbopomofo"},
+ {0x0159, "rcaron"},
+ {0x0157, "rcedilla"},
+ {0x24e1, "rcircle"},
+ {0x0157, "rcommaaccent"},
+ {0x0211, "rdblgrave"},
+ {0x1e59, "rdotaccent"},
+ {0x1e5b, "rdotbelow"},
+ {0x1e5d, "rdotbelowmacron"},
+ {0x203b, "referencemark"},
+ {0x2286, "reflexsubset"},
+ {0x2287, "reflexsuperset"},
+ {0x00ae, "registered"},
+ {0xf8e8, "registersans"},
+ {0xf6da, "registerserif"},
+ {0x0631, "reharabic"},
+ {0x0580, "reharmenian"},
+ {0xfeae, "rehfinalarabic"},
+ {0x308c, "rehiragana"},
+ {0x30ec, "rekatakana"},
+ {0xff9a, "rekatakanahalfwidth"},
+ {0x05e8, "resh"},
+ {0xfb48, "reshdageshhebrew"},
+ {0x05e8, "reshhebrew"},
+ {0x223d, "reversedtilde"},
+ {0x0597, "reviahebrew"},
+ {0x0597, "reviamugrashhebrew"},
+ {0x2310, "revlogicalnot"},
+ {0x027e, "rfishhook"},
+ {0x027f, "rfishhookreversed"},
+ {0x09dd, "rhabengali"},
+ {0x095d, "rhadeva"},
+ {0x03c1, "rho"},
+ {0x027d, "rhook"},
+ {0x027b, "rhookturned"},
+ {0x02b5, "rhookturnedsuperior"},
+ {0x03f1, "rhosymbolgreek"},
+ {0x02de, "rhotichookmod"},
+ {0x3271, "rieulacirclekorean"},
+ {0x3211, "rieulaparenkorean"},
+ {0x3263, "rieulcirclekorean"},
+ {0x3140, "rieulhieuhkorean"},
+ {0x313a, "rieulkiyeokkorean"},
+ {0x3169, "rieulkiyeoksioskorean"},
+ {0x3139, "rieulkorean"},
+ {0x313b, "rieulmieumkorean"},
+ {0x316c, "rieulpansioskorean"},
+ {0x3203, "rieulparenkorean"},
+ {0x313f, "rieulphieuphkorean"},
+ {0x313c, "rieulpieupkorean"},
+ {0x316b, "rieulpieupsioskorean"},
+ {0x313d, "rieulsioskorean"},
+ {0x313e, "rieulthieuthkorean"},
+ {0x316a, "rieultikeutkorean"},
+ {0x316d, "rieulyeorinhieuhkorean"},
+ {0x221f, "rightangle"},
+ {0x0319, "righttackbelowcmb"},
+ {0x22bf, "righttriangle"},
+ {0x308a, "rihiragana"},
+ {0x30ea, "rikatakana"},
+ {0xff98, "rikatakanahalfwidth"},
+ {0x02da, "ring"},
+ {0x0325, "ringbelowcmb"},
+ {0x030a, "ringcmb"},
+ {0x02bf, "ringhalfleft"},
+ {0x0559, "ringhalfleftarmenian"},
+ {0x031c, "ringhalfleftbelowcmb"},
+ {0x02d3, "ringhalfleftcentered"},
+ {0x02be, "ringhalfright"},
+ {0x0339, "ringhalfrightbelowcmb"},
+ {0x02d2, "ringhalfrightcentered"},
+ {0x0213, "rinvertedbreve"},
+ {0x3351, "rittorusquare"},
+ {0x1e5f, "rlinebelow"},
+ {0x027c, "rlongleg"},
+ {0x027a, "rlonglegturned"},
+ {0xff52, "rmonospace"},
+ {0x308d, "rohiragana"},
+ {0x30ed, "rokatakana"},
+ {0xff9b, "rokatakanahalfwidth"},
+ {0x0e23, "roruathai"},
+ {0x24ad, "rparen"},
+ {0x09dc, "rrabengali"},
+ {0x0931, "rradeva"},
+ {0x0a5c, "rragurmukhi"},
+ {0x0691, "rreharabic"},
+ {0xfb8d, "rrehfinalarabic"},
+ {0x09e0, "rrvocalicbengali"},
+ {0x0960, "rrvocalicdeva"},
+ {0x0ae0, "rrvocalicgujarati"},
+ {0x09c4, "rrvocalicvowelsignbengali"},
+ {0x0944, "rrvocalicvowelsigndeva"},
+ {0x0ac4, "rrvocalicvowelsigngujarati"},
+ {0xf6f1, "rsuperior"},
+ {0x2590, "rtblock"},
+ {0x0279, "rturned"},
+ {0x02b4, "rturnedsuperior"},
+ {0x308b, "ruhiragana"},
+ {0x30eb, "rukatakana"},
+ {0xff99, "rukatakanahalfwidth"},
+ {0x09f2, "rupeemarkbengali"},
+ {0x09f3, "rupeesignbengali"},
+ {0xf6dd, "rupiah"},
+ {0x0e24, "ruthai"},
+ {0x098b, "rvocalicbengali"},
+ {0x090b, "rvocalicdeva"},
+ {0x0a8b, "rvocalicgujarati"},
+ {0x09c3, "rvocalicvowelsignbengali"},
+ {0x0943, "rvocalicvowelsigndeva"},
+ {0x0ac3, "rvocalicvowelsigngujarati"},
+ {0x0073, "s"},
+ {0x09b8, "sabengali"},
+ {0x015b, "sacute"},
+ {0x1e65, "sacutedotaccent"},
+ {0x0635, "sadarabic"},
+ {0x0938, "sadeva"},
+ {0xfeba, "sadfinalarabic"},
+ {0xfebb, "sadinitialarabic"},
+ {0xfebc, "sadmedialarabic"},
+ {0x0ab8, "sagujarati"},
+ {0x0a38, "sagurmukhi"},
+ {0x3055, "sahiragana"},
+ {0x30b5, "sakatakana"},
+ {0xff7b, "sakatakanahalfwidth"},
+ {0xfdfa, "sallallahoualayhewasallamarabic"},
+ {0x05e1, "samekh"},
+ {0xfb41, "samekhdagesh"},
+ {0xfb41, "samekhdageshhebrew"},
+ {0x05e1, "samekhhebrew"},
+ {0x0e32, "saraaathai"},
+ {0x0e41, "saraaethai"},
+ {0x0e44, "saraaimaimalaithai"},
+ {0x0e43, "saraaimaimuanthai"},
+ {0x0e33, "saraamthai"},
+ {0x0e30, "saraathai"},
+ {0x0e40, "saraethai"},
+ {0xf886, "saraiileftthai"},
+ {0x0e35, "saraiithai"},
+ {0xf885, "saraileftthai"},
+ {0x0e34, "saraithai"},
+ {0x0e42, "saraothai"},
+ {0xf888, "saraueeleftthai"},
+ {0x0e37, "saraueethai"},
+ {0xf887, "saraueleftthai"},
+ {0x0e36, "sarauethai"},
+ {0x0e38, "sarauthai"},
+ {0x0e39, "sarauuthai"},
+ {0x3119, "sbopomofo"},
+ {0x0161, "scaron"},
+ {0x1e67, "scarondotaccent"},
+ {0x015f, "scedilla"},
+ {0x0259, "schwa"},
+ {0x04d9, "schwacyrillic"},
+ {0x04db, "schwadieresiscyrillic"},
+ {0x025a, "schwahook"},
+ {0x24e2, "scircle"},
+ {0x015d, "scircumflex"},
+ {0x0219, "scommaaccent"},
+ {0x1e61, "sdotaccent"},
+ {0x1e63, "sdotbelow"},
+ {0x1e69, "sdotbelowdotaccent"},
+ {0x033c, "seagullbelowcmb"},
+ {0x2033, "second"},
+ {0x02ca, "secondtonechinese"},
+ {0x00a7, "section"},
+ {0x0633, "seenarabic"},
+ {0xfeb2, "seenfinalarabic"},
+ {0xfeb3, "seeninitialarabic"},
+ {0xfeb4, "seenmedialarabic"},
+ {0x05b6, "segol"},
+ {0x05b6, "segol13"},
+ {0x05b6, "segol1f"},
+ {0x05b6, "segol2c"},
+ {0x05b6, "segolhebrew"},
+ {0x05b6, "segolnarrowhebrew"},
+ {0x05b6, "segolquarterhebrew"},
+ {0x0592, "segoltahebrew"},
+ {0x05b6, "segolwidehebrew"},
+ {0x057d, "seharmenian"},
+ {0x305b, "sehiragana"},
+ {0x30bb, "sekatakana"},
+ {0xff7e, "sekatakanahalfwidth"},
+ {0x003b, "semicolon"},
+ {0x061b, "semicolonarabic"},
+ {0xff1b, "semicolonmonospace"},
+ {0xfe54, "semicolonsmall"},
+ {0x309c, "semivoicedmarkkana"},
+ {0xff9f, "semivoicedmarkkanahalfwidth"},
+ {0x3322, "sentisquare"},
+ {0x3323, "sentosquare"},
+ {0x0037, "seven"},
+ {0x0667, "sevenarabic"},
+ {0x09ed, "sevenbengali"},
+ {0x2466, "sevencircle"},
+ {0x2790, "sevencircleinversesansserif"},
+ {0x096d, "sevendeva"},
+ {0x215e, "seveneighths"},
+ {0x0aed, "sevengujarati"},
+ {0x0a6d, "sevengurmukhi"},
+ {0x0667, "sevenhackarabic"},
+ {0x3027, "sevenhangzhou"},
+ {0x3226, "sevenideographicparen"},
+ {0x2087, "seveninferior"},
+ {0xff17, "sevenmonospace"},
+ {0xf737, "sevenoldstyle"},
+ {0x247a, "sevenparen"},
+ {0x248e, "sevenperiod"},
+ {0x06f7, "sevenpersian"},
+ {0x2176, "sevenroman"},
+ {0x2077, "sevensuperior"},
+ {0x2470, "seventeencircle"},
+ {0x2484, "seventeenparen"},
+ {0x2498, "seventeenperiod"},
+ {0x0e57, "seventhai"},
+ {0x00ad, "sfthyphen"},
+ {0x0577, "shaarmenian"},
+ {0x09b6, "shabengali"},
+ {0x0448, "shacyrillic"},
+ {0x0651, "shaddaarabic"},
+ {0xfc61, "shaddadammaarabic"},
+ {0xfc5e, "shaddadammatanarabic"},
+ {0xfc60, "shaddafathaarabic"},
+ {0xfc62, "shaddakasraarabic"},
+ {0xfc5f, "shaddakasratanarabic"},
+ {0x2592, "shade"},
+ {0x2593, "shadedark"},
+ {0x2591, "shadelight"},
+ {0x2592, "shademedium"},
+ {0x0936, "shadeva"},
+ {0x0ab6, "shagujarati"},
+ {0x0a36, "shagurmukhi"},
+ {0x0593, "shalshelethebrew"},
+ {0x3115, "shbopomofo"},
+ {0x0449, "shchacyrillic"},
+ {0x0634, "sheenarabic"},
+ {0xfeb6, "sheenfinalarabic"},
+ {0xfeb7, "sheeninitialarabic"},
+ {0xfeb8, "sheenmedialarabic"},
+ {0x03e3, "sheicoptic"},
+ {0x20aa, "sheqel"},
+ {0x20aa, "sheqelhebrew"},
+ {0x05b0, "sheva"},
+ {0x05b0, "sheva115"},
+ {0x05b0, "sheva15"},
+ {0x05b0, "sheva22"},
+ {0x05b0, "sheva2e"},
+ {0x05b0, "shevahebrew"},
+ {0x05b0, "shevanarrowhebrew"},
+ {0x05b0, "shevaquarterhebrew"},
+ {0x05b0, "shevawidehebrew"},
+ {0x04bb, "shhacyrillic"},
+ {0x03ed, "shimacoptic"},
+ {0x05e9, "shin"},
+ {0xfb49, "shindagesh"},
+ {0xfb49, "shindageshhebrew"},
+ {0xfb2c, "shindageshshindot"},
+ {0xfb2c, "shindageshshindothebrew"},
+ {0xfb2d, "shindageshsindot"},
+ {0xfb2d, "shindageshsindothebrew"},
+ {0x05c1, "shindothebrew"},
+ {0x05e9, "shinhebrew"},
+ {0xfb2a, "shinshindot"},
+ {0xfb2a, "shinshindothebrew"},
+ {0xfb2b, "shinsindot"},
+ {0xfb2b, "shinsindothebrew"},
+ {0x0282, "shook"},
+ {0x03c3, "sigma"},
+ {0x03c2, "sigma1"},
+ {0x03c2, "sigmafinal"},
+ {0x03f2, "sigmalunatesymbolgreek"},
+ {0x3057, "sihiragana"},
+ {0x30b7, "sikatakana"},
+ {0xff7c, "sikatakanahalfwidth"},
+ {0x05bd, "siluqhebrew"},
+ {0x05bd, "siluqlefthebrew"},
+ {0x223c, "similar"},
+ {0x05c2, "sindothebrew"},
+ {0x3274, "siosacirclekorean"},
+ {0x3214, "siosaparenkorean"},
+ {0x317e, "sioscieuckorean"},
+ {0x3266, "sioscirclekorean"},
+ {0x317a, "sioskiyeokkorean"},
+ {0x3145, "sioskorean"},
+ {0x317b, "siosnieunkorean"},
+ {0x3206, "siosparenkorean"},
+ {0x317d, "siospieupkorean"},
+ {0x317c, "siostikeutkorean"},
+ {0x0036, "six"},
+ {0x0666, "sixarabic"},
+ {0x09ec, "sixbengali"},
+ {0x2465, "sixcircle"},
+ {0x278f, "sixcircleinversesansserif"},
+ {0x096c, "sixdeva"},
+ {0x0aec, "sixgujarati"},
+ {0x0a6c, "sixgurmukhi"},
+ {0x0666, "sixhackarabic"},
+ {0x3026, "sixhangzhou"},
+ {0x3225, "sixideographicparen"},
+ {0x2086, "sixinferior"},
+ {0xff16, "sixmonospace"},
+ {0xf736, "sixoldstyle"},
+ {0x2479, "sixparen"},
+ {0x248d, "sixperiod"},
+ {0x06f6, "sixpersian"},
+ {0x2175, "sixroman"},
+ {0x2076, "sixsuperior"},
+ {0x246f, "sixteencircle"},
+ {0x09f9, "sixteencurrencydenominatorbengali"},
+ {0x2483, "sixteenparen"},
+ {0x2497, "sixteenperiod"},
+ {0x0e56, "sixthai"},
+ {0x002f, "slash"},
+ {0xff0f, "slashmonospace"},
+ {0x017f, "slong"},
+ {0x1e9b, "slongdotaccent"},
+ {0x263a, "smileface"},
+ {0xff53, "smonospace"},
+ {0x05c3, "sofpasuqhebrew"},
+ {0x00ad, "softhyphen"},
+ {0x044c, "softsigncyrillic"},
+ {0x305d, "sohiragana"},
+ {0x30bd, "sokatakana"},
+ {0xff7f, "sokatakanahalfwidth"},
+ {0x0338, "soliduslongoverlaycmb"},
+ {0x0337, "solidusshortoverlaycmb"},
+ {0x0e29, "sorusithai"},
+ {0x0e28, "sosalathai"},
+ {0x0e0b, "sosothai"},
+ {0x0e2a, "sosuathai"},
+ {0x0020, "space"},
+ {0x0020, "spacehackarabic"},
+ {0x2660, "spade"},
+ {0x2660, "spadesuitblack"},
+ {0x2664, "spadesuitwhite"},
+ {0x24ae, "sparen"},
+ {0x033b, "squarebelowcmb"},
+ {0x33c4, "squarecc"},
+ {0x339d, "squarecm"},
+ {0x25a9, "squarediagonalcrosshatchfill"},
+ {0x25a4, "squarehorizontalfill"},
+ {0x338f, "squarekg"},
+ {0x339e, "squarekm"},
+ {0x33ce, "squarekmcapital"},
+ {0x33d1, "squareln"},
+ {0x33d2, "squarelog"},
+ {0x338e, "squaremg"},
+ {0x33d5, "squaremil"},
+ {0x339c, "squaremm"},
+ {0x33a1, "squaremsquared"},
+ {0x25a6, "squareorthogonalcrosshatchfill"},
+ {0x25a7, "squareupperlefttolowerrightfill"},
+ {0x25a8, "squareupperrighttolowerleftfill"},
+ {0x25a5, "squareverticalfill"},
+ {0x25a3, "squarewhitewithsmallblack"},
+ {0x33db, "srsquare"},
+ {0x09b7, "ssabengali"},
+ {0x0937, "ssadeva"},
+ {0x0ab7, "ssagujarati"},
+ {0x3149, "ssangcieuckorean"},
+ {0x3185, "ssanghieuhkorean"},
+ {0x3180, "ssangieungkorean"},
+ {0x3132, "ssangkiyeokkorean"},
+ {0x3165, "ssangnieunkorean"},
+ {0x3143, "ssangpieupkorean"},
+ {0x3146, "ssangsioskorean"},
+ {0x3138, "ssangtikeutkorean"},
+ {0xf6f2, "ssuperior"},
+ {0x00a3, "sterling"},
+ {0xffe1, "sterlingmonospace"},
+ {0x0336, "strokelongoverlaycmb"},
+ {0x0335, "strokeshortoverlaycmb"},
+ {0x2282, "subset"},
+ {0x228a, "subsetnotequal"},
+ {0x2286, "subsetorequal"},
+ {0x227b, "succeeds"},
+ {0x220b, "suchthat"},
+ {0x3059, "suhiragana"},
+ {0x30b9, "sukatakana"},
+ {0xff7d, "sukatakanahalfwidth"},
+ {0x0652, "sukunarabic"},
+ {0x2211, "summation"},
+ {0x263c, "sun"},
+ {0x2283, "superset"},
+ {0x228b, "supersetnotequal"},
+ {0x2287, "supersetorequal"},
+ {0x33dc, "svsquare"},
+ {0x337c, "syouwaerasquare"},
+ {0x0074, "t"},
+ {0x09a4, "tabengali"},
+ {0x22a4, "tackdown"},
+ {0x22a3, "tackleft"},
+ {0x0924, "tadeva"},
+ {0x0aa4, "tagujarati"},
+ {0x0a24, "tagurmukhi"},
+ {0x0637, "taharabic"},
+ {0xfec2, "tahfinalarabic"},
+ {0xfec3, "tahinitialarabic"},
+ {0x305f, "tahiragana"},
+ {0xfec4, "tahmedialarabic"},
+ {0x337d, "taisyouerasquare"},
+ {0x30bf, "takatakana"},
+ {0xff80, "takatakanahalfwidth"},
+ {0x0640, "tatweelarabic"},
+ {0x03c4, "tau"},
+ {0x05ea, "tav"},
+ {0xfb4a, "tavdages"},
+ {0xfb4a, "tavdagesh"},
+ {0xfb4a, "tavdageshhebrew"},
+ {0x05ea, "tavhebrew"},
+ {0x0167, "tbar"},
+ {0x310a, "tbopomofo"},
+ {0x0165, "tcaron"},
+ {0x02a8, "tccurl"},
+ {0x0163, "tcedilla"},
+ {0x0686, "tcheharabic"},
+ {0xfb7b, "tchehfinalarabic"},
+ {0xfb7c, "tchehinitialarabic"},
+ {0xfb7d, "tchehmedialarabic"},
+ {0x24e3, "tcircle"},
+ {0x1e71, "tcircumflexbelow"},
+ {0x0163, "tcommaaccent"},
+ {0x1e97, "tdieresis"},
+ {0x1e6b, "tdotaccent"},
+ {0x1e6d, "tdotbelow"},
+ {0x0442, "tecyrillic"},
+ {0x04ad, "tedescendercyrillic"},
+ {0x062a, "teharabic"},
+ {0xfe96, "tehfinalarabic"},
+ {0xfca2, "tehhahinitialarabic"},
+ {0xfc0c, "tehhahisolatedarabic"},
+ {0xfe97, "tehinitialarabic"},
+ {0x3066, "tehiragana"},
+ {0xfca1, "tehjeeminitialarabic"},
+ {0xfc0b, "tehjeemisolatedarabic"},
+ {0x0629, "tehmarbutaarabic"},
+ {0xfe94, "tehmarbutafinalarabic"},
+ {0xfe98, "tehmedialarabic"},
+ {0xfca4, "tehmeeminitialarabic"},
+ {0xfc0e, "tehmeemisolatedarabic"},
+ {0xfc73, "tehnoonfinalarabic"},
+ {0x30c6, "tekatakana"},
+ {0xff83, "tekatakanahalfwidth"},
+ {0x2121, "telephone"},
+ {0x260e, "telephoneblack"},
+ {0x05a0, "telishagedolahebrew"},
+ {0x05a9, "telishaqetanahebrew"},
+ {0x2469, "tencircle"},
+ {0x3229, "tenideographicparen"},
+ {0x247d, "tenparen"},
+ {0x2491, "tenperiod"},
+ {0x2179, "tenroman"},
+ {0x02a7, "tesh"},
+ {0x05d8, "tet"},
+ {0xfb38, "tetdagesh"},
+ {0xfb38, "tetdageshhebrew"},
+ {0x05d8, "tethebrew"},
+ {0x04b5, "tetsecyrillic"},
+ {0x059b, "tevirhebrew"},
+ {0x059b, "tevirlefthebrew"},
+ {0x09a5, "thabengali"},
+ {0x0925, "thadeva"},
+ {0x0aa5, "thagujarati"},
+ {0x0a25, "thagurmukhi"},
+ {0x0630, "thalarabic"},
+ {0xfeac, "thalfinalarabic"},
+ {0xf898, "thanthakhatlowleftthai"},
+ {0xf897, "thanthakhatlowrightthai"},
+ {0x0e4c, "thanthakhatthai"},
+ {0xf896, "thanthakhatupperleftthai"},
+ {0x062b, "theharabic"},
+ {0xfe9a, "thehfinalarabic"},
+ {0xfe9b, "thehinitialarabic"},
+ {0xfe9c, "thehmedialarabic"},
+ {0x2203, "thereexists"},
+ {0x2234, "therefore"},
+ {0x03b8, "theta"},
+ {0x03d1, "theta1"},
+ {0x03d1, "thetasymbolgreek"},
+ {0x3279, "thieuthacirclekorean"},
+ {0x3219, "thieuthaparenkorean"},
+ {0x326b, "thieuthcirclekorean"},
+ {0x314c, "thieuthkorean"},
+ {0x320b, "thieuthparenkorean"},
+ {0x246c, "thirteencircle"},
+ {0x2480, "thirteenparen"},
+ {0x2494, "thirteenperiod"},
+ {0x0e11, "thonangmonthothai"},
+ {0x01ad, "thook"},
+ {0x0e12, "thophuthaothai"},
+ {0x00fe, "thorn"},
+ {0x0e17, "thothahanthai"},
+ {0x0e10, "thothanthai"},
+ {0x0e18, "thothongthai"},
+ {0x0e16, "thothungthai"},
+ {0x0482, "thousandcyrillic"},
+ {0x066c, "thousandsseparatorarabic"},
+ {0x066c, "thousandsseparatorpersian"},
+ {0x0033, "three"},
+ {0x0663, "threearabic"},
+ {0x09e9, "threebengali"},
+ {0x2462, "threecircle"},
+ {0x278c, "threecircleinversesansserif"},
+ {0x0969, "threedeva"},
+ {0x215c, "threeeighths"},
+ {0x0ae9, "threegujarati"},
+ {0x0a69, "threegurmukhi"},
+ {0x0663, "threehackarabic"},
+ {0x3023, "threehangzhou"},
+ {0x3222, "threeideographicparen"},
+ {0x2083, "threeinferior"},
+ {0xff13, "threemonospace"},
+ {0x09f6, "threenumeratorbengali"},
+ {0xf733, "threeoldstyle"},
+ {0x2476, "threeparen"},
+ {0x248a, "threeperiod"},
+ {0x06f3, "threepersian"},
+ {0x00be, "threequarters"},
+ {0xf6de, "threequartersemdash"},
+ {0x2172, "threeroman"},
+ {0x00b3, "threesuperior"},
+ {0x0e53, "threethai"},
+ {0x3394, "thzsquare"},
+ {0x3061, "tihiragana"},
+ {0x30c1, "tikatakana"},
+ {0xff81, "tikatakanahalfwidth"},
+ {0x3270, "tikeutacirclekorean"},
+ {0x3210, "tikeutaparenkorean"},
+ {0x3262, "tikeutcirclekorean"},
+ {0x3137, "tikeutkorean"},
+ {0x3202, "tikeutparenkorean"},
+ {0x02dc, "tilde"},
+ {0x0330, "tildebelowcmb"},
+ {0x0303, "tildecmb"},
+ {0x0303, "tildecomb"},
+ {0x0360, "tildedoublecmb"},
+ {0x223c, "tildeoperator"},
+ {0x0334, "tildeoverlaycmb"},
+ {0x033e, "tildeverticalcmb"},
+ {0x2297, "timescircle"},
+ {0x0596, "tipehahebrew"},
+ {0x0596, "tipehalefthebrew"},
+ {0x0a70, "tippigurmukhi"},
+ {0x0483, "titlocyrilliccmb"},
+ {0x057f, "tiwnarmenian"},
+ {0x1e6f, "tlinebelow"},
+ {0xff54, "tmonospace"},
+ {0x0569, "toarmenian"},
+ {0x3068, "tohiragana"},
+ {0x30c8, "tokatakana"},
+ {0xff84, "tokatakanahalfwidth"},
+ {0x02e5, "tonebarextrahighmod"},
+ {0x02e9, "tonebarextralowmod"},
+ {0x02e6, "tonebarhighmod"},
+ {0x02e8, "tonebarlowmod"},
+ {0x02e7, "tonebarmidmod"},
+ {0x01bd, "tonefive"},
+ {0x0185, "tonesix"},
+ {0x01a8, "tonetwo"},
+ {0x0384, "tonos"},
+ {0x3327, "tonsquare"},
+ {0x0e0f, "topatakthai"},
+ {0x3014, "tortoiseshellbracketleft"},
+ {0xfe5d, "tortoiseshellbracketleftsmall"},
+ {0xfe39, "tortoiseshellbracketleftvertical"},
+ {0x3015, "tortoiseshellbracketright"},
+ {0xfe5e, "tortoiseshellbracketrightsmall"},
+ {0xfe3a, "tortoiseshellbracketrightvertical"},
+ {0x0e15, "totaothai"},
+ {0x01ab, "tpalatalhook"},
+ {0x24af, "tparen"},
+ {0x2122, "trademark"},
+ {0xf8ea, "trademarksans"},
+ {0xf6db, "trademarkserif"},
+ {0x0288, "tretroflexhook"},
+ {0x25bc, "triagdn"},
+ {0x25c4, "triaglf"},
+ {0x25ba, "triagrt"},
+ {0x25b2, "triagup"},
+ {0x02a6, "ts"},
+ {0x05e6, "tsadi"},
+ {0xfb46, "tsadidagesh"},
+ {0xfb46, "tsadidageshhebrew"},
+ {0x05e6, "tsadihebrew"},
+ {0x0446, "tsecyrillic"},
+ {0x05b5, "tsere"},
+ {0x05b5, "tsere12"},
+ {0x05b5, "tsere1e"},
+ {0x05b5, "tsere2b"},
+ {0x05b5, "tserehebrew"},
+ {0x05b5, "tserenarrowhebrew"},
+ {0x05b5, "tserequarterhebrew"},
+ {0x05b5, "tserewidehebrew"},
+ {0x045b, "tshecyrillic"},
+ {0xf6f3, "tsuperior"},
+ {0x099f, "ttabengali"},
+ {0x091f, "ttadeva"},
+ {0x0a9f, "ttagujarati"},
+ {0x0a1f, "ttagurmukhi"},
+ {0x0679, "tteharabic"},
+ {0xfb67, "ttehfinalarabic"},
+ {0xfb68, "ttehinitialarabic"},
+ {0xfb69, "ttehmedialarabic"},
+ {0x09a0, "tthabengali"},
+ {0x0920, "tthadeva"},
+ {0x0aa0, "tthagujarati"},
+ {0x0a20, "tthagurmukhi"},
+ {0x0287, "tturned"},
+ {0x3064, "tuhiragana"},
+ {0x30c4, "tukatakana"},
+ {0xff82, "tukatakanahalfwidth"},
+ {0x3063, "tusmallhiragana"},
+ {0x30c3, "tusmallkatakana"},
+ {0xff6f, "tusmallkatakanahalfwidth"},
+ {0x246b, "twelvecircle"},
+ {0x247f, "twelveparen"},
+ {0x2493, "twelveperiod"},
+ {0x217b, "twelveroman"},
+ {0x2473, "twentycircle"},
+ {0x5344, "twentyhangzhou"},
+ {0x2487, "twentyparen"},
+ {0x249b, "twentyperiod"},
+ {0x0032, "two"},
+ {0x0662, "twoarabic"},
+ {0x09e8, "twobengali"},
+ {0x2461, "twocircle"},
+ {0x278b, "twocircleinversesansserif"},
+ {0x0968, "twodeva"},
+ {0x2025, "twodotenleader"},
+ {0x2025, "twodotleader"},
+ {0xfe30, "twodotleadervertical"},
+ {0x0ae8, "twogujarati"},
+ {0x0a68, "twogurmukhi"},
+ {0x0662, "twohackarabic"},
+ {0x3022, "twohangzhou"},
+ {0x3221, "twoideographicparen"},
+ {0x2082, "twoinferior"},
+ {0xff12, "twomonospace"},
+ {0x09f5, "twonumeratorbengali"},
+ {0xf732, "twooldstyle"},
+ {0x2475, "twoparen"},
+ {0x2489, "twoperiod"},
+ {0x06f2, "twopersian"},
+ {0x2171, "tworoman"},
+ {0x01bb, "twostroke"},
+ {0x00b2, "twosuperior"},
+ {0x0e52, "twothai"},
+ {0x2154, "twothirds"},
+ {0x0075, "u"},
+ {0x00fa, "uacute"},
+ {0x0289, "ubar"},
+ {0x0989, "ubengali"},
+ {0x3128, "ubopomofo"},
+ {0x016d, "ubreve"},
+ {0x01d4, "ucaron"},
+ {0x24e4, "ucircle"},
+ {0x00fb, "ucircumflex"},
+ {0x1e77, "ucircumflexbelow"},
+ {0x0443, "ucyrillic"},
+ {0x0951, "udattadeva"},
+ {0x0171, "udblacute"},
+ {0x0215, "udblgrave"},
+ {0x0909, "udeva"},
+ {0x00fc, "udieresis"},
+ {0x01d8, "udieresisacute"},
+ {0x1e73, "udieresisbelow"},
+ {0x01da, "udieresiscaron"},
+ {0x04f1, "udieresiscyrillic"},
+ {0x01dc, "udieresisgrave"},
+ {0x01d6, "udieresismacron"},
+ {0x1ee5, "udotbelow"},
+ {0x00f9, "ugrave"},
+ {0x0a89, "ugujarati"},
+ {0x0a09, "ugurmukhi"},
+ {0x3046, "uhiragana"},
+ {0x1ee7, "uhookabove"},
+ {0x01b0, "uhorn"},
+ {0x1ee9, "uhornacute"},
+ {0x1ef1, "uhorndotbelow"},
+ {0x1eeb, "uhorngrave"},
+ {0x1eed, "uhornhookabove"},
+ {0x1eef, "uhorntilde"},
+ {0x0171, "uhungarumlaut"},
+ {0x04f3, "uhungarumlautcyrillic"},
+ {0x0217, "uinvertedbreve"},
+ {0x30a6, "ukatakana"},
+ {0xff73, "ukatakanahalfwidth"},
+ {0x0479, "ukcyrillic"},
+ {0x315c, "ukorean"},
+ {0x016b, "umacron"},
+ {0x04ef, "umacroncyrillic"},
+ {0x1e7b, "umacrondieresis"},
+ {0x0a41, "umatragurmukhi"},
+ {0xff55, "umonospace"},
+ {0x005f, "underscore"},
+ {0x2017, "underscoredbl"},
+ {0xff3f, "underscoremonospace"},
+ {0xfe33, "underscorevertical"},
+ {0xfe4f, "underscorewavy"},
+ {0x222a, "union"},
+ {0x2200, "universal"},
+ {0x0173, "uogonek"},
+ {0x24b0, "uparen"},
+ {0x2580, "upblock"},
+ {0x05c4, "upperdothebrew"},
+ {0x03c5, "upsilon"},
+ {0x03cb, "upsilondieresis"},
+ {0x03b0, "upsilondieresistonos"},
+ {0x028a, "upsilonlatin"},
+ {0x03cd, "upsilontonos"},
+ {0x031d, "uptackbelowcmb"},
+ {0x02d4, "uptackmod"},
+ {0x0a73, "uragurmukhi"},
+ {0x016f, "uring"},
+ {0x045e, "ushortcyrillic"},
+ {0x3045, "usmallhiragana"},
+ {0x30a5, "usmallkatakana"},
+ {0xff69, "usmallkatakanahalfwidth"},
+ {0x04af, "ustraightcyrillic"},
+ {0x04b1, "ustraightstrokecyrillic"},
+ {0x0169, "utilde"},
+ {0x1e79, "utildeacute"},
+ {0x1e75, "utildebelow"},
+ {0x098a, "uubengali"},
+ {0x090a, "uudeva"},
+ {0x0a8a, "uugujarati"},
+ {0x0a0a, "uugurmukhi"},
+ {0x0a42, "uumatragurmukhi"},
+ {0x09c2, "uuvowelsignbengali"},
+ {0x0942, "uuvowelsigndeva"},
+ {0x0ac2, "uuvowelsigngujarati"},
+ {0x09c1, "uvowelsignbengali"},
+ {0x0941, "uvowelsigndeva"},
+ {0x0ac1, "uvowelsigngujarati"},
+ {0x0076, "v"},
+ {0x0935, "vadeva"},
+ {0x0ab5, "vagujarati"},
+ {0x0a35, "vagurmukhi"},
+ {0x30f7, "vakatakana"},
+ {0x05d5, "vav"},
+ {0xfb35, "vavdagesh"},
+ {0xfb35, "vavdagesh65"},
+ {0xfb35, "vavdageshhebrew"},
+ {0x05d5, "vavhebrew"},
+ {0xfb4b, "vavholam"},
+ {0xfb4b, "vavholamhebrew"},
+ {0x05f0, "vavvavhebrew"},
+ {0x05f1, "vavyodhebrew"},
+ {0x24e5, "vcircle"},
+ {0x1e7f, "vdotbelow"},
+ {0x0432, "vecyrillic"},
+ {0x06a4, "veharabic"},
+ {0xfb6b, "vehfinalarabic"},
+ {0xfb6c, "vehinitialarabic"},
+ {0xfb6d, "vehmedialarabic"},
+ {0x30f9, "vekatakana"},
+ {0x2640, "venus"},
+ {0x007c, "verticalbar"},
+ {0x030d, "verticallineabovecmb"},
+ {0x0329, "verticallinebelowcmb"},
+ {0x02cc, "verticallinelowmod"},
+ {0x02c8, "verticallinemod"},
+ {0x057e, "vewarmenian"},
+ {0x028b, "vhook"},
+ {0x30f8, "vikatakana"},
+ {0x09cd, "viramabengali"},
+ {0x094d, "viramadeva"},
+ {0x0acd, "viramagujarati"},
+ {0x0983, "visargabengali"},
+ {0x0903, "visargadeva"},
+ {0x0a83, "visargagujarati"},
+ {0xff56, "vmonospace"},
+ {0x0578, "voarmenian"},
+ {0x309e, "voicediterationhiragana"},
+ {0x30fe, "voicediterationkatakana"},
+ {0x309b, "voicedmarkkana"},
+ {0xff9e, "voicedmarkkanahalfwidth"},
+ {0x30fa, "vokatakana"},
+ {0x24b1, "vparen"},
+ {0x1e7d, "vtilde"},
+ {0x028c, "vturned"},
+ {0x3094, "vuhiragana"},
+ {0x30f4, "vukatakana"},
+ {0x0077, "w"},
+ {0x1e83, "wacute"},
+ {0x3159, "waekorean"},
+ {0x308f, "wahiragana"},
+ {0x30ef, "wakatakana"},
+ {0xff9c, "wakatakanahalfwidth"},
+ {0x3158, "wakorean"},
+ {0x308e, "wasmallhiragana"},
+ {0x30ee, "wasmallkatakana"},
+ {0x3357, "wattosquare"},
+ {0x301c, "wavedash"},
+ {0xfe34, "wavyunderscorevertical"},
+ {0x0648, "wawarabic"},
+ {0xfeee, "wawfinalarabic"},
+ {0x0624, "wawhamzaabovearabic"},
+ {0xfe86, "wawhamzaabovefinalarabic"},
+ {0x33dd, "wbsquare"},
+ {0x24e6, "wcircle"},
+ {0x0175, "wcircumflex"},
+ {0x1e85, "wdieresis"},
+ {0x1e87, "wdotaccent"},
+ {0x1e89, "wdotbelow"},
+ {0x3091, "wehiragana"},
+ {0x2118, "weierstrass"},
+ {0x30f1, "wekatakana"},
+ {0x315e, "wekorean"},
+ {0x315d, "weokorean"},
+ {0x1e81, "wgrave"},
+ {0x25e6, "whitebullet"},
+ {0x25cb, "whitecircle"},
+ {0x25d9, "whitecircleinverse"},
+ {0x300e, "whitecornerbracketleft"},
+ {0xfe43, "whitecornerbracketleftvertical"},
+ {0x300f, "whitecornerbracketright"},
+ {0xfe44, "whitecornerbracketrightvertical"},
+ {0x25c7, "whitediamond"},
+ {0x25c8, "whitediamondcontainingblacksmalldiamond"},
+ {0x25bf, "whitedownpointingsmalltriangle"},
+ {0x25bd, "whitedownpointingtriangle"},
+ {0x25c3, "whiteleftpointingsmalltriangle"},
+ {0x25c1, "whiteleftpointingtriangle"},
+ {0x3016, "whitelenticularbracketleft"},
+ {0x3017, "whitelenticularbracketright"},
+ {0x25b9, "whiterightpointingsmalltriangle"},
+ {0x25b7, "whiterightpointingtriangle"},
+ {0x25ab, "whitesmallsquare"},
+ {0x263a, "whitesmilingface"},
+ {0x25a1, "whitesquare"},
+ {0x2606, "whitestar"},
+ {0x260f, "whitetelephone"},
+ {0x3018, "whitetortoiseshellbracketleft"},
+ {0x3019, "whitetortoiseshellbracketright"},
+ {0x25b5, "whiteuppointingsmalltriangle"},
+ {0x25b3, "whiteuppointingtriangle"},
+ {0x3090, "wihiragana"},
+ {0x30f0, "wikatakana"},
+ {0x315f, "wikorean"},
+ {0xff57, "wmonospace"},
+ {0x3092, "wohiragana"},
+ {0x30f2, "wokatakana"},
+ {0xff66, "wokatakanahalfwidth"},
+ {0x20a9, "won"},
+ {0xffe6, "wonmonospace"},
+ {0x0e27, "wowaenthai"},
+ {0x24b2, "wparen"},
+ {0x1e98, "wring"},
+ {0x02b7, "wsuperior"},
+ {0x028d, "wturned"},
+ {0x01bf, "wynn"},
+ {0x0078, "x"},
+ {0x033d, "xabovecmb"},
+ {0x3112, "xbopomofo"},
+ {0x24e7, "xcircle"},
+ {0x1e8d, "xdieresis"},
+ {0x1e8b, "xdotaccent"},
+ {0x056d, "xeharmenian"},
+ {0x03be, "xi"},
+ {0xff58, "xmonospace"},
+ {0x24b3, "xparen"},
+ {0x02e3, "xsuperior"},
+ {0x0079, "y"},
+ {0x334e, "yaadosquare"},
+ {0x09af, "yabengali"},
+ {0x00fd, "yacute"},
+ {0x092f, "yadeva"},
+ {0x3152, "yaekorean"},
+ {0x0aaf, "yagujarati"},
+ {0x0a2f, "yagurmukhi"},
+ {0x3084, "yahiragana"},
+ {0x30e4, "yakatakana"},
+ {0xff94, "yakatakanahalfwidth"},
+ {0x3151, "yakorean"},
+ {0x0e4e, "yamakkanthai"},
+ {0x3083, "yasmallhiragana"},
+ {0x30e3, "yasmallkatakana"},
+ {0xff6c, "yasmallkatakanahalfwidth"},
+ {0x0463, "yatcyrillic"},
+ {0x24e8, "ycircle"},
+ {0x0177, "ycircumflex"},
+ {0x00ff, "ydieresis"},
+ {0x1e8f, "ydotaccent"},
+ {0x1ef5, "ydotbelow"},
+ {0x064a, "yeharabic"},
+ {0x06d2, "yehbarreearabic"},
+ {0xfbaf, "yehbarreefinalarabic"},
+ {0xfef2, "yehfinalarabic"},
+ {0x0626, "yehhamzaabovearabic"},
+ {0xfe8a, "yehhamzaabovefinalarabic"},
+ {0xfe8b, "yehhamzaaboveinitialarabic"},
+ {0xfe8c, "yehhamzaabovemedialarabic"},
+ {0xfef3, "yehinitialarabic"},
+ {0xfef4, "yehmedialarabic"},
+ {0xfcdd, "yehmeeminitialarabic"},
+ {0xfc58, "yehmeemisolatedarabic"},
+ {0xfc94, "yehnoonfinalarabic"},
+ {0x06d1, "yehthreedotsbelowarabic"},
+ {0x3156, "yekorean"},
+ {0x00a5, "yen"},
+ {0xffe5, "yenmonospace"},
+ {0x3155, "yeokorean"},
+ {0x3186, "yeorinhieuhkorean"},
+ {0x05aa, "yerahbenyomohebrew"},
+ {0x05aa, "yerahbenyomolefthebrew"},
+ {0x044b, "yericyrillic"},
+ {0x04f9, "yerudieresiscyrillic"},
+ {0x3181, "yesieungkorean"},
+ {0x3183, "yesieungpansioskorean"},
+ {0x3182, "yesieungsioskorean"},
+ {0x059a, "yetivhebrew"},
+ {0x1ef3, "ygrave"},
+ {0x01b4, "yhook"},
+ {0x1ef7, "yhookabove"},
+ {0x0575, "yiarmenian"},
+ {0x0457, "yicyrillic"},
+ {0x3162, "yikorean"},
+ {0x262f, "yinyang"},
+ {0x0582, "yiwnarmenian"},
+ {0xff59, "ymonospace"},
+ {0x05d9, "yod"},
+ {0xfb39, "yoddagesh"},
+ {0xfb39, "yoddageshhebrew"},
+ {0x05d9, "yodhebrew"},
+ {0x05f2, "yodyodhebrew"},
+ {0xfb1f, "yodyodpatahhebrew"},
+ {0x3088, "yohiragana"},
+ {0x3189, "yoikorean"},
+ {0x30e8, "yokatakana"},
+ {0xff96, "yokatakanahalfwidth"},
+ {0x315b, "yokorean"},
+ {0x3087, "yosmallhiragana"},
+ {0x30e7, "yosmallkatakana"},
+ {0xff6e, "yosmallkatakanahalfwidth"},
+ {0x03f3, "yotgreek"},
+ {0x3188, "yoyaekorean"},
+ {0x3187, "yoyakorean"},
+ {0x0e22, "yoyakthai"},
+ {0x0e0d, "yoyingthai"},
+ {0x24b4, "yparen"},
+ {0x037a, "ypogegrammeni"},
+ {0x0345, "ypogegrammenigreekcmb"},
+ {0x01a6, "yr"},
+ {0x1e99, "yring"},
+ {0x02b8, "ysuperior"},
+ {0x1ef9, "ytilde"},
+ {0x028e, "yturned"},
+ {0x3086, "yuhiragana"},
+ {0x318c, "yuikorean"},
+ {0x30e6, "yukatakana"},
+ {0xff95, "yukatakanahalfwidth"},
+ {0x3160, "yukorean"},
+ {0x046b, "yusbigcyrillic"},
+ {0x046d, "yusbigiotifiedcyrillic"},
+ {0x0467, "yuslittlecyrillic"},
+ {0x0469, "yuslittleiotifiedcyrillic"},
+ {0x3085, "yusmallhiragana"},
+ {0x30e5, "yusmallkatakana"},
+ {0xff6d, "yusmallkatakanahalfwidth"},
+ {0x318b, "yuyekorean"},
+ {0x318a, "yuyeokorean"},
+ {0x09df, "yyabengali"},
+ {0x095f, "yyadeva"},
+ {0x007a, "z"},
+ {0x0566, "zaarmenian"},
+ {0x017a, "zacute"},
+ {0x095b, "zadeva"},
+ {0x0a5b, "zagurmukhi"},
+ {0x0638, "zaharabic"},
+ {0xfec6, "zahfinalarabic"},
+ {0xfec7, "zahinitialarabic"},
+ {0x3056, "zahiragana"},
+ {0xfec8, "zahmedialarabic"},
+ {0x0632, "zainarabic"},
+ {0xfeb0, "zainfinalarabic"},
+ {0x30b6, "zakatakana"},
+ {0x0595, "zaqefgadolhebrew"},
+ {0x0594, "zaqefqatanhebrew"},
+ {0x0598, "zarqahebrew"},
+ {0x05d6, "zayin"},
+ {0xfb36, "zayindagesh"},
+ {0xfb36, "zayindageshhebrew"},
+ {0x05d6, "zayinhebrew"},
+ {0x3117, "zbopomofo"},
+ {0x017e, "zcaron"},
+ {0x24e9, "zcircle"},
+ {0x1e91, "zcircumflex"},
+ {0x0291, "zcurl"},
+ {0x017c, "zdot"},
+ {0x017c, "zdotaccent"},
+ {0x1e93, "zdotbelow"},
+ {0x0437, "zecyrillic"},
+ {0x0499, "zedescendercyrillic"},
+ {0x04df, "zedieresiscyrillic"},
+ {0x305c, "zehiragana"},
+ {0x30bc, "zekatakana"},
+ {0x0030, "zero"},
+ {0x0660, "zeroarabic"},
+ {0x09e6, "zerobengali"},
+ {0x0966, "zerodeva"},
+ {0x0ae6, "zerogujarati"},
+ {0x0a66, "zerogurmukhi"},
+ {0x0660, "zerohackarabic"},
+ {0x2080, "zeroinferior"},
+ {0xff10, "zeromonospace"},
+ {0xf730, "zerooldstyle"},
+ {0x06f0, "zeropersian"},
+ {0x2070, "zerosuperior"},
+ {0x0e50, "zerothai"},
+ {0xfeff, "zerowidthjoiner"},
+ {0x200c, "zerowidthnonjoiner"},
+ {0x200b, "zerowidthspace"},
+ {0x03b6, "zeta"},
+ {0x3113, "zhbopomofo"},
+ {0x056a, "zhearmenian"},
+ {0x04c2, "zhebrevecyrillic"},
+ {0x0436, "zhecyrillic"},
+ {0x0497, "zhedescendercyrillic"},
+ {0x04dd, "zhedieresiscyrillic"},
+ {0x3058, "zihiragana"},
+ {0x30b8, "zikatakana"},
+ {0x05ae, "zinorhebrew"},
+ {0x1e95, "zlinebelow"},
+ {0xff5a, "zmonospace"},
+ {0x305e, "zohiragana"},
+ {0x30be, "zokatakana"},
+ {0x24b5, "zparen"},
+ {0x0290, "zretroflexhook"},
+ {0x01b6, "zstroke"},
+ {0x305a, "zuhiragana"},
+ {0x30ba, "zukatakana"},
+ {0x007b, "{"},
+ {0x007c, "|"},
+ {0x007d, "}"},
+ {0x007e, "~"},
+ { 0, NULL }
+};
+
+// map ZapfDingbats names to Unicode
+static struct NameToUnicodeTab nameToUnicodeZapfDingbatsTab[] = {
+ {0x275e, "a100"},
+ {0x2761, "a101"},
+ {0x2762, "a102"},
+ {0x2763, "a103"},
+ {0x2764, "a104"},
+ {0x2710, "a105"},
+ {0x2765, "a106"},
+ {0x2766, "a107"},
+ {0x2767, "a108"},
+ {0x2660, "a109"},
+ {0x2721, "a10"},
+ {0x2665, "a110"},
+ {0x2666, "a111"},
+ {0x2663, "a112"},
+ {0x2709, "a117"},
+ {0x2708, "a118"},
+ {0x2707, "a119"},
+ {0x261b, "a11"},
+ {0x2460, "a120"},
+ {0x2461, "a121"},
+ {0x2462, "a122"},
+ {0x2463, "a123"},
+ {0x2464, "a124"},
+ {0x2465, "a125"},
+ {0x2466, "a126"},
+ {0x2467, "a127"},
+ {0x2468, "a128"},
+ {0x2469, "a129"},
+ {0x261e, "a12"},
+ {0x2776, "a130"},
+ {0x2777, "a131"},
+ {0x2778, "a132"},
+ {0x2779, "a133"},
+ {0x277a, "a134"},
+ {0x277b, "a135"},
+ {0x277c, "a136"},
+ {0x277d, "a137"},
+ {0x277e, "a138"},
+ {0x277f, "a139"},
+ {0x270c, "a13"},
+ {0x2780, "a140"},
+ {0x2781, "a141"},
+ {0x2782, "a142"},
+ {0x2783, "a143"},
+ {0x2784, "a144"},
+ {0x2785, "a145"},
+ {0x2786, "a146"},
+ {0x2787, "a147"},
+ {0x2788, "a148"},
+ {0x2789, "a149"},
+ {0x270d, "a14"},
+ {0x278a, "a150"},
+ {0x278b, "a151"},
+ {0x278c, "a152"},
+ {0x278d, "a153"},
+ {0x278e, "a154"},
+ {0x278f, "a155"},
+ {0x2790, "a156"},
+ {0x2791, "a157"},
+ {0x2792, "a158"},
+ {0x2793, "a159"},
+ {0x270e, "a15"},
+ {0x2794, "a160"},
+ {0x2192, "a161"},
+ {0x27a3, "a162"},
+ {0x2194, "a163"},
+ {0x2195, "a164"},
+ {0x2799, "a165"},
+ {0x279b, "a166"},
+ {0x279c, "a167"},
+ {0x279d, "a168"},
+ {0x279e, "a169"},
+ {0x270f, "a16"},
+ {0x279f, "a170"},
+ {0x27a0, "a171"},
+ {0x27a1, "a172"},
+ {0x27a2, "a173"},
+ {0x27a4, "a174"},
+ {0x27a5, "a175"},
+ {0x27a6, "a176"},
+ {0x27a7, "a177"},
+ {0x27a8, "a178"},
+ {0x27a9, "a179"},
+ {0x2711, "a17"},
+ {0x27ab, "a180"},
+ {0x27ad, "a181"},
+ {0x27af, "a182"},
+ {0x27b2, "a183"},
+ {0x27b3, "a184"},
+ {0x27b5, "a185"},
+ {0x27b8, "a186"},
+ {0x27ba, "a187"},
+ {0x27bb, "a188"},
+ {0x27bc, "a189"},
+ {0x2712, "a18"},
+ {0x27bd, "a190"},
+ {0x27be, "a191"},
+ {0x279a, "a192"},
+ {0x27aa, "a193"},
+ {0x27b6, "a194"},
+ {0x27b9, "a195"},
+ {0x2798, "a196"},
+ {0x27b4, "a197"},
+ {0x27b7, "a198"},
+ {0x27ac, "a199"},
+ {0x2713, "a19"},
+ {0x2701, "a1"},
+ {0x27ae, "a200"},
+ {0x27b1, "a201"},
+ {0x2703, "a202"},
+ {0x2750, "a203"},
+ {0x2752, "a204"},
+ {0x276e, "a205"},
+ {0x2770, "a206"},
+ {0x2714, "a20"},
+ {0x2715, "a21"},
+ {0x2716, "a22"},
+ {0x2717, "a23"},
+ {0x2718, "a24"},
+ {0x2719, "a25"},
+ {0x271a, "a26"},
+ {0x271b, "a27"},
+ {0x271c, "a28"},
+ {0x2722, "a29"},
+ {0x2702, "a2"},
+ {0x2723, "a30"},
+ {0x2724, "a31"},
+ {0x2725, "a32"},
+ {0x2726, "a33"},
+ {0x2727, "a34"},
+ {0x2605, "a35"},
+ {0x2729, "a36"},
+ {0x272a, "a37"},
+ {0x272b, "a38"},
+ {0x272c, "a39"},
+ {0x2704, "a3"},
+ {0x272d, "a40"},
+ {0x272e, "a41"},
+ {0x272f, "a42"},
+ {0x2730, "a43"},
+ {0x2731, "a44"},
+ {0x2732, "a45"},
+ {0x2733, "a46"},
+ {0x2734, "a47"},
+ {0x2735, "a48"},
+ {0x2736, "a49"},
+ {0x260e, "a4"},
+ {0x2737, "a50"},
+ {0x2738, "a51"},
+ {0x2739, "a52"},
+ {0x273a, "a53"},
+ {0x273b, "a54"},
+ {0x273c, "a55"},
+ {0x273d, "a56"},
+ {0x273e, "a57"},
+ {0x273f, "a58"},
+ {0x2740, "a59"},
+ {0x2706, "a5"},
+ {0x2741, "a60"},
+ {0x2742, "a61"},
+ {0x2743, "a62"},
+ {0x2744, "a63"},
+ {0x2745, "a64"},
+ {0x2746, "a65"},
+ {0x2747, "a66"},
+ {0x2748, "a67"},
+ {0x2749, "a68"},
+ {0x274a, "a69"},
+ {0x271d, "a6"},
+ {0x274b, "a70"},
+ {0x25cf, "a71"},
+ {0x274d, "a72"},
+ {0x25a0, "a73"},
+ {0x274f, "a74"},
+ {0x2751, "a75"},
+ {0x25b2, "a76"},
+ {0x25bc, "a77"},
+ {0x25c6, "a78"},
+ {0x2756, "a79"},
+ {0x271e, "a7"},
+ {0x25d7, "a81"},
+ {0x2758, "a82"},
+ {0x2759, "a83"},
+ {0x275a, "a84"},
+ {0x276f, "a85"},
+ {0x2771, "a86"},
+ {0x2772, "a87"},
+ {0x2773, "a88"},
+ {0x2768, "a89"},
+ {0x271f, "a8"},
+ {0x2769, "a90"},
+ {0x276c, "a91"},
+ {0x276d, "a92"},
+ {0x276a, "a93"},
+ {0x276b, "a94"},
+ {0x2774, "a95"},
+ {0x2775, "a96"},
+ {0x275b, "a97"},
+ {0x275c, "a98"},
+ {0x275d, "a99"},
+ {0x2720, "a9"},
+ { 0, NULL }
+};
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Object.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Object.cc
new file mode 100644
index 00000000000..d06bb39fb6d
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Object.cc
@@ -0,0 +1,252 @@
+//========================================================================
+//
+// Object.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008, 2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Error.h"
+#include "Stream.h"
+#include "XRef.h"
+
+//------------------------------------------------------------------------
+// Object
+//------------------------------------------------------------------------
+
+static const char *objTypeNames[numObjTypes] = {
+ "boolean",
+ "integer",
+ "real",
+ "string",
+ "name",
+ "null",
+ "array",
+ "dictionary",
+ "stream",
+ "ref",
+ "cmd",
+ "error",
+ "eof",
+ "none",
+ "integer64"
+};
+
+#ifdef DEBUG_MEM
+int Object::numAlloc[numObjTypes] =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#endif
+
+Object *Object::initArray(XRef *xref) {
+ initObj(objArray);
+ array = new Array(xref);
+ return this;
+}
+
+Object *Object::initDict(XRef *xref) {
+ initObj(objDict);
+ dict = new Dict(xref);
+ return this;
+}
+
+Object *Object::initDict(Dict *dictA) {
+ initObj(objDict);
+ dict = dictA;
+ dict->incRef();
+ return this;
+}
+
+Object *Object::initStream(Stream *streamA) {
+ initObj(objStream);
+ stream = streamA;
+ return this;
+}
+
+Object *Object::copy(Object *obj) {
+ *obj = *this;
+ switch (type) {
+ case objString:
+ obj->string = string->copy();
+ break;
+ case objName:
+ obj->name = copyString(name);
+ break;
+ case objArray:
+ array->incRef();
+ break;
+ case objDict:
+ dict->incRef();
+ break;
+ case objStream:
+ stream->incRef();
+ break;
+ case objCmd:
+ obj->cmd = copyString(cmd);
+ break;
+ default:
+ break;
+ }
+#ifdef DEBUG_MEM
+ ++numAlloc[type];
+#endif
+ return obj;
+}
+
+Object *Object::fetch(XRef *xref, Object *obj, int recursion) {
+ return (type == objRef && xref) ?
+ xref->fetch(ref.num, ref.gen, obj, recursion) : copy(obj);
+}
+
+void Object::free() {
+ switch (type) {
+ case objString:
+ delete string;
+ break;
+ case objName:
+ gfree(name);
+ break;
+ case objArray:
+ if (!array->decRef()) {
+ delete array;
+ }
+ break;
+ case objDict:
+ if (!dict->decRef()) {
+ delete dict;
+ }
+ break;
+ case objStream:
+ if (!stream->decRef()) {
+ delete stream;
+ }
+ break;
+ case objCmd:
+ gfree(cmd);
+ break;
+ default:
+ break;
+ }
+#ifdef DEBUG_MEM
+ --numAlloc[type];
+#endif
+ type = objNone;
+}
+
+const char *Object::getTypeName() {
+ return objTypeNames[type];
+}
+
+void Object::print(FILE *f) {
+ Object obj;
+ int i;
+
+ switch (type) {
+ case objBool:
+ fprintf(f, "%s", booln ? "true" : "false");
+ break;
+ case objInt:
+ fprintf(f, "%d", intg);
+ break;
+ case objReal:
+ fprintf(f, "%g", real);
+ break;
+ case objString:
+ fprintf(f, "(");
+ fwrite(string->getCString(), 1, string->getLength(), f);
+ fprintf(f, ")");
+ break;
+ case objName:
+ fprintf(f, "/%s", name);
+ break;
+ case objNull:
+ fprintf(f, "null");
+ break;
+ case objArray:
+ fprintf(f, "[");
+ for (i = 0; i < arrayGetLength(); ++i) {
+ if (i > 0)
+ fprintf(f, " ");
+ arrayGetNF(i, &obj);
+ obj.print(f);
+ obj.free();
+ }
+ fprintf(f, "]");
+ break;
+ case objDict:
+ fprintf(f, "<<");
+ for (i = 0; i < dictGetLength(); ++i) {
+ fprintf(f, " /%s ", dictGetKey(i));
+ dictGetValNF(i, &obj);
+ obj.print(f);
+ obj.free();
+ }
+ fprintf(f, " >>");
+ break;
+ case objStream:
+ fprintf(f, "<stream>");
+ break;
+ case objRef:
+ fprintf(f, "%d %d R", ref.num, ref.gen);
+ break;
+ case objCmd:
+ fprintf(f, "%s", cmd);
+ break;
+ case objError:
+ fprintf(f, "<error>");
+ break;
+ case objEOF:
+ fprintf(f, "<EOF>");
+ break;
+ case objNone:
+ fprintf(f, "<none>");
+ break;
+ case objInt64:
+ fprintf(f, "%lld", int64g);
+ break;
+ }
+}
+
+void Object::memCheck(FILE *f) {
+#ifdef DEBUG_MEM
+ int i;
+ int t;
+
+ t = 0;
+ for (i = 0; i < numObjTypes; ++i)
+ t += numAlloc[i];
+ if (t > 0) {
+ fprintf(f, "Allocated objects:\n");
+ for (i = 0; i < numObjTypes; ++i) {
+ if (numAlloc[i] > 0)
+ fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]);
+ }
+ }
+#else
+ (void)f;
+#endif
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Object.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Object.h
new file mode 100644
index 00000000000..2a3766288a6
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Object.h
@@ -0,0 +1,373 @@
+//========================================================================
+//
+// Object.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2008 Kees Cook <kees@outflux.net>
+// Copyright (C) 2008, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Jakub Wilk <jwilk@jwilk.net>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef OBJECT_H
+#define OBJECT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <set>
+#include <stdio.h>
+#include <string.h>
+#include "goo/gtypes.h"
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "goo/GooLikely.h"
+#include "Error.h"
+
+#define OBJECT_TYPE_CHECK(wanted_type) \
+ if (unlikely(type != wanted_type)) { \
+ error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
+ "not the expected type {1:d}", type, wanted_type); \
+ abort(); \
+ }
+
+#define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3) \
+ if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) { \
+ error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
+ "not the expected type {1:d}, {2:d} or {3:d}", type, wanted_type1, wanted_type2, wanted_type3); \
+ abort(); \
+ }
+
+class XRef;
+class Array;
+class Dict;
+class Stream;
+
+//------------------------------------------------------------------------
+// Ref
+//------------------------------------------------------------------------
+
+struct Ref {
+ int num; // object number
+ int gen; // generation number
+};
+
+//------------------------------------------------------------------------
+// object types
+//------------------------------------------------------------------------
+
+enum ObjType {
+ // simple objects
+ objBool, // boolean
+ objInt, // integer
+ objReal, // real
+ objString, // string
+ objName, // name
+ objNull, // null
+
+ // complex objects
+ objArray, // array
+ objDict, // dictionary
+ objStream, // stream
+ objRef, // indirect reference
+
+ // special objects
+ objCmd, // command name
+ objError, // error return from Lexer
+ objEOF, // end of file return from Lexer
+ objNone, // uninitialized object
+
+ // poppler-only objects
+ objInt64 // integer with at least 64-bits
+};
+
+#define numObjTypes 15 // total number of object types
+
+//------------------------------------------------------------------------
+// Object
+//------------------------------------------------------------------------
+
+#ifdef DEBUG_MEM
+#define initObj(t) zeroUnion(); ++numAlloc[type = t]
+#else
+#define initObj(t) zeroUnion(); type = t
+#endif
+
+class Object {
+public:
+ // clear the anonymous union as best we can -- clear at least a pointer
+ void zeroUnion() { this->name = NULL; }
+
+ // Default constructor.
+ Object():
+ type(objNone) { zeroUnion(); }
+
+ // Initialize an object.
+ Object *initBool(GBool boolnA)
+ { initObj(objBool); booln = boolnA; return this; }
+ Object *initInt(int intgA)
+ { initObj(objInt); intg = intgA; return this; }
+ Object *initReal(double realA)
+ { initObj(objReal); real = realA; return this; }
+ Object *initString(GooString *stringA)
+ { initObj(objString); string = stringA; return this; }
+ Object *initName(const char *nameA)
+ { initObj(objName); name = copyString(nameA); return this; }
+ Object *initNull()
+ { initObj(objNull); return this; }
+ Object *initArray(XRef *xref);
+ Object *initDict(XRef *xref);
+ Object *initDict(Dict *dictA);
+ Object *initStream(Stream *streamA);
+ Object *initRef(int numA, int genA)
+ { initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
+ Object *initCmd(const char *cmdA)
+ { initObj(objCmd); cmd = copyString(cmdA); return this; }
+ Object *initError()
+ { initObj(objError); return this; }
+ Object *initEOF()
+ { initObj(objEOF); return this; }
+ Object *initInt64(long long int64gA)
+ { initObj(objInt64); int64g = int64gA; return this; }
+
+ // Copy an object.
+ Object *copy(Object *obj);
+ Object *shallowCopy(Object *obj) {
+ *obj = *this;
+ return obj;
+ }
+
+ // If object is a Ref, fetch and return the referenced object.
+ // Otherwise, return a copy of the object.
+ Object *fetch(XRef *xref, Object *obj, int recursion = 0);
+
+ // Free object contents.
+ void free();
+
+ // Type checking.
+ ObjType getType() { return type; }
+ GBool isBool() { return type == objBool; }
+ GBool isInt() { return type == objInt; }
+ GBool isReal() { return type == objReal; }
+ GBool isNum() { return type == objInt || type == objReal || type == objInt64; }
+ GBool isString() { return type == objString; }
+ GBool isName() { return type == objName; }
+ GBool isNull() { return type == objNull; }
+ GBool isArray() { return type == objArray; }
+ GBool isDict() { return type == objDict; }
+ GBool isStream() { return type == objStream; }
+ GBool isRef() { return type == objRef; }
+ GBool isCmd() { return type == objCmd; }
+ GBool isError() { return type == objError; }
+ GBool isEOF() { return type == objEOF; }
+ GBool isNone() { return type == objNone; }
+ GBool isInt64() { return type == objInt64; }
+
+ // Special type checking.
+ GBool isName(const char *nameA)
+ { return type == objName && !strcmp(name, nameA); }
+ GBool isDict(const char *dictType);
+ GBool isStream(const char *dictType);
+ GBool isCmd(const char *cmdA)
+ { return type == objCmd && !strcmp(cmd, cmdA); }
+
+ // Accessors.
+ GBool getBool() { OBJECT_TYPE_CHECK(objBool); return booln; }
+ int getInt() { OBJECT_TYPE_CHECK(objInt); return intg; }
+ double getReal() { OBJECT_TYPE_CHECK(objReal); return real; }
+
+ // Note: integers larger than 2^53 can not be exactly represented by a double.
+ // Where the exact value of integers up to 2^63 is required, use isInt64()/getInt64().
+ double getNum() { OBJECT_3TYPES_CHECK(objInt, objInt64, objReal);
+ return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real; }
+ GooString *getString() { OBJECT_TYPE_CHECK(objString); return string; }
+ // After takeString() the only method that should be called for the object is free()
+ // because the object it's not expected to have a NULL string.
+ GooString *takeString() {
+ OBJECT_TYPE_CHECK(objString); GooString *s = string; string = NULL; return s; }
+ char *getName() { OBJECT_TYPE_CHECK(objName); return name; }
+ Array *getArray() { OBJECT_TYPE_CHECK(objArray); return array; }
+ Dict *getDict() { OBJECT_TYPE_CHECK(objDict); return dict; }
+ Stream *getStream() { OBJECT_TYPE_CHECK(objStream); return stream; }
+ Ref getRef() { OBJECT_TYPE_CHECK(objRef); return ref; }
+ int getRefNum() { OBJECT_TYPE_CHECK(objRef); return ref.num; }
+ int getRefGen() { OBJECT_TYPE_CHECK(objRef); return ref.gen; }
+ char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cmd; }
+ long long getInt64() { OBJECT_TYPE_CHECK(objInt64); return int64g; }
+
+ // Array accessors.
+ int arrayGetLength();
+ void arrayAdd(Object *elem);
+ void arrayRemove(int i);
+ Object *arrayGet(int i, Object *obj, int recursion);
+ Object *arrayGetNF(int i, Object *obj);
+
+ // Dict accessors.
+ int dictGetLength();
+ void dictAdd(char *key, Object *val);
+ void dictSet(const char *key, Object *val);
+ GBool dictIs(const char *dictType);
+ Object *dictLookup(const char *key, Object *obj, int recursion = 0);
+ Object *dictLookupNF(const char *key, Object *obj);
+ char *dictGetKey(int i);
+ Object *dictGetVal(int i, Object *obj);
+ Object *dictGetValNF(int i, Object *obj);
+
+ // Stream accessors.
+ GBool streamIs(const char *dictType);
+ void streamReset();
+ void streamClose();
+ int streamGetChar();
+ int streamGetChars(int nChars, Guchar *buffer);
+ int streamLookChar();
+ char *streamGetLine(char *buf, int size);
+ Goffset streamGetPos();
+ void streamSetPos(Goffset pos, int dir = 0);
+ Dict *streamGetDict();
+
+ // Output.
+ const char *getTypeName();
+ void print(FILE *f = stdout);
+
+ // Memory testing.
+ static void memCheck(FILE *f);
+
+private:
+
+ ObjType type; // object type
+ union { // value for each type:
+ GBool booln; // boolean
+ int intg; // integer
+ long long int64g; // 64-bit integer
+ double real; // real
+ GooString *string; // string
+ char *name; // name
+ Array *array; // array
+ Dict *dict; // dictionary
+ Stream *stream; // stream
+ Ref ref; // indirect reference
+ char *cmd; // command
+ };
+
+#ifdef DEBUG_MEM
+ static int // number of each type of object
+ numAlloc[numObjTypes]; // currently allocated
+#endif
+};
+
+//------------------------------------------------------------------------
+// Array accessors.
+//------------------------------------------------------------------------
+
+#include "Array.h"
+
+inline int Object::arrayGetLength()
+ { OBJECT_TYPE_CHECK(objArray); return array->getLength(); }
+
+inline void Object::arrayAdd(Object *elem)
+ { OBJECT_TYPE_CHECK(objArray); array->add(elem); }
+
+inline void Object::arrayRemove(int i)
+ { OBJECT_TYPE_CHECK(objArray); array->remove(i); }
+
+inline Object *Object::arrayGet(int i, Object *obj, int recursion = 0)
+ { OBJECT_TYPE_CHECK(objArray); return array->get(i, obj, recursion); }
+
+inline Object *Object::arrayGetNF(int i, Object *obj)
+ { OBJECT_TYPE_CHECK(objArray); return array->getNF(i, obj); }
+
+//------------------------------------------------------------------------
+// Dict accessors.
+//------------------------------------------------------------------------
+
+#include "Dict.h"
+
+inline int Object::dictGetLength()
+ { OBJECT_TYPE_CHECK(objDict); return dict->getLength(); }
+
+inline void Object::dictAdd(char *key, Object *val)
+ { OBJECT_TYPE_CHECK(objDict); dict->add(key, val); }
+
+inline void Object::dictSet(const char *key, Object *val)
+ { OBJECT_TYPE_CHECK(objDict); dict->set(key, val); }
+
+inline GBool Object::dictIs(const char *dictType)
+ { OBJECT_TYPE_CHECK(objDict); return dict->is(dictType); }
+
+inline GBool Object::isDict(const char *dictType)
+ { return type == objDict && dictIs(dictType); }
+
+inline Object *Object::dictLookup(const char *key, Object *obj, int recursion)
+ { OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, obj, recursion); }
+
+inline Object *Object::dictLookupNF(const char *key, Object *obj)
+ { OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key, obj); }
+
+inline char *Object::dictGetKey(int i)
+ { OBJECT_TYPE_CHECK(objDict); return dict->getKey(i); }
+
+inline Object *Object::dictGetVal(int i, Object *obj)
+ { OBJECT_TYPE_CHECK(objDict); return dict->getVal(i, obj); }
+
+inline Object *Object::dictGetValNF(int i, Object *obj)
+ { OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i, obj); }
+
+//------------------------------------------------------------------------
+// Stream accessors.
+//------------------------------------------------------------------------
+
+#include "Stream.h"
+
+inline GBool Object::streamIs(const char *dictType)
+ { OBJECT_TYPE_CHECK(objStream); return stream->getDict()->is(dictType); }
+
+inline GBool Object::isStream(const char *dictType)
+ { return type == objStream && streamIs(dictType); }
+
+inline void Object::streamReset()
+ { OBJECT_TYPE_CHECK(objStream); stream->reset(); }
+
+inline void Object::streamClose()
+ { OBJECT_TYPE_CHECK(objStream); stream->close(); }
+
+inline int Object::streamGetChar()
+ { OBJECT_TYPE_CHECK(objStream); return stream->getChar(); }
+
+inline int Object::streamGetChars(int nChars, Guchar *buffer)
+ { OBJECT_TYPE_CHECK(objStream); return stream->doGetChars(nChars, buffer); }
+
+inline int Object::streamLookChar()
+ { OBJECT_TYPE_CHECK(objStream); return stream->lookChar(); }
+
+inline char *Object::streamGetLine(char *buf, int size)
+ { OBJECT_TYPE_CHECK(objStream); return stream->getLine(buf, size); }
+
+inline Goffset Object::streamGetPos()
+ { OBJECT_TYPE_CHECK(objStream); return stream->getPos(); }
+
+inline void Object::streamSetPos(Goffset pos, int dir)
+ { OBJECT_TYPE_CHECK(objStream); stream->setPos(pos, dir); }
+
+inline Dict *Object::streamGetDict()
+ { OBJECT_TYPE_CHECK(objStream); return stream->getDict(); }
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/OptionalContent.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/OptionalContent.cc
new file mode 100644
index 00000000000..e0d49bc9a5f
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/OptionalContent.cc
@@ -0,0 +1,553 @@
+//========================================================================
+//
+// OptionalContent.cc
+//
+// Copyright 2007 Brad Hards <bradh@kde.org>
+// Copyright 2008 Pino Toscano <pino@kde.org>
+// Copyright 2008, 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright 2008, 2010, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright 2008 Mark Kaplan <mkaplan@finjan.com>
+//
+// Released under the GPL (version 2, or later, at your option)
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "goo/GooList.h"
+#include "Error.h"
+// #include "PDFDocEncoding.h"
+#include "OptionalContent.h"
+
+// Max depth of nested visibility expressions. This is used to catch
+// infinite loops in the visibility expression object structure.
+#define visibilityExprRecursionLimit 50
+
+// Max depth of nested display nodes. This is used to catch infinite
+// loops in the "Order" object structure.
+#define displayNodeRecursionLimit 50
+
+//------------------------------------------------------------------------
+
+OCGs::OCGs(Object *ocgObject, XRef *xref) :
+ m_xref(xref)
+{
+ // we need to parse the dictionary here, and build optionalContentGroups
+ ok = gTrue;
+ optionalContentGroups = new GooList();
+ display = NULL;
+
+ Object ocgList;
+ ocgObject->dictLookup("OCGs", &ocgList);
+ if (!ocgList.isArray()) {
+ error(errSyntaxError, -1, "Expected the optional content group list, but wasn't able to find it, or it isn't an Array");
+ ocgList.free();
+ ok = gFalse;
+ return;
+ }
+
+ // we now enumerate over the ocgList, and build up the optionalContentGroups list.
+ for(int i = 0; i < ocgList.arrayGetLength(); ++i) {
+ Object ocg;
+ ocgList.arrayGet(i, &ocg);
+ if (!ocg.isDict()) {
+ ocg.free();
+ break;
+ }
+ OptionalContentGroup *thisOptionalContentGroup = new OptionalContentGroup(ocg.getDict());
+ ocg.free();
+ ocgList.arrayGetNF(i, &ocg);
+ // TODO: we should create a lookup map from Ref to the OptionalContentGroup
+ thisOptionalContentGroup->setRef( ocg.getRef() );
+ ocg.free();
+ // the default is ON - we change state later, depending on BaseState, ON and OFF
+ thisOptionalContentGroup->setState(OptionalContentGroup::On);
+ optionalContentGroups->append(thisOptionalContentGroup);
+ }
+
+ Object defaultOcgConfig;
+ ocgObject->dictLookup("D", &defaultOcgConfig);
+ if (!defaultOcgConfig.isDict()) {
+ error(errSyntaxError, -1, "Expected the default config, but wasn't able to find it, or it isn't a Dictionary");
+ defaultOcgConfig.free();
+ ocgList.free();
+ ok = gFalse;
+ return;
+ }
+
+ Object baseState;
+ defaultOcgConfig.dictLookup("BaseState", &baseState);
+ if (baseState.isName("OFF")) {
+ for (int i = 0; i < optionalContentGroups->getLength(); ++i) {
+ OptionalContentGroup *group;
+
+ group = (OptionalContentGroup *)optionalContentGroups->get(i);
+ group->setState(OptionalContentGroup::Off);
+ }
+ }
+ baseState.free();
+
+ Object on;
+ defaultOcgConfig.dictLookup("ON", &on);
+ if (on.isArray()) {
+ // ON is an optional element
+ for (int i = 0; i < on.arrayGetLength(); ++i) {
+ Object reference;
+ on.arrayGetNF(i, &reference);
+ if (!reference.isRef()) {
+ // there can be null entries
+ reference.free();
+ break;
+ }
+ OptionalContentGroup *group = findOcgByRef( reference.getRef() );
+ reference.free();
+ if (!group) {
+ error(errSyntaxWarning, -1, "Couldn't find group for reference");
+ break;
+ }
+ group->setState(OptionalContentGroup::On);
+ }
+ }
+ on.free();
+
+ Object off;
+ defaultOcgConfig.dictLookup("OFF", &off);
+ if (off.isArray()) {
+ // OFF is an optional element
+ for (int i = 0; i < off.arrayGetLength(); ++i) {
+ Object reference;
+ off.arrayGetNF(i, &reference);
+ if (!reference.isRef()) {
+ // there can be null entries
+ reference.free();
+ break;
+ }
+ OptionalContentGroup *group = findOcgByRef( reference.getRef() );
+ reference.free();
+ if (!group) {
+ error(errSyntaxWarning, -1, "Couldn't find group for reference to set OFF");
+ break;
+ }
+ group->setState(OptionalContentGroup::Off);
+ }
+ }
+ off.free();
+
+ defaultOcgConfig.dictLookup("Order", &order);
+ defaultOcgConfig.dictLookup("RBGroups", &rbgroups);
+
+ ocgList.free();
+ defaultOcgConfig.free();
+}
+
+OCGs::~OCGs()
+{
+ deleteGooList(optionalContentGroups, OptionalContentGroup);
+ order.free();
+ if (display)
+ delete display;
+ rbgroups.free();
+}
+
+
+bool OCGs::hasOCGs()
+{
+ return ( optionalContentGroups->getLength() > 0 );
+}
+
+OptionalContentGroup* OCGs::findOcgByRef( const Ref &ref)
+{
+ //TODO: make this more efficient
+ OptionalContentGroup *ocg = NULL;
+ for (int i=0; i < optionalContentGroups->getLength(); ++i) {
+ ocg = (OptionalContentGroup*)optionalContentGroups->get(i);
+ if ( (ocg->getRef().num == ref.num) && (ocg->getRef().gen == ref.gen) ) {
+ return ocg;
+ }
+ }
+
+ // not found
+ return NULL;
+}
+
+OCDisplayNode *OCGs::getDisplayRoot()
+{
+ if (display)
+ return display;
+
+ if (order.isArray())
+ display = OCDisplayNode::parse(&order, this, m_xref);
+
+ return display;
+}
+
+bool OCGs::optContentIsVisible( Object *dictRef )
+{
+ Object dictObj;
+ Dict *dict;
+ Object dictType;
+ Object ocg;
+ Object policy;
+ Object ve;
+ bool result = true;
+
+ if (dictRef->isNull())
+ return result;
+
+ if (dictRef->isRef()) {
+ OptionalContentGroup *oc = findOcgByRef(dictRef->getRef());
+ if (oc)
+ return oc->getState() == OptionalContentGroup::On;
+ }
+
+ dictRef->fetch( m_xref, &dictObj );
+ if ( ! dictObj.isDict() ) {
+ error(errSyntaxWarning, -1, "Unexpected oc reference target: {0:d}", dictObj.getType() );
+ dictObj.free();
+ return result;
+ }
+ dict = dictObj.getDict();
+ // printf("checking if optContent is visible\n");
+ dict->lookup("Type", &dictType);
+ if (dictType.isName("OCMD")) {
+ if (dict->lookup("VE", &ve)->isArray()) {
+ result = evalOCVisibilityExpr(&ve, 0);
+ } else {
+ dict->lookupNF("OCGs", &ocg);
+ if (ocg.isArray()) {
+ dict->lookup("P", &policy);
+ if (policy.isName("AllOn")) {
+ result = allOn( ocg.getArray() );
+ } else if (policy.isName("AllOff")) {
+ result = allOff( ocg.getArray() );
+ } else if (policy.isName("AnyOff")) {
+ result = anyOff( ocg.getArray() );
+ } else if ( (!policy.isName()) || (policy.isName("AnyOn") ) ) {
+ // this is the default
+ result = anyOn( ocg.getArray() );
+ }
+ policy.free();
+ } else if (ocg.isRef()) {
+ OptionalContentGroup *oc = findOcgByRef( ocg.getRef() );
+ if ( oc && oc->getState() == OptionalContentGroup::Off ) {
+ result = false;
+ } else {
+ result = true ;
+ }
+ }
+ ocg.free();
+ }
+ ve.free();
+ } else if ( dictType.isName("OCG") ) {
+ OptionalContentGroup* oc = findOcgByRef( dictRef->getRef() );
+ if ( oc && oc->getState() == OptionalContentGroup::Off ) {
+ result=false;
+ }
+ }
+ dictType.free();
+ dictObj.free();
+ // printf("visibility: %s\n", result? "on" : "off");
+ return result;
+}
+
+GBool OCGs::evalOCVisibilityExpr(Object *expr, int recursion) {
+ OptionalContentGroup *ocg;
+ Object expr2, op, obj;
+ GBool ret;
+ int i;
+
+ if (recursion > visibilityExprRecursionLimit) {
+ error(errSyntaxError, -1,
+ "Loop detected in optional content visibility expression");
+ return gTrue;
+ }
+ if (expr->isRef()) {
+ if ((ocg = findOcgByRef(expr->getRef()))) {
+ return ocg->getState() == OptionalContentGroup::On;
+ }
+ }
+ expr->fetch(m_xref, &expr2);
+ if (!expr2.isArray() || expr2.arrayGetLength() < 1) {
+ error(errSyntaxError, -1,
+ "Invalid optional content visibility expression");
+ expr2.free();
+ return gTrue;
+ }
+ expr2.arrayGet(0, &op);
+ if (op.isName("Not")) {
+ if (expr2.arrayGetLength() == 2) {
+ expr2.arrayGetNF(1, &obj);
+ ret = !evalOCVisibilityExpr(&obj, recursion + 1);
+ obj.free();
+ } else {
+ error(errSyntaxError, -1,
+ "Invalid optional content visibility expression");
+ ret = gTrue;
+ }
+ } else if (op.isName("And")) {
+ ret = gTrue;
+ for (i = 1; i < expr2.arrayGetLength() && ret; ++i) {
+ expr2.arrayGetNF(i, &obj);
+ ret = evalOCVisibilityExpr(&obj, recursion + 1);
+ obj.free();
+ }
+ } else if (op.isName("Or")) {
+ ret = gFalse;
+ for (i = 1; i < expr2.arrayGetLength() && !ret; ++i) {
+ expr2.arrayGetNF(i, &obj);
+ ret = evalOCVisibilityExpr(&obj, recursion + 1);
+ obj.free();
+ }
+ } else {
+ error(errSyntaxError, -1,
+ "Invalid optional content visibility expression");
+ ret = gTrue;
+ }
+ op.free();
+ expr2.free();
+ return ret;
+}
+
+bool OCGs::allOn( Array *ocgArray )
+{
+ for (int i = 0; i < ocgArray->getLength(); ++i) {
+ Object ocgItem;
+ ocgArray->getNF(i, &ocgItem);
+ if (ocgItem.isRef()) {
+ OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );
+ if ( oc && oc->getState() == OptionalContentGroup::Off ) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool OCGs::allOff( Array *ocgArray )
+{
+ for (int i = 0; i < ocgArray->getLength(); ++i) {
+ Object ocgItem;
+ ocgArray->getNF(i, &ocgItem);
+ if (ocgItem.isRef()) {
+ OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );
+ if ( oc && oc->getState() == OptionalContentGroup::On ) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool OCGs::anyOn( Array *ocgArray )
+{
+ for (int i = 0; i < ocgArray->getLength(); ++i) {
+ Object ocgItem;
+ ocgArray->getNF(i, &ocgItem);
+ if (ocgItem.isRef()) {
+ OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );
+ if ( oc && oc->getState() == OptionalContentGroup::On ) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool OCGs::anyOff( Array *ocgArray )
+{
+ for (int i = 0; i < ocgArray->getLength(); ++i) {
+ Object ocgItem;
+ ocgArray->getNF(i, &ocgItem);
+ if (ocgItem.isRef()) {
+ OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );
+ if ( oc && oc->getState() == OptionalContentGroup::Off ) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//------------------------------------------------------------------------
+
+OptionalContentGroup::OptionalContentGroup(Dict *ocgDict) : m_name(NULL)
+{
+ Object obj1, obj2, obj3;
+ Object ocgName;
+ ocgDict->lookup("Name", &ocgName);
+ if (!ocgName.isString()) {
+ error(errSyntaxWarning, -1, "Expected the name of the OCG, but wasn't able to find it, or it isn't a String");
+ } else {
+ m_name = new GooString( ocgName.getString() );
+ }
+ ocgName.free();
+
+ viewState = printState = ocUsageUnset;
+ if (ocgDict->lookup("Usage", &obj1)->isDict()) {
+ if (obj1.dictLookup("View", &obj2)->isDict()) {
+ if (obj2.dictLookup("ViewState", &obj3)->isName()) {
+ if (obj3.isName("ON")) {
+ viewState = ocUsageOn;
+ } else {
+ viewState = ocUsageOff;
+ }
+ }
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Print", &obj2)->isDict()) {
+ if (obj2.dictLookup("PrintState", &obj3)->isName()) {
+ if (obj3.isName("ON")) {
+ printState = ocUsageOn;
+ } else {
+ printState = ocUsageOff;
+ }
+ }
+ obj3.free();
+ }
+ obj2.free();
+ }
+ obj1.free();
+}
+
+OptionalContentGroup::OptionalContentGroup(GooString *label)
+{
+ m_name = label;
+ m_state = On;
+}
+
+GooString* OptionalContentGroup::getName() const
+{
+ return m_name;
+}
+
+void OptionalContentGroup::setRef(const Ref ref)
+{
+ m_ref = ref;
+}
+
+Ref OptionalContentGroup::getRef() const
+{
+ return m_ref;
+}
+
+OptionalContentGroup::~OptionalContentGroup()
+{
+ delete m_name;
+}
+
+//------------------------------------------------------------------------
+
+OCDisplayNode *OCDisplayNode::parse(Object *obj, OCGs *oc,
+ XRef *xref, int recursion) {
+ Object obj2, obj3;
+ OptionalContentGroup *ocgA;
+ OCDisplayNode *node, *child;
+ int i;
+
+ if (recursion > displayNodeRecursionLimit) {
+ error(errSyntaxError, -1, "Loop detected in optional content order");
+ return NULL;
+ }
+ if (obj->isRef()) {
+ if ((ocgA = oc->findOcgByRef(obj->getRef()))) {
+ return new OCDisplayNode(ocgA);
+ }
+ }
+ obj->fetch(xref, &obj2);
+ if (!obj2.isArray()) {
+ obj2.free();
+ return NULL;
+ }
+ i = 0;
+ if (obj2.arrayGetLength() >= 1) {
+ if (obj2.arrayGet(0, &obj3)->isString()) {
+ node = new OCDisplayNode(obj3.getString());
+ i = 1;
+ } else {
+ node = new OCDisplayNode();
+ }
+ obj3.free();
+ } else {
+ node = new OCDisplayNode();
+ }
+ for (; i < obj2.arrayGetLength(); ++i) {
+ obj2.arrayGetNF(i, &obj3);
+ if ((child = OCDisplayNode::parse(&obj3, oc, xref, recursion + 1))) {
+ if (!child->ocg && !child->name && node->getNumChildren() > 0) {
+ node->getChild(node->getNumChildren() - 1)->addChildren(child->takeChildren());
+ delete child;
+ } else {
+ node->addChild(child);
+ }
+ }
+ obj3.free();
+ }
+ obj2.free();
+ return node;
+}
+
+OCDisplayNode::OCDisplayNode() {
+ name = NULL;
+ ocg = NULL;
+ children = NULL;
+}
+
+OCDisplayNode::OCDisplayNode(GooString *nameA) {
+ name = new GooString(nameA);
+ ocg = NULL;
+ children = NULL;
+}
+
+OCDisplayNode::OCDisplayNode(OptionalContentGroup *ocgA) {
+ name = (ocgA->getName()) ? ocgA->getName()->copy() : NULL;
+ ocg = ocgA;
+ children = NULL;
+}
+
+void OCDisplayNode::addChild(OCDisplayNode *child) {
+ if (!children) {
+ children = new GooList();
+ }
+ children->append(child);
+}
+
+void OCDisplayNode::addChildren(GooList *childrenA) {
+ if (!children) {
+ children = new GooList();
+ }
+ children->append(childrenA);
+ delete childrenA;
+}
+
+GooList *OCDisplayNode::takeChildren() {
+ GooList *childrenA;
+
+ childrenA = children;
+ children = NULL;
+ return childrenA;
+}
+
+OCDisplayNode::~OCDisplayNode() {
+ gfree(name);
+ if (children) {
+ deleteGooList(children, OCDisplayNode);
+ }
+}
+
+int OCDisplayNode::getNumChildren() {
+ if (!children) {
+ return 0;
+ }
+ return children->getLength();
+}
+
+OCDisplayNode *OCDisplayNode::getChild(int idx) {
+ return (OCDisplayNode *)children->get(idx);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/OptionalContent.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/OptionalContent.h
new file mode 100644
index 00000000000..2e416462003
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/OptionalContent.h
@@ -0,0 +1,140 @@
+//========================================================================
+//
+// OptionalContent.h
+//
+// Copyright 2007 Brad Hards <bradh@kde.org>
+// Copyright 2008 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright 2013 Albert Astals Cid <aacid@kde.org>
+//
+// Released under the GPL (version 2, or later, at your option)
+//
+//========================================================================
+
+#ifndef OPTIONALCONTENT_H
+#define OPTIONALCONTENT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+#include "CharTypes.h"
+
+class GooString;
+class GooList;
+class XRef;
+
+class OptionalContentGroup;
+class OCDisplayNode;
+
+//------------------------------------------------------------------------
+
+class OCGs {
+public:
+
+ OCGs(Object *ocgObject, XRef *xref);
+ ~OCGs();
+
+ // Is OCGS valid?
+ GBool isOk() { return ok; }
+
+ bool hasOCGs();
+ GooList *getOCGs() const { return optionalContentGroups; }
+
+ OptionalContentGroup* findOcgByRef( const Ref &ref);
+
+ // Get the root node of the optional content group display tree
+ // (which does not necessarily include all of the OCGs).
+ OCDisplayNode *getDisplayRoot();
+
+ Array* getOrderArray()
+ { return (order.isArray() && order.arrayGetLength() > 0) ? order.getArray() : NULL; }
+ Array* getRBGroupsArray()
+ { return (rbgroups.isArray() && rbgroups.arrayGetLength()) ? rbgroups.getArray() : NULL; }
+
+ bool optContentIsVisible( Object *dictRef );
+
+private:
+ GBool ok;
+
+ GBool evalOCVisibilityExpr(Object *expr, int recursion);
+ bool allOn( Array *ocgArray );
+ bool allOff( Array *ocgArray );
+ bool anyOn( Array *ocgArray );
+ bool anyOff( Array *ocgArray );
+
+ GooList *optionalContentGroups;
+
+ Object order;
+ Object rbgroups;
+ XRef *m_xref;
+ OCDisplayNode *display; // root node of display tree
+};
+
+//------------------------------------------------------------------------
+
+class OptionalContentGroup {
+public:
+ enum State { On, Off };
+
+ // Values from the optional content usage dictionary.
+ enum UsageState {
+ ocUsageOn,
+ ocUsageOff,
+ ocUsageUnset
+ };
+
+ OptionalContentGroup(Dict *dict);
+
+ OptionalContentGroup(GooString *label);
+
+ ~OptionalContentGroup();
+
+ GooString* getName() const;
+
+ Ref getRef() const;
+ void setRef(const Ref ref);
+
+ State getState() { return m_state; };
+ void setState(State state) { m_state = state; };
+
+ UsageState getViewState() { return viewState; }
+ UsageState getPrintState() { return printState; }
+
+private:
+ GooString *m_name;
+ Ref m_ref;
+ State m_state;
+ UsageState viewState; // suggested state when viewing
+ UsageState printState; // suggested state when printing
+};
+
+//------------------------------------------------------------------------
+
+class OCDisplayNode {
+public:
+
+ static OCDisplayNode *parse(Object *obj, OCGs *oc, XRef *xref, int recursion = 0);
+ OCDisplayNode();
+ ~OCDisplayNode();
+
+ GooString *getName() { return name; }
+ OptionalContentGroup *getOCG() { return ocg; }
+ int getNumChildren();
+ OCDisplayNode *getChild(int idx);
+
+private:
+
+ OCDisplayNode(GooString *nameA);
+ OCDisplayNode(OptionalContentGroup *ocgA);
+ void addChild(OCDisplayNode *child);
+ void addChildren(GooList *childrenA);
+ GooList *takeChildren();
+
+ GooString *name; // display name (may be NULL)
+ OptionalContentGroup *ocg; // NULL for display labels
+ GooList *children; // NULL if there are no children
+ // [OCDisplayNode]
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Outline.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Outline.cc
new file mode 100644
index 00000000000..bd4e6d01b6d
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Outline.cc
@@ -0,0 +1,188 @@
+//========================================================================
+//
+// Outline.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
+// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Nick Jones <nick.jones@network-box.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "goo/GooList.h"
+#include "XRef.h"
+#include "Link.h"
+#include "PDFDocEncoding.h"
+#include "Outline.h"
+
+//------------------------------------------------------------------------
+
+Outline::Outline(Object *outlineObj, XRef *xref) {
+ Object first, last;
+
+ items = NULL;
+ if (!outlineObj->isDict()) {
+ return;
+ }
+ items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first),
+ outlineObj->dictLookupNF("Last", &last),
+ xref);
+ first.free();
+ last.free();
+}
+
+Outline::~Outline() {
+ if (items) {
+ deleteGooList(items, OutlineItem);
+ }
+}
+
+//------------------------------------------------------------------------
+
+OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) {
+ Object obj1;
+ GooString *s;
+ int i;
+
+ xref = xrefA;
+ title = NULL;
+ action = NULL;
+ kids = NULL;
+
+ if (dict->lookup("Title", &obj1)->isString()) {
+ s = obj1.getString();
+ if ((s->getChar(0) & 0xff) == 0xfe &&
+ (s->getChar(1) & 0xff) == 0xff) {
+ titleLen = (s->getLength() - 2) / 2;
+ title = (Unicode *)gmallocn(titleLen, sizeof(Unicode));
+ for (i = 0; i < titleLen; ++i) {
+ title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) |
+ (s->getChar(3 + 2*i) & 0xff);
+ }
+ } else {
+ titleLen = s->getLength();
+ title = (Unicode *)gmallocn(titleLen, sizeof(Unicode));
+ for (i = 0; i < titleLen; ++i) {
+ title[i] = pdfDocEncoding[s->getChar(i) & 0xff];
+ }
+ }
+ } else {
+ titleLen = 0;
+ }
+ obj1.free();
+
+ if (!dict->lookup("Dest", &obj1)->isNull()) {
+ action = LinkAction::parseDest(&obj1);
+ } else {
+ obj1.free();
+ if (!dict->lookup("A", &obj1)->isNull()) {
+ action = LinkAction::parseAction(&obj1);
+ }
+ }
+ obj1.free();
+
+ dict->lookupNF("First", &firstRef);
+ dict->lookupNF("Last", &lastRef);
+ dict->lookupNF("Next", &nextRef);
+
+ startsOpen = gFalse;
+ if (dict->lookup("Count", &obj1)->isInt()) {
+ if (obj1.getInt() > 0) {
+ startsOpen = gTrue;
+ }
+ }
+ obj1.free();
+}
+
+OutlineItem::~OutlineItem() {
+ close();
+ if (title) {
+ gfree(title);
+ }
+ if (action) {
+ delete action;
+ }
+ firstRef.free();
+ lastRef.free();
+ nextRef.free();
+}
+
+GooList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef,
+ XRef *xrefA) {
+ GooList *items;
+ char* alreadyRead;
+ OutlineItem *item;
+ Object obj;
+ Object *p;
+
+ if (!lastItemRef->isRef())
+ return NULL;
+
+ items = new GooList();
+
+ alreadyRead = (char *)gmalloc(xrefA->getNumObjects());
+ memset(alreadyRead, 0, xrefA->getNumObjects());
+
+ p = firstItemRef;
+ while (p->isRef() &&
+ (p->getRefNum() >= 0) &&
+ (p->getRefNum() < xrefA->getNumObjects()) &&
+ !alreadyRead[p->getRefNum()]) {
+ if (!p->fetch(xrefA, &obj)->isDict()) {
+ obj.free();
+ break;
+ }
+ alreadyRead[p->getRefNum()] = 1;
+ item = new OutlineItem(obj.getDict(), xrefA);
+ obj.free();
+ items->append(item);
+ if (p->getRef().num == lastItemRef->getRef().num &&
+ p->getRef().gen == lastItemRef->getRef().gen) {
+ break;
+ }
+ p = &item->nextRef;
+ }
+
+ gfree(alreadyRead);
+
+ if (!items->getLength()) {
+ delete items;
+ items = NULL;
+ }
+
+ return items;
+}
+
+void OutlineItem::open() {
+ if (!kids) {
+ kids = readItemList(&firstRef, &lastRef, xref);
+ }
+}
+
+void OutlineItem::close() {
+ if (kids) {
+ deleteGooList(kids, OutlineItem);
+ kids = NULL;
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Outline.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Outline.h
new file mode 100644
index 00000000000..90190e69280
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Outline.h
@@ -0,0 +1,89 @@
+//========================================================================
+//
+// Outline.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef OUTLINE_H
+#define OUTLINE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+#include "CharTypes.h"
+
+class GooString;
+class GooList;
+class XRef;
+class LinkAction;
+
+//------------------------------------------------------------------------
+
+class Outline {
+public:
+
+ Outline(Object *outlineObj, XRef *xref);
+ ~Outline();
+
+ GooList *getItems() { return items; }
+
+private:
+
+ GooList *items; // NULL if document has no outline,
+ // otherwise, a list of OutlineItem
+};
+
+//------------------------------------------------------------------------
+
+class OutlineItem {
+public:
+
+ OutlineItem(Dict *dict, XRef *xrefA);
+ ~OutlineItem();
+
+ static GooList *readItemList(Object *firstItemRef, Object *lastItemRef,
+ XRef *xrefA);
+
+ void open();
+ void close();
+
+ Unicode *getTitle() { return title; }
+ int getTitleLength() { return titleLen; }
+ LinkAction *getAction() { return action; }
+ GBool isOpen() { return startsOpen; }
+ GBool hasKids() { return firstRef.isRef(); }
+ GooList *getKids() { return kids; }
+
+private:
+
+ XRef *xref;
+ Unicode *title;
+ int titleLen;
+ LinkAction *action;
+ Object firstRef;
+ Object lastRef;
+ Object nextRef;
+ GBool startsOpen;
+ GooList *kids; // NULL if this item is closed or has no kids,
+ // otherwise a list of OutlineItem
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/OutputDev.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/OutputDev.cc
new file mode 100644
index 00000000000..ee3cf5a30ff
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/OutputDev.cc
@@ -0,0 +1,201 @@
+//========================================================================
+//
+// OutputDev.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
+// Copyright (C) 2006 Thorkild Stray <thorkild@ifi.uio.no>
+// Copyright (C) 2007 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009, 2012, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Stream.h"
+#include "GfxState.h"
+#include "OutputDev.h"
+#include "goo/GooHash.h"
+
+//------------------------------------------------------------------------
+// OutputDev
+//------------------------------------------------------------------------
+
+void OutputDev::setDefaultCTM(double *ctm) {
+ int i;
+ double det;
+
+ for (i = 0; i < 6; ++i) {
+ defCTM[i] = ctm[i];
+ }
+ det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]);
+ defICTM[0] = defCTM[3] * det;
+ defICTM[1] = -defCTM[1] * det;
+ defICTM[2] = -defCTM[2] * det;
+ defICTM[3] = defCTM[0] * det;
+ defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det;
+ defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det;
+}
+
+void OutputDev::cvtDevToUser(double dx, double dy, double *ux, double *uy) {
+ *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4];
+ *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5];
+}
+
+void OutputDev::cvtUserToDev(double ux, double uy, int *dx, int *dy) {
+ *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5);
+ *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5);
+}
+
+void OutputDev::updateAll(GfxState *state) {
+ updateLineDash(state);
+ updateFlatness(state);
+ updateLineJoin(state);
+ updateLineCap(state);
+ updateMiterLimit(state);
+ updateLineWidth(state);
+ updateStrokeAdjust(state);
+ updateFillColorSpace(state);
+ updateFillColor(state);
+ updateStrokeColorSpace(state);
+ updateStrokeColor(state);
+ updateBlendMode(state);
+ updateFillOpacity(state);
+ updateStrokeOpacity(state);
+ updateFillOverprint(state);
+ updateStrokeOverprint(state);
+ updateTransfer(state);
+ updateFont(state);
+}
+
+GBool OutputDev::beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen) {
+ return gFalse;
+}
+
+void OutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg) {
+ int i, j;
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ str->close();
+ }
+}
+
+void OutputDev::setSoftMaskFromImageMask(GfxState *state,
+ Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix) {
+ drawImageMask(state, ref, str, width, height, invert, gFalse, inlineImg);
+}
+
+void OutputDev::unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) {
+ return;
+}
+
+void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg) {
+ int i, j;
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ str->close();
+ }
+}
+
+void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GBool maskInvert,
+ GBool maskInterpolate) {
+ drawImage(state, ref, str, width, height, colorMap, interpolate, NULL, gFalse);
+}
+
+void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate) {
+ drawImage(state, ref, str, width, height, colorMap, interpolate, NULL, gFalse);
+}
+
+void OutputDev::endMarkedContent(GfxState *state) {
+}
+
+void OutputDev::beginMarkedContent(char *name, Dict *properties) {
+}
+
+void OutputDev::markPoint(char *name) {
+}
+
+void OutputDev::markPoint(char *name, Dict *properties) {
+}
+
+
+#if OPI_SUPPORT
+void OutputDev::opiBegin(GfxState *state, Dict *opiDict) {
+}
+
+void OutputDev::opiEnd(GfxState *state, Dict *opiDict) {
+}
+#endif
+
+void OutputDev::startProfile() {
+ if (profileHash)
+ delete profileHash;
+
+ profileHash = new GooHash (true);
+}
+
+GooHash *OutputDev::endProfile() {
+ GooHash *profile = profileHash;
+
+ profileHash = NULL;
+
+ return profile;
+}
+
+#ifdef USE_CMS
+PopplerCache *OutputDev::getIccColorSpaceCache()
+{
+ return &iccColorSpaceCache;
+}
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/OutputDev.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/OutputDev.h
new file mode 100644
index 00000000000..e8a7a4794ce
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/OutputDev.h
@@ -0,0 +1,350 @@
+//========================================================================
+//
+// OutputDev.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
+// Copyright (C) 2006 Thorkild Stray <thorkild@ifi.uio.no>
+// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2007, 2011 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2009, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009, 2012, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012 William Bader <williambader@hotmail.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef OUTPUTDEV_H
+#define OUTPUTDEV_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "goo/gtypes.h"
+#include "CharTypes.h"
+#include "Object.h"
+#include "PopplerCache.h"
+
+class Annot;
+class Dict;
+class GooHash;
+class GooString;
+class GfxState;
+class Gfx;
+struct GfxColor;
+class GfxColorSpace;
+class GfxImageColorMap;
+class GfxFunctionShading;
+class GfxAxialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
+class GfxRadialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
+class Stream;
+class Links;
+class AnnotLink;
+class Catalog;
+class Page;
+class Function;
+
+//------------------------------------------------------------------------
+// OutputDev
+//------------------------------------------------------------------------
+
+class OutputDev {
+public:
+
+ // Constructor.
+ OutputDev()
+#ifdef USE_CMS
+ : iccColorSpaceCache(5)
+#endif
+ {
+ profileHash = NULL;
+ }
+
+ // Destructor.
+ virtual ~OutputDev() {}
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() = 0;
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() = 0;
+
+ // Does this device use tilingPatternFill()? If this returns false,
+ // tiling pattern fills will be reduced to a series of other drawing
+ // operations.
+ virtual GBool useTilingPatternFill() { return gFalse; }
+
+ // Does this device support specific shading types?
+ // see gouraudTriangleShadedFill() and patchMeshShadedFill()
+ virtual GBool useShadedFills(int type) { return gFalse; }
+
+ // Does this device use FillColorStop()?
+ virtual GBool useFillColorStop() { return gFalse; }
+
+ // Does this device use drawForm()? If this returns false,
+ // form-type XObjects will be interpreted (i.e., unrolled).
+ virtual GBool useDrawForm() { return gFalse; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() = 0;
+
+ // Does this device need non-text content?
+ virtual GBool needNonText() { return gTrue; }
+
+ // Does this device require incCharCount to be called for text on
+ // non-shown layers?
+ virtual GBool needCharCount() { return gFalse; }
+
+ // Does this device need to clip pages to the crop box even when the
+ // box is the crop box?
+ virtual GBool needClipToCropBox() { return gFalse; }
+
+ //----- initialization and control
+
+ // Set default transform matrix.
+ virtual void setDefaultCTM(double *ctm);
+
+ // Check to see if a page slice should be displayed. If this
+ // returns false, the page display is aborted. Typically, an
+ // OutputDev will use some alternate means to display the page
+ // before returning false.
+ virtual GBool checkPageSlice(Page *page, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing,
+ GBool (* abortCheckCbk)(void *data) = NULL,
+ void * abortCheckCbkData = NULL,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+ void *annotDisplayDecideCbkData = NULL)
+ { return gTrue; }
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state, XRef *xref) {}
+
+ // End a page.
+ virtual void endPage() {}
+
+ // Dump page contents to display.
+ virtual void dump() {}
+
+ //----- coordinate conversion
+
+ // Convert between device and user coordinates.
+ virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy);
+ virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy);
+
+ double *getDefCTM() { return defCTM; }
+ double *getDefICTM() { return defICTM; }
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState * /*state*/) {}
+ virtual void restoreState(GfxState * /*state*/) {}
+
+ //----- update graphics state
+ virtual void updateAll(GfxState *state);
+ virtual void updateCTM(GfxState * /*state*/, double /*m11*/, double /*m12*/,
+ double /*m21*/, double /*m22*/, double /*m31*/, double /*m32*/) {}
+ virtual void updateLineDash(GfxState * /*state*/) {}
+ virtual void updateFlatness(GfxState * /*state*/) {}
+ virtual void updateLineJoin(GfxState * /*state*/) {}
+ virtual void updateLineCap(GfxState * /*state*/) {}
+ virtual void updateMiterLimit(GfxState * /*state*/) {}
+ virtual void updateLineWidth(GfxState * /*state*/) {}
+ virtual void updateStrokeAdjust(GfxState * /*state*/) {}
+ virtual void updateAlphaIsShape(GfxState * /*state*/) {}
+ virtual void updateTextKnockout(GfxState * /*state*/) {}
+ virtual void updateFillColorSpace(GfxState * /*state*/) {}
+ virtual void updateStrokeColorSpace(GfxState * /*state*/) {}
+ virtual void updateFillColor(GfxState * /*state*/) {}
+ virtual void updateStrokeColor(GfxState * /*state*/) {}
+ virtual void updateBlendMode(GfxState * /*state*/) {}
+ virtual void updateFillOpacity(GfxState * /*state*/) {}
+ virtual void updateStrokeOpacity(GfxState * /*state*/) {}
+ virtual void updateFillOverprint(GfxState * /*state*/) {}
+ virtual void updateStrokeOverprint(GfxState * /*state*/) {}
+ virtual void updateOverprintMode(GfxState * /*state*/) {}
+ virtual void updateTransfer(GfxState * /*state*/) {}
+ virtual void updateFillColorStop(GfxState * /*state*/, double /*offset*/) {}
+
+ //----- update text state
+ virtual void updateFont(GfxState * /*state*/) {}
+ virtual void updateTextMat(GfxState * /*state*/) {}
+ virtual void updateCharSpace(GfxState * /*state*/) {}
+ virtual void updateRender(GfxState * /*state*/) {}
+ virtual void updateRise(GfxState * /*state*/) {}
+ virtual void updateWordSpace(GfxState * /*state*/) {}
+ virtual void updateHorizScaling(GfxState * /*state*/) {}
+ virtual void updateTextPos(GfxState * /*state*/) {}
+ virtual void updateTextShift(GfxState * /*state*/, double /*shift*/) {}
+ virtual void saveTextPos(GfxState * /*state*/) {}
+ virtual void restoreTextPos(GfxState * /*state*/) {}
+
+ //----- path painting
+ virtual void stroke(GfxState * /*state*/) {}
+ virtual void fill(GfxState * /*state*/) {}
+ virtual void eoFill(GfxState * /*state*/) {}
+ virtual GBool tilingPatternFill(GfxState * /*state*/, Gfx * /*gfx*/, Catalog * /*cat*/, Object * /*str*/,
+ double * /*pmat*/, int /*paintType*/, int /*tilingType*/, Dict * /*resDict*/,
+ double * /*mat*/, double * /*bbox*/,
+ int /*x0*/, int /*y0*/, int /*x1*/, int /*y1*/,
+ double /*xStep*/, double /*yStep*/)
+ { return gFalse; }
+ virtual GBool functionShadedFill(GfxState * /*state*/,
+ GfxFunctionShading * /*shading*/)
+ { return gFalse; }
+ virtual GBool axialShadedFill(GfxState * /*state*/, GfxAxialShading * /*shading*/, double /*tMin*/, double /*tMax*/)
+ { return gFalse; }
+ virtual GBool axialShadedSupportExtend(GfxState * /*state*/, GfxAxialShading * /*shading*/)
+ { return gFalse; }
+ virtual GBool radialShadedFill(GfxState * /*state*/, GfxRadialShading * /*shading*/, double /*sMin*/, double /*sMax*/)
+ { return gFalse; }
+ virtual GBool radialShadedSupportExtend(GfxState * /*state*/, GfxRadialShading * /*shading*/)
+ { return gFalse; }
+ virtual GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+ { return gFalse; }
+ virtual GBool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
+ { return gFalse; }
+
+ //----- path clipping
+ virtual void clip(GfxState * /*state*/) {}
+ virtual void eoClip(GfxState * /*state*/) {}
+ virtual void clipToStrokePath(GfxState * /*state*/) {}
+
+ //----- text drawing
+ virtual void beginStringOp(GfxState * /*state*/) {}
+ virtual void endStringOp(GfxState * /*state*/) {}
+ virtual void beginString(GfxState * /*state*/, GooString * /*s*/) {}
+ virtual void endString(GfxState * /*state*/) {}
+ virtual void drawChar(GfxState * /*state*/, double /*x*/, double /*y*/,
+ double /*dx*/, double /*dy*/,
+ double /*originX*/, double /*originY*/,
+ CharCode /*code*/, int /*nBytes*/, Unicode * /*u*/, int /*uLen*/) {}
+ virtual void drawString(GfxState * /*state*/, GooString * /*s*/) {}
+ virtual GBool beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/,
+ double /*dx*/, double /*dy*/,
+ CharCode /*code*/, Unicode * /*u*/, int /*uLen*/);
+ virtual void endType3Char(GfxState * /*state*/) {}
+ virtual void beginTextObject(GfxState * /*state*/) {}
+ virtual void endTextObject(GfxState * /*state*/) {}
+ virtual void incCharCount(int /*nChars*/) {}
+ virtual void beginActualText(GfxState * /*state*/, GooString * /*text*/ ) {}
+ virtual void endActualText(GfxState * /*state*/) {}
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert, GBool interpolate,
+ GBool inlineImg);
+ virtual void setSoftMaskFromImageMask(GfxState *state,
+ Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix);
+ virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap, GBool interpolate,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ GBool maskInvert, GBool maskInterpolate);
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate);
+
+ //----- grouping operators
+
+ virtual void endMarkedContent(GfxState *state);
+ virtual void beginMarkedContent(char *name, Dict *properties);
+ virtual void markPoint(char *name);
+ virtual void markPoint(char *name, Dict *properties);
+
+
+
+#if OPI_SUPPORT
+ //----- OPI functions
+ virtual void opiBegin(GfxState *state, Dict *opiDict);
+ virtual void opiEnd(GfxState *state, Dict *opiDict);
+#endif
+
+ //----- Type 3 font operators
+ virtual void type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/) {}
+ virtual void type3D1(GfxState * /*state*/, double /*wx*/, double /*wy*/,
+ double /*llx*/, double /*lly*/, double /*urx*/, double /*ury*/) {}
+
+ //----- form XObjects
+ virtual void drawForm(Ref /*id*/) {}
+
+ //----- PostScript XObjects
+ virtual void psXObject(Stream * /*psStream*/, Stream * /*level1Stream*/) {}
+
+ //----- Profiling
+ virtual void startProfile();
+ virtual GooHash *getProfileHash() {return profileHash; }
+ virtual GooHash *endProfile();
+
+ //----- transparency groups and soft masks
+ virtual GBool checkTransparencyGroup(GfxState * /*state*/, GBool /*knockout*/) { return gTrue; }
+ 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(AnnotLink * /*link*/) {}
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ virtual GBool getVectorAntialias() { return gFalse; }
+ virtual void setVectorAntialias(GBool /*vaa*/) {}
+#endif
+
+#ifdef USE_CMS
+ PopplerCache *getIccColorSpaceCache();
+#endif
+
+private:
+
+ double defCTM[6]; // default coordinate transform matrix
+ double defICTM[6]; // inverse of default CTM
+ GooHash *profileHash;
+
+#ifdef USE_CMS
+ PopplerCache iccColorSpaceCache;
+#endif
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDoc.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDoc.cc
new file mode 100644
index 00000000000..46c4544e75b
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDoc.cc
@@ -0,0 +1,1955 @@
+//========================================================================
+//
+// PDFDoc.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2006, 2008 Brad Hards <bradh@frogmouth.net>
+// Copyright (C) 2005, 2007-2009, 2011-2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2008, 2010 Pino Toscano <pino@kde.org>
+// Copyright (C) 2008, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009 Eric Toombs <ewtoombs@uwaterloo.ca>
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2009, 2011 Axel Struebing <axel.struebing@freenet.de>
+// Copyright (C) 2010-2012, 2014 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net>
+// Copyright (C) 2010 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2010 Srinivas Adicherla <srinivas.adicherla@geodesic.com>
+// Copyright (C) 2010 Philip Lorenz <lorenzph+freedesktop@gmail.com>
+// Copyright (C) 2011-2015 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Adam Reichold <adamreichold@myopera.com>
+// Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com>
+// Copyright (C) 2015 Li Junling <lijunling@sina.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <time.h>
+#include <sys/stat.h>
+#include "goo/gstrtod.h"
+#include "goo/GooString.h"
+#include "goo/gfile.h"
+#include "poppler-config.h"
+#include "GlobalParams.h"
+#include "Page.h"
+#include "Catalog.h"
+#include "Stream.h"
+#include "XRef.h"
+#include "Linearization.h"
+#include "Link.h"
+#include "OutputDev.h"
+#include "Error.h"
+#include "ErrorCodes.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "SecurityHandler.h"
+#include "Decrypt.h"
+#ifndef DISABLE_OUTLINE
+#include "Outline.h"
+#endif
+#include "PDFDoc.h"
+#include "Hints.h"
+
+#if MULTITHREADED
+# define pdfdocLocker() MutexLocker locker(&mutex)
+#else
+# define pdfdocLocker()
+#endif
+
+//------------------------------------------------------------------------
+
+#define headerSearchSize 1024 // read this many bytes at beginning of
+ // file to look for '%PDF'
+#define pdfIdLength 32 // PDF Document IDs (PermanentId, UpdateId) length
+
+#define linearizationSearchSize 1024 // read this many bytes at beginning of
+ // file to look for linearization
+ // dictionary
+
+#define xrefSearchSize 1024 // read this many bytes at end of file
+ // to look for 'startxref'
+
+//------------------------------------------------------------------------
+// PDFDoc
+//------------------------------------------------------------------------
+
+void PDFDoc::init()
+{
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+ ok = gFalse;
+ errCode = errNone;
+ fileName = NULL;
+ file = NULL;
+ str = NULL;
+ xref = NULL;
+ linearization = NULL;
+ catalog = NULL;
+ hints = NULL;
+#ifndef DISABLE_OUTLINE
+ outline = NULL;
+#endif
+ startXRefPos = -1;
+ secHdlr = NULL;
+ pageCache = NULL;
+}
+
+PDFDoc::PDFDoc()
+{
+ init();
+}
+
+PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword,
+ GooString *userPassword, void *guiDataA) {
+ Object obj;
+#ifdef _WIN32
+ int n, i;
+#endif
+
+ init();
+
+ fileName = fileNameA;
+ guiData = guiDataA;
+#ifdef _WIN32
+ n = fileName->getLength();
+ fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t));
+ for (i = 0; i < n; ++i) {
+ fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff);
+ }
+ fileNameU[n] = L'\0';
+#endif
+
+ // try to open file
+ file = GooFile::open(fileName);
+ if (file == NULL) {
+ // fopen() has failed.
+ // Keep a copy of the errno returned by fopen so that it can be
+ // referred to later.
+ fopenErrno = errno;
+ error(errIO, -1, "Couldn't open file '{0:t}': {1:s}.", fileName, strerror(errno));
+ errCode = errOpenFile;
+ return;
+ }
+
+ // create stream
+ obj.initNull();
+ str = new FileStream(file, 0, gFalse, file->size(), &obj);
+
+ ok = setup(ownerPassword, userPassword);
+}
+
+#ifdef _WIN32
+PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword,
+ GooString *userPassword, void *guiDataA) {
+ OSVERSIONINFO version;
+ Object obj;
+ int i;
+
+ init();
+
+ guiData = guiDataA;
+
+ // save both Unicode and 8-bit copies of the file name
+ fileName = new GooString();
+ fileNameU = (wchar_t *)gmallocn(fileNameLen + 1, sizeof(wchar_t));
+ for (i = 0; i < fileNameLen; ++i) {
+ fileName->append((char)fileNameA[i]);
+ fileNameU[i] = fileNameA[i];
+ }
+ fileNameU[fileNameLen] = L'\0';
+
+ // try to open file
+ // NB: _wfopen is only available in NT
+ version.dwOSVersionInfoSize = sizeof(version);
+ GetVersionEx(&version);
+ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ file = GooFile::open(fileNameU);
+ } else {
+ file = GooFile::open(fileName);
+ }
+ if (!file) {
+ error(errIO, -1, "Couldn't open file '{0:t}'", fileName);
+ errCode = errOpenFile;
+ return;
+ }
+
+ // create stream
+ obj.initNull();
+ str = new FileStream(file, 0, gFalse, file->size(), &obj);
+
+ ok = setup(ownerPassword, userPassword);
+}
+#endif
+
+PDFDoc::PDFDoc(BaseStream *strA, GooString *ownerPassword,
+ GooString *userPassword, void *guiDataA) {
+#ifdef _WIN32
+ int n, i;
+#endif
+
+ init();
+ guiData = guiDataA;
+ if (strA->getFileName()) {
+ fileName = strA->getFileName()->copy();
+#ifdef _WIN32
+ n = fileName->getLength();
+ fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t));
+ for (i = 0; i < n; ++i) {
+ fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff);
+ }
+ fileNameU[n] = L'\0';
+#endif
+ } else {
+ fileName = NULL;
+#ifdef _WIN32
+ fileNameU = NULL;
+#endif
+ }
+ str = strA;
+ ok = setup(ownerPassword, userPassword);
+}
+
+GBool PDFDoc::setup(GooString *ownerPassword, GooString *userPassword) {
+ pdfdocLocker();
+ str->setPos(0, -1);
+ if (str->getPos() < 0)
+ {
+ error(errSyntaxError, -1, "Document base stream is not seekable");
+ return gFalse;
+ }
+
+ str->reset();
+
+ // check footer
+ // Adobe does not seem to enforce %%EOF, so we do the same
+// if (!checkFooter()) return gFalse;
+
+ // check header
+ checkHeader();
+
+ GBool wasReconstructed = false;
+
+ // read xref table
+ xref = new XRef(str, getStartXRef(), getMainXRefEntriesOffset(), &wasReconstructed);
+ if (!xref->isOk()) {
+ if (wasReconstructed) {
+ delete xref;
+ startXRefPos = -1;
+ xref = new XRef(str, getStartXRef(gTrue), getMainXRefEntriesOffset(gTrue), &wasReconstructed);
+ }
+ if (!xref->isOk()) {
+ error(errSyntaxError, -1, "Couldn't read xref table");
+ errCode = xref->getErrorCode();
+ return gFalse;
+ }
+ }
+
+ // check for encryption
+ if (!checkEncryption(ownerPassword, userPassword)) {
+ errCode = errEncrypted;
+ return gFalse;
+ }
+
+ // read catalog
+ catalog = new Catalog(this);
+ if (catalog && !catalog->isOk()) {
+ if (!wasReconstructed)
+ {
+ // try one more time to contruct the Catalog, maybe the problem is damaged XRef
+ delete catalog;
+ delete xref;
+ xref = new XRef(str, 0, 0, NULL, true);
+ catalog = new Catalog(this);
+ }
+
+ if (catalog && !catalog->isOk()) {
+ error(errSyntaxError, -1, "Couldn't read page catalog");
+ errCode = errBadCatalog;
+ return gFalse;
+ }
+ }
+
+ // done
+ return gTrue;
+}
+
+PDFDoc::~PDFDoc() {
+ if (pageCache) {
+ for (int i = 0; i < getNumPages(); i++) {
+ if (pageCache[i]) {
+ delete pageCache[i];
+ }
+ }
+ gfree(pageCache);
+ }
+ delete secHdlr;
+#ifndef DISABLE_OUTLINE
+ if (outline) {
+ delete outline;
+ }
+#endif
+ if (catalog) {
+ delete catalog;
+ }
+ if (xref) {
+ delete xref;
+ }
+ if (hints) {
+ delete hints;
+ }
+ if (linearization) {
+ delete linearization;
+ }
+ if (str) {
+ delete str;
+ }
+ if (file) {
+ delete file;
+ }
+ if (fileName) {
+ delete fileName;
+ }
+#ifdef _WIN32
+ if (fileNameU) {
+ gfree(fileNameU);
+ }
+#endif
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+
+// Check for a %%EOF at the end of this stream
+GBool PDFDoc::checkFooter() {
+ // we look in the last 1024 chars because Adobe does the same
+ char *eof = new char[1025];
+ Goffset pos = str->getPos();
+ str->setPos(1024, -1);
+ int i, ch;
+ for (i = 0; i < 1024; i++)
+ {
+ ch = str->getChar();
+ if (ch == EOF)
+ break;
+ eof[i] = ch;
+ }
+ eof[i] = '\0';
+
+ bool found = false;
+ for (i = i - 5; i >= 0; i--) {
+ if (strncmp (&eof[i], "%%EOF", 5) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ error(errSyntaxError, -1, "Document has not the mandatory ending %%EOF");
+ errCode = errDamaged;
+ delete[] eof;
+ return gFalse;
+ }
+ delete[] eof;
+ str->setPos(pos);
+ return gTrue;
+}
+
+// Check for a PDF header on this stream. Skip past some garbage
+// if necessary.
+void PDFDoc::checkHeader() {
+ char hdrBuf[headerSearchSize+1];
+ char *p;
+ char *tokptr;
+ int i;
+
+ pdfMajorVersion = 0;
+ pdfMinorVersion = 0;
+ for (i = 0; i < headerSearchSize; ++i) {
+ hdrBuf[i] = str->getChar();
+ }
+ hdrBuf[headerSearchSize] = '\0';
+ for (i = 0; i < headerSearchSize - 5; ++i) {
+ if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
+ break;
+ }
+ }
+ if (i >= headerSearchSize - 5) {
+ error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)");
+ return;
+ }
+ str->moveStart(i);
+ if (!(p = strtok_r(&hdrBuf[i+5], " \t\n\r", &tokptr))) {
+ error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)");
+ return;
+ }
+ sscanf(p, "%d.%d", &pdfMajorVersion, &pdfMinorVersion);
+ // We don't do the version check. Don't add it back in.
+}
+
+GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) {
+ Object encrypt;
+ GBool encrypted;
+ GBool ret;
+
+ xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
+ if ((encrypted = encrypt.isDict())) {
+ if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
+ if (secHdlr->isUnencrypted()) {
+ // no encryption
+ ret = gTrue;
+ } else if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
+ // authorization succeeded
+ xref->setEncryption(secHdlr->getPermissionFlags(),
+ secHdlr->getOwnerPasswordOk(),
+ secHdlr->getFileKey(),
+ secHdlr->getFileKeyLength(),
+ secHdlr->getEncVersion(),
+ secHdlr->getEncRevision(),
+ secHdlr->getEncAlgorithm());
+ ret = gTrue;
+ } else {
+ // authorization failed
+ ret = gFalse;
+ }
+ } else {
+ // couldn't find the matching security handler
+ ret = gFalse;
+ }
+ } else {
+ // document is not encrypted
+ ret = gTrue;
+ }
+ encrypt.free();
+ return ret;
+}
+
+void PDFDoc::displayPage(OutputDev *out, int page,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
+ void *annotDisplayDecideCbkData, GBool copyXRef) {
+ if (globalParams->getPrintCommands()) {
+ printf("***** page %d *****\n", page);
+ }
+
+ if (getPage(page))
+ getPage(page)->display(out, hDPI, vDPI,
+ rotate, useMediaBox, crop, printing,
+ abortCheckCbk, abortCheckCbkData,
+ annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
+
+}
+
+void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
+ void *annotDisplayDecideCbkData) {
+ int page;
+
+ for (page = firstPage; page <= lastPage; ++page) {
+ displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing,
+ abortCheckCbk, abortCheckCbkData,
+ annotDisplayDecideCbk, annotDisplayDecideCbkData);
+ }
+}
+
+void PDFDoc::displayPageSlice(OutputDev *out, int page,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
+ void *annotDisplayDecideCbkData, GBool copyXRef) {
+ if (getPage(page))
+ getPage(page)->displaySlice(out, hDPI, vDPI,
+ rotate, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ printing,
+ abortCheckCbk, abortCheckCbkData,
+ annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
+}
+
+Links *PDFDoc::getLinks(int page) {
+ Page *p = getPage(page);
+ if (!p) {
+ return new Links (NULL);
+ }
+ return p->getLinks();
+}
+
+void PDFDoc::processLinks(OutputDev *out, int page) {
+ if (getPage(page))
+ getPage(page)->processLinks(out);
+}
+
+Linearization *PDFDoc::getLinearization()
+{
+ if (!linearization) {
+ linearization = new Linearization(str);
+ }
+ return linearization;
+}
+
+GBool PDFDoc::isLinearized(GBool tryingToReconstruct) {
+ if ((str->getLength()) &&
+ (getLinearization()->getLength() == str->getLength()))
+ return gTrue;
+ else {
+ if (tryingToReconstruct)
+ return getLinearization()->getLength() > 0;
+ else
+ return gFalse;
+ }
+}
+
+static GBool
+get_id (GooString *encodedidstring, GooString *id) {
+ const char *encodedid = encodedidstring->getCString();
+ char pdfid[pdfIdLength + 1];
+ int n;
+
+ if (encodedidstring->getLength() != pdfIdLength / 2)
+ return gFalse;
+
+ n = sprintf(pdfid, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ encodedid[0] & 0xff, encodedid[1] & 0xff, encodedid[2] & 0xff, encodedid[3] & 0xff,
+ encodedid[4] & 0xff, encodedid[5] & 0xff, encodedid[6] & 0xff, encodedid[7] & 0xff,
+ encodedid[8] & 0xff, encodedid[9] & 0xff, encodedid[10] & 0xff, encodedid[11] & 0xff,
+ encodedid[12] & 0xff, encodedid[13] & 0xff, encodedid[14] & 0xff, encodedid[15] & 0xff);
+ if (n != pdfIdLength)
+ return gFalse;
+
+ id->Set(pdfid, pdfIdLength);
+ return gTrue;
+}
+
+GBool PDFDoc::getID(GooString *permanent_id, GooString *update_id) {
+ Object obj;
+ xref->getTrailerDict()->dictLookup ("ID", &obj);
+
+ if (obj.isArray() && obj.arrayGetLength() == 2) {
+ Object obj2;
+
+ if (permanent_id) {
+ if (obj.arrayGet(0, &obj2)->isString()) {
+ if (!get_id (obj2.getString(), permanent_id)) {
+ obj2.free();
+ return gFalse;
+ }
+ } else {
+ error(errSyntaxError, -1, "Invalid permanent ID");
+ obj2.free();
+ return gFalse;
+ }
+ obj2.free();
+ }
+
+ if (update_id) {
+ if (obj.arrayGet(1, &obj2)->isString()) {
+ if (!get_id (obj2.getString(), update_id)) {
+ obj2.free();
+ return gFalse;
+ }
+ } else {
+ error(errSyntaxError, -1, "Invalid update ID");
+ obj2.free();
+ return gFalse;
+ }
+ obj2.free();
+ }
+
+ obj.free();
+
+ return gTrue;
+ }
+ obj.free();
+
+ return gFalse;
+}
+
+Hints *PDFDoc::getHints()
+{
+ if (!hints && isLinearized()) {
+ hints = new Hints(str, getLinearization(), getXRef(), secHdlr);
+ }
+
+ return hints;
+}
+
+int PDFDoc::savePageAs(GooString *name, int pageNo)
+{
+ FILE *f;
+ OutStream *outStr;
+ XRef *yRef, *countRef;
+ int rootNum = getXRef()->getNumObjects() + 1;
+
+ // Make sure that special flags are set, because we are going to read
+ // all objects, including Unencrypted ones.
+ xref->scanSpecialFlags();
+
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
+
+ if (pageNo < 1 || pageNo > getNumPages() || !getCatalog()->getPage(pageNo)) {
+ error(errInternal, -1, "Illegal pageNo: {0:d}({1:d})", pageNo, getNumPages() );
+ return errOpenFile;
+ }
+ PDFRectangle *cropBox = NULL;
+ if (getCatalog()->getPage(pageNo)->isCropped()) {
+ cropBox = getCatalog()->getPage(pageNo)->getCropBox();
+ }
+ replacePageDict(pageNo,
+ getCatalog()->getPage(pageNo)->getRotate(),
+ getCatalog()->getPage(pageNo)->getMediaBox(),
+ cropBox);
+ Ref *refPage = getCatalog()->getPageRef(pageNo);
+ Object page;
+ getXRef()->fetch(refPage->num, refPage->gen, &page);
+
+ if (!(f = fopen(name->getCString(), "wb"))) {
+ error(errIO, -1, "Couldn't open file '{0:t}'", name);
+ return errOpenFile;
+ }
+ outStr = new FileOutStream(f,0);
+
+ yRef = new XRef(getXRef()->getTrailerDict());
+
+ if (secHdlr != NULL && !secHdlr->isUnencrypted()) {
+ yRef->setEncryption(secHdlr->getPermissionFlags(),
+ secHdlr->getOwnerPasswordOk(), fileKey, keyLength, secHdlr->getEncVersion(), secHdlr->getEncRevision(), encAlgorithm);
+ }
+ countRef = new XRef();
+ Object *trailerObj = getXRef()->getTrailerDict();
+ if (trailerObj->isDict()) {
+ markPageObjects(trailerObj->getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
+ }
+ yRef->add(0, 65535, 0, gFalse);
+ writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion());
+
+ // get and mark info dict
+ Object infoObj;
+ getXRef()->getDocInfo(&infoObj);
+ if (infoObj.isDict()) {
+ Dict *infoDict = infoObj.getDict();
+ markPageObjects(infoDict, yRef, countRef, 0, refPage->num, rootNum + 2);
+ if (trailerObj->isDict()) {
+ Dict *trailerDict = trailerObj->getDict();
+ Object ref;
+ trailerDict->lookupNF("Info", &ref);
+ if (ref.isRef()) {
+ yRef->add(ref.getRef().num, ref.getRef().gen, 0, gTrue);
+ if (getXRef()->getEntry(ref.getRef().num)->type == xrefEntryCompressed) {
+ yRef->getEntry(ref.getRef().num)->type = xrefEntryCompressed;
+ }
+ }
+ ref.free();
+ }
+ }
+ infoObj.free();
+
+ // get and mark output intents etc.
+ Object catObj, pagesObj, resourcesObj, annotsObj, afObj;
+ getXRef()->getCatalog(&catObj);
+ Dict *catDict = catObj.getDict();
+ catDict->lookup("Pages", &pagesObj);
+ catDict->lookupNF("AcroForm", &afObj);
+ if (!afObj.isNull()) {
+ markAcroForm(&afObj, yRef, countRef, 0, refPage->num, rootNum + 2);
+ afObj.free();
+ }
+ Dict *pagesDict = pagesObj.getDict();
+ pagesDict->lookup("Resources", &resourcesObj);
+ if (resourcesObj.isDict())
+ markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
+ markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2);
+
+ Dict *pageDict = page.getDict();
+ markPageObjects(pageDict, yRef, countRef, 0, refPage->num, rootNum + 2);
+ pageDict->lookupNF("Annots", &annotsObj);
+ if (!annotsObj.isNull()) {
+ markAnnotations(&annotsObj, yRef, countRef, 0, refPage->num, rootNum + 2);
+ annotsObj.free();
+ }
+ yRef->markUnencrypted();
+ writePageObjects(outStr, yRef, 0);
+
+ yRef->add(rootNum,0,outStr->getPos(),gTrue);
+ outStr->printf("%d 0 obj\n", rootNum);
+ outStr->printf("<< /Type /Catalog /Pages %d 0 R", rootNum + 1);
+ for (int j = 0; j < catDict->getLength(); j++) {
+ const char *key = catDict->getKey(j);
+ if (strcmp(key, "Type") != 0 &&
+ strcmp(key, "Catalog") != 0 &&
+ strcmp(key, "Pages") != 0)
+ {
+ if (j > 0) outStr->printf(" ");
+ Object value; catDict->getValNF(j, &value);
+ outStr->printf("/%s ", key);
+ writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
+ value.free();
+ }
+ }
+ catObj.free();
+ pagesObj.free();
+ outStr->printf(">>\nendobj\n");
+
+ yRef->add(rootNum + 1,0,outStr->getPos(),gTrue);
+ outStr->printf("%d 0 obj\n", rootNum + 1);
+ outStr->printf("<< /Type /Pages /Kids [ %d 0 R ] /Count 1 ", rootNum + 2);
+ if (resourcesObj.isDict()) {
+ outStr->printf("/Resources ");
+ writeObject(&resourcesObj, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
+ resourcesObj.free();
+ }
+ outStr->printf(">>\n");
+ outStr->printf("endobj\n");
+
+ yRef->add(rootNum + 2,0,outStr->getPos(),gTrue);
+ outStr->printf("%d 0 obj\n", rootNum + 2);
+ outStr->printf("<< ");
+ for (int n = 0; n < pageDict->getLength(); n++) {
+ if (n > 0) outStr->printf(" ");
+ const char *key = pageDict->getKey(n);
+ Object value; pageDict->getValNF(n, &value);
+ if (strcmp(key, "Parent") == 0) {
+ outStr->printf("/Parent %d 0 R", rootNum + 1);
+ } else {
+ outStr->printf("/%s ", key);
+ writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
+ }
+ value.free();
+ }
+ outStr->printf(" >>\nendobj\n");
+ page.free();
+
+ Goffset uxrefOffset = outStr->getPos();
+ Ref ref;
+ ref.num = rootNum;
+ ref.gen = 0;
+ Dict *trailerDict = createTrailerDict(rootNum + 3, gFalse, 0, &ref, getXRef(),
+ name->getCString(), uxrefOffset);
+ writeXRefTableTrailer(trailerDict, yRef, gFalse /* do not write unnecessary entries */,
+ uxrefOffset, outStr, getXRef());
+ delete trailerDict;
+
+ outStr->close();
+ fclose(f);
+ delete yRef;
+ delete countRef;
+ delete outStr;
+
+ return errNone;
+}
+
+int PDFDoc::saveAs(GooString *name, PDFWriteMode mode) {
+ FILE *f;
+ OutStream *outStr;
+ int res;
+
+ if (!(f = fopen(name->getCString(), "wb"))) {
+ error(errIO, -1, "Couldn't open file '{0:t}'", name);
+ return errOpenFile;
+ }
+ outStr = new FileOutStream(f,0);
+ res = saveAs(outStr, mode);
+ delete outStr;
+ fclose(f);
+ return res;
+}
+
+int PDFDoc::saveAs(OutStream *outStr, PDFWriteMode mode) {
+
+ // find if we have updated objects
+ GBool updated = gFalse;
+ for(int i=0; i<xref->getNumObjects(); i++) {
+ if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) {
+ updated = gTrue;
+ break;
+ }
+ }
+
+ if (!updated && mode == writeStandard) {
+ // simply copy the original file
+ saveWithoutChangesAs (outStr);
+ } else if (mode == writeForceRewrite) {
+ saveCompleteRewrite(outStr);
+ } else {
+ saveIncrementalUpdate(outStr);
+ }
+
+ return errNone;
+}
+
+int PDFDoc::saveWithoutChangesAs(GooString *name) {
+ FILE *f;
+ OutStream *outStr;
+ int res;
+
+ if (!(f = fopen(name->getCString(), "wb"))) {
+ error(errIO, -1, "Couldn't open file '{0:t}'", name);
+ return errOpenFile;
+ }
+
+ outStr = new FileOutStream(f,0);
+ res = saveWithoutChangesAs(outStr);
+ delete outStr;
+
+ fclose(f);
+
+ return res;
+}
+
+int PDFDoc::saveWithoutChangesAs(OutStream *outStr) {
+ int c;
+
+ BaseStream *copyStr = str->copy();
+ copyStr->reset();
+ while ((c = copyStr->getChar()) != EOF) {
+ outStr->put(c);
+ }
+ copyStr->close();
+ delete copyStr;
+
+ return errNone;
+}
+
+void PDFDoc::saveIncrementalUpdate (OutStream* outStr)
+{
+ XRef *uxref;
+ int c;
+ //copy the original file
+ BaseStream *copyStr = str->copy();
+ copyStr->reset();
+ while ((c = copyStr->getChar()) != EOF) {
+ outStr->put(c);
+ }
+ copyStr->close();
+ delete copyStr;
+
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
+
+ uxref = new XRef();
+ uxref->add(0, 65535, 0, gFalse);
+ xref->lock();
+ for(int i=0; i<xref->getNumObjects(); i++) {
+ if ((xref->getEntry(i)->type == xrefEntryFree) &&
+ (xref->getEntry(i)->gen == 0)) //we skip the irrelevant free objects
+ continue;
+
+ if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) { //we have an updated object
+ Ref ref;
+ ref.num = i;
+ ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen;
+ if (xref->getEntry(i)->type != xrefEntryFree) {
+ Object obj1;
+ xref->fetch(ref.num, ref.gen, &obj1, 1);
+ Goffset offset = writeObjectHeader(&ref, outStr);
+ writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
+ writeObjectFooter(outStr);
+ uxref->add(ref.num, ref.gen, offset, gTrue);
+ obj1.free();
+ } else {
+ uxref->add(ref.num, ref.gen, 0, gFalse);
+ }
+ }
+ }
+ xref->unlock();
+ if (uxref->getNumObjects() == 0) { //we have nothing to update
+ delete uxref;
+ return;
+ }
+
+ Goffset uxrefOffset = outStr->getPos();
+ int numobjects = xref->getNumObjects();
+ const char *fileNameA = fileName ? fileName->getCString() : NULL;
+ Ref rootRef, uxrefStreamRef;
+ rootRef.num = getXRef()->getRootNum();
+ rootRef.gen = getXRef()->getRootGen();
+
+ // Output a xref stream if there is a xref stream already
+ GBool xRefStream = xref->isXRefStream();
+
+ if (xRefStream) {
+ // Append an entry for the xref stream itself
+ uxrefStreamRef.num = numobjects++;
+ uxrefStreamRef.gen = 0;
+ uxref->add(uxrefStreamRef.num, uxrefStreamRef.gen, uxrefOffset, gTrue);
+ }
+
+ Dict *trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset);
+ if (xRefStream) {
+ writeXRefStreamTrailer(trailerDict, uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef());
+ } else {
+ writeXRefTableTrailer(trailerDict, uxref, gFalse, uxrefOffset, outStr, getXRef());
+ }
+
+ delete trailerDict;
+ delete uxref;
+}
+
+void PDFDoc::saveCompleteRewrite (OutStream* outStr)
+{
+ // Make sure that special flags are set, because we are going to read
+ // all objects, including Unencrypted ones.
+ xref->scanSpecialFlags();
+
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
+
+ outStr->printf("%%PDF-%d.%d\r\n",pdfMajorVersion,pdfMinorVersion);
+ XRef *uxref = new XRef();
+ uxref->add(0, 65535, 0, gFalse);
+ xref->lock();
+ for(int i=0; i<xref->getNumObjects(); i++) {
+ Object obj1;
+ Ref ref;
+ XRefEntryType type = xref->getEntry(i)->type;
+ if (type == xrefEntryFree) {
+ ref.num = i;
+ ref.gen = xref->getEntry(i)->gen;
+ /* the XRef class adds a lot of irrelevant free entries, we only want the significant one
+ and we don't want the one with num=0 because it has already been added (gen = 65535)*/
+ if (ref.gen > 0 && ref.num > 0)
+ uxref->add(ref.num, ref.gen, 0, gFalse);
+ } else if (xref->getEntry(i)->getFlag(XRefEntry::DontRewrite)) {
+ // This entry must not be written, put a free entry instead (with incremented gen)
+ ref.num = i;
+ ref.gen = xref->getEntry(i)->gen + 1;
+ uxref->add(ref.num, ref.gen, 0, gFalse);
+ } else if (type == xrefEntryUncompressed){
+ ref.num = i;
+ ref.gen = xref->getEntry(i)->gen;
+ xref->fetch(ref.num, ref.gen, &obj1, 1);
+ Goffset offset = writeObjectHeader(&ref, outStr);
+ // Write unencrypted objects in unencrypted form
+ if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) {
+ writeObject(&obj1, outStr, NULL, cryptRC4, 0, 0, 0);
+ } else {
+ writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
+ }
+ writeObjectFooter(outStr);
+ uxref->add(ref.num, ref.gen, offset, gTrue);
+ obj1.free();
+ } else if (type == xrefEntryCompressed) {
+ ref.num = i;
+ ref.gen = 0; //compressed entries have gen == 0
+ xref->fetch(ref.num, ref.gen, &obj1, 1);
+ Goffset offset = writeObjectHeader(&ref, outStr);
+ writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
+ writeObjectFooter(outStr);
+ uxref->add(ref.num, ref.gen, offset, gTrue);
+ obj1.free();
+ }
+ }
+ xref->unlock();
+ Goffset uxrefOffset = outStr->getPos();
+ writeXRefTableTrailer(uxrefOffset, uxref, gTrue /* write all entries */,
+ uxref->getNumObjects(), outStr, gFalse /* complete rewrite */);
+ delete uxref;
+}
+
+void PDFDoc::writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen)
+{
+ Object obj1;
+ outStr->printf("<<");
+ for (int i=0; i<dict->getLength(); i++) {
+ GooString keyName(dict->getKey(i));
+ GooString *keyNameToPrint = keyName.sanitizedName(gFalse /* non ps mode */);
+ outStr->printf("/%s ", keyNameToPrint->getCString());
+ delete keyNameToPrint;
+ writeObject(dict->getValNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ obj1.free();
+ }
+ outStr->printf(">> ");
+}
+
+void PDFDoc::writeStream (Stream* str, OutStream* outStr)
+{
+ outStr->printf("stream\r\n");
+ str->reset();
+ for (int c=str->getChar(); c!= EOF; c=str->getChar()) {
+ outStr->printf("%c", c);
+ }
+ outStr->printf("\r\nendstream\r\n");
+}
+
+void PDFDoc::writeRawStream (Stream* str, OutStream* outStr)
+{
+ Object obj1;
+ str->getDict()->lookup("Length", &obj1);
+ if (!obj1.isInt() && !obj1.isInt64()) {
+ error (errSyntaxError, -1, "PDFDoc::writeRawStream, no Length in stream dict");
+ return;
+ }
+
+ Goffset length;
+ if (obj1.isInt())
+ length = obj1.getInt();
+ else
+ length = obj1.getInt64();
+ obj1.free();
+
+ outStr->printf("stream\r\n");
+ str->unfilteredReset();
+ for (Goffset i = 0; i < length; i++) {
+ int c = str->getUnfilteredChar();
+ if (unlikely(c == EOF)) {
+ error (errSyntaxError, -1, "PDFDoc::writeRawStream: EOF reading stream");
+ break;
+ }
+ outStr->printf("%c", c);
+ }
+ str->reset();
+ outStr->printf("\r\nendstream\r\n");
+}
+
+void PDFDoc::writeString (GooString* s, OutStream* outStr, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen)
+{
+ // Encrypt string if encryption is enabled
+ GooString *sEnc = NULL;
+ if (fileKey) {
+ Object obj;
+ EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), obj.initNull()),
+ fileKey, encAlgorithm, keyLength, objNum, objGen);
+ sEnc = new GooString();
+ int c;
+ enc->reset();
+ while ((c = enc->getChar()) != EOF) {
+ sEnc->append((char)c);
+ }
+
+ delete enc;
+ s = sEnc;
+ }
+
+ // Write data
+ if (s->hasUnicodeMarker()) {
+ //unicode string don't necessary end with \0
+ const char* c = s->getCString();
+ outStr->printf("(");
+ for(int i=0; i<s->getLength(); i++) {
+ char unescaped = *(c+i)&0x000000ff;
+ //escape if needed
+ if (unescaped == '(' || unescaped == ')' || unescaped == '\\')
+ outStr->printf("%c", '\\');
+ outStr->printf("%c", unescaped);
+ }
+ outStr->printf(") ");
+ } else {
+ const char* c = s->getCString();
+ outStr->printf("(");
+ for(int i=0; i<s->getLength(); i++) {
+ char unescaped = *(c+i)&0x000000ff;
+ //escape if needed
+ if (unescaped == '\r')
+ outStr->printf("\\r");
+ else if (unescaped == '\n')
+ outStr->printf("\\n");
+ else {
+ if (unescaped == '(' || unescaped == ')' || unescaped == '\\') {
+ outStr->printf("%c", '\\');
+ }
+ outStr->printf("%c", unescaped);
+ }
+ }
+ outStr->printf(") ");
+ }
+
+ delete sEnc;
+}
+
+Goffset PDFDoc::writeObjectHeader (Ref *ref, OutStream* outStr)
+{
+ Goffset offset = outStr->getPos();
+ outStr->printf("%i %i obj ", ref->num, ref->gen);
+ return offset;
+}
+
+void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen)
+{
+ Array *array;
+ Object obj1;
+ Goffset tmp;
+
+ switch (obj->getType()) {
+ case objBool:
+ outStr->printf("%s ", obj->getBool()?"true":"false");
+ break;
+ case objInt:
+ outStr->printf("%i ", obj->getInt());
+ break;
+ case objInt64:
+ outStr->printf("%lli ", obj->getInt64());
+ break;
+ case objReal:
+ {
+ GooString s;
+ s.appendf("{0:.10g}", obj->getReal());
+ outStr->printf("%s ", s.getCString());
+ break;
+ }
+ case objString:
+ writeString(obj->getString(), outStr, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ break;
+ case objName:
+ {
+ GooString name(obj->getName());
+ GooString *nameToPrint = name.sanitizedName(gFalse /* non ps mode */);
+ outStr->printf("/%s ", nameToPrint->getCString());
+ delete nameToPrint;
+ break;
+ }
+ case objNull:
+ outStr->printf( "null ");
+ break;
+ case objArray:
+ array = obj->getArray();
+ outStr->printf("[");
+ for (int i=0; i<array->getLength(); i++) {
+ writeObject(array->getNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ obj1.free();
+ }
+ outStr->printf("] ");
+ break;
+ case objDict:
+ writeDictionnary (obj->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ break;
+ case objStream:
+ {
+ //We can't modify stream with the current implementation (no write functions in Stream API)
+ // => the only type of streams which that have been modified are internal streams (=strWeird)
+ Stream *stream = obj->getStream();
+ if (stream->getKind() == strWeird || stream->getKind() == strCrypt) {
+ //we write the stream unencoded => TODO: write stream encoder
+
+ // Encrypt stream
+ EncryptStream *encStream = NULL;
+ GBool removeFilter = gTrue;
+ if (stream->getKind() == strWeird && fileKey) {
+ Object filter;
+ stream->getDict()->lookup("Filter", &filter);
+ if (!filter.isName("Crypt")) {
+ if (filter.isArray()) {
+ for (int i = 0; i < filter.arrayGetLength(); i++) {
+ Object filterEle;
+ filter.arrayGet(i, &filterEle);
+ if (filterEle.isName("Crypt")) {
+ filterEle.free();
+ removeFilter = gFalse;
+ break;
+ }
+ filterEle.free();
+ }
+ if (removeFilter) {
+ encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ encStream->setAutoDelete(gFalse);
+ stream = encStream;
+ }
+ } else {
+ encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ encStream->setAutoDelete(gFalse);
+ stream = encStream;
+ }
+ } else {
+ removeFilter = gFalse;
+ }
+ filter.free();
+ } else if (fileKey != NULL) { // Encrypt stream
+ encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ encStream->setAutoDelete(gFalse);
+ stream = encStream;
+ }
+
+ stream->reset();
+ //recalculate stream length
+ tmp = 0;
+ for (int c=stream->getChar(); c!=EOF; c=stream->getChar()) {
+ tmp++;
+ }
+ obj1.initInt64(tmp);
+ stream->getDict()->set("Length", &obj1);
+
+ //Remove Stream encoding
+ if (removeFilter) {
+ stream->getDict()->remove("Filter");
+ }
+ stream->getDict()->remove("DecodeParms");
+
+ writeDictionnary (stream->getDict(),outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ writeStream (stream,outStr);
+ delete encStream;
+ obj1.free();
+ } else {
+ //raw stream copy
+ FilterStream *fs = dynamic_cast<FilterStream*>(stream);
+ if (fs) {
+ BaseStream *bs = fs->getBaseStream();
+ if (bs) {
+ Goffset streamEnd;
+ if (xRef->getStreamEnd(bs->getStart(), &streamEnd)) {
+ Object val;
+ val.initInt64(streamEnd - bs->getStart());
+ stream->getDict()->set("Length", &val);
+ }
+ }
+ }
+ writeDictionnary (stream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ writeRawStream (stream, outStr);
+ }
+ break;
+ }
+ case objRef:
+ outStr->printf("%i %i R ", obj->getRef().num + numOffset, obj->getRef().gen);
+ break;
+ case objCmd:
+ outStr->printf("%s\n", obj->getCmd());
+ break;
+ case objError:
+ outStr->printf("error\r\n");
+ break;
+ case objEOF:
+ outStr->printf("eof\r\n");
+ break;
+ case objNone:
+ outStr->printf("none\r\n");
+ break;
+ default:
+ error(errUnimplemented, -1,"Unhandled objType : {0:d}, please report a bug with a testcase\r\n", obj->getType());
+ break;
+ }
+}
+
+void PDFDoc::writeObjectFooter (OutStream* outStr)
+{
+ outStr->printf("endobj\r\n");
+}
+
+Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxRef,
+ Ref *root, XRef *xRef, const char *fileName, Goffset fileSize)
+{
+ Dict *trailerDict = new Dict(xRef);
+ Object obj1;
+ obj1.initInt(uxrefSize);
+ trailerDict->set("Size", &obj1);
+ obj1.free();
+
+ //build a new ID, as recommended in the reference, uses:
+ // - current time
+ // - file name
+ // - file size
+ // - values of entry in information dictionnary
+ GooString message;
+ char buffer[256];
+ sprintf(buffer, "%i", (int)time(NULL));
+ message.append(buffer);
+
+ if (fileName)
+ message.append(fileName);
+
+ sprintf(buffer, "%lli", (long long)fileSize);
+ message.append(buffer);
+
+ //info dict -- only use text string
+ if (!xRef->getTrailerDict()->isNone() && xRef->getDocInfo(&obj1)->isDict()) {
+ for(int i=0; i<obj1.getDict()->getLength(); i++) {
+ Object obj2;
+ obj1.getDict()->getVal(i, &obj2);
+ if (obj2.isString()) {
+ message.append(obj2.getString());
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ GBool hasEncrypt = gFalse;
+ if (!xRef->getTrailerDict()->isNone()) {
+ Object obj2;
+ xRef->getTrailerDict()->dictLookupNF("Encrypt", &obj2);
+ if (!obj2.isNull()) {
+ trailerDict->set("Encrypt", &obj2);
+ hasEncrypt = gTrue;
+ obj2.free();
+ }
+ }
+
+ //calculate md5 digest
+ Guchar digest[16];
+ md5((Guchar*)message.getCString(), message.getLength(), digest);
+ obj1.initString(new GooString((const char*)digest, 16));
+
+ //create ID array
+ Object obj2,obj3,obj5;
+ obj2.initArray(xRef);
+
+ // In case of encrypted files, the ID must not be changed because it's used to calculate the key
+ if (incrUpdate || hasEncrypt) {
+ Object obj4;
+ //only update the second part of the array
+ xRef->getTrailerDict()->getDict()->lookup("ID", &obj4);
+ if (!obj4.isArray()) {
+ error(errSyntaxWarning, -1, "PDFDoc::createTrailerDict original file's ID entry isn't an array. Trying to continue");
+ } else {
+ //Get the first part of the ID
+ obj4.arrayGet(0,&obj3);
+
+ obj2.arrayAdd(&obj3);
+ obj2.arrayAdd(&obj1);
+ trailerDict->set("ID", &obj2);
+ }
+ obj4.free();
+ } else {
+ //new file => same values for the two identifiers
+ obj2.arrayAdd(&obj1);
+ obj1.initString(new GooString((const char*)digest, 16));
+ obj2.arrayAdd(&obj1);
+ trailerDict->set("ID", &obj2);
+ }
+
+ obj1.initRef(root->num, root->gen);
+ trailerDict->set("Root", &obj1);
+
+ if (incrUpdate) {
+ obj1.initInt64(startxRef);
+ trailerDict->set("Prev", &obj1);
+ }
+
+ if (!xRef->getTrailerDict()->isNone()) {
+ xRef->getDocInfoNF(&obj5);
+ if (!obj5.isNull()) {
+ trailerDict->set("Info", &obj5);
+ }
+ }
+
+ return trailerDict;
+}
+
+void PDFDoc::writeXRefTableTrailer(Dict *trailerDict, XRef *uxref, GBool writeAllEntries, Goffset uxrefOffset, OutStream* outStr, XRef *xRef)
+{
+ uxref->writeTableToFile( outStr, writeAllEntries );
+ outStr->printf( "trailer\r\n");
+ writeDictionnary(trailerDict, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0);
+ outStr->printf( "\r\nstartxref\r\n");
+ outStr->printf( "%lli\r\n", uxrefOffset);
+ outStr->printf( "%%%%EOF\r\n");
+}
+
+void PDFDoc::writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream* outStr, XRef *xRef)
+{
+ GooString stmData;
+
+ // Fill stmData and some trailerDict fields
+ uxref->writeStreamToBuffer(&stmData, trailerDict, xRef);
+
+ // Create XRef stream object and write it
+ Object obj1;
+ MemStream *mStream = new MemStream( stmData.getCString(), 0,
+ stmData.getLength(), obj1.initDict(trailerDict) );
+ writeObjectHeader(uxrefStreamRef, outStr);
+ writeObject(obj1.initStream(mStream), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0);
+ writeObjectFooter(outStr);
+ obj1.free();
+
+ outStr->printf( "startxref\r\n");
+ outStr->printf( "%lli\r\n", uxrefOffset);
+ outStr->printf( "%%%%EOF\r\n");
+}
+
+void PDFDoc::writeXRefTableTrailer(Goffset uxrefOffset, XRef *uxref, GBool writeAllEntries,
+ int uxrefSize, OutStream* outStr, GBool incrUpdate)
+{
+ const char *fileNameA = fileName ? fileName->getCString() : NULL;
+ // file size (doesn't include the trailer)
+ unsigned int fileSize = 0;
+ int c;
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ fileSize++;
+ }
+ str->close();
+ Ref ref;
+ ref.num = getXRef()->getRootNum();
+ ref.gen = getXRef()->getRootGen();
+ Dict * trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref,
+ getXRef(), fileNameA, fileSize);
+ writeXRefTableTrailer(trailerDict, uxref, writeAllEntries, uxrefOffset, outStr, getXRef());
+ delete trailerDict;
+}
+
+void PDFDoc::writeHeader(OutStream *outStr, int major, int minor)
+{
+ outStr->printf("%%PDF-%d.%d\n", major, minor);
+ outStr->printf("%%\xE2\xE3\xCF\xD3\n");
+}
+
+void PDFDoc::markDictionnary (Dict* dict, XRef * xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum)
+{
+ Object obj1;
+ for (int i=0; i<dict->getLength(); i++) {
+ const char *key = dict->getKey(i);
+ if (strcmp(key, "Annots") != 0) {
+ markObject(dict->getValNF(i, &obj1), xRef, countRef, numOffset, oldRefNum, newRefNum);
+ } else {
+ Object annotsObj;
+ dict->getValNF(i, &annotsObj);
+ if (!annotsObj.isNull()) {
+ markAnnotations(&annotsObj, xRef, countRef, 0, oldRefNum, newRefNum);
+ annotsObj.free();
+ }
+ }
+ obj1.free();
+ }
+}
+
+void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum)
+{
+ Array *array;
+ Object obj1;
+
+ switch (obj->getType()) {
+ case objArray:
+ array = obj->getArray();
+ for (int i=0; i<array->getLength(); i++) {
+ markObject(array->getNF(i, &obj1), xRef, countRef, numOffset, oldRefNum, newRefNum);
+ obj1.free();
+ }
+ break;
+ case objDict:
+ markDictionnary (obj->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum);
+ break;
+ case objStream:
+ {
+ Stream *stream = obj->getStream();
+ markDictionnary (stream->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum);
+ }
+ break;
+ case objRef:
+ {
+ if (obj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree) {
+ if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryFree) {
+ return; // already marked as free => should be replaced
+ }
+ xRef->add(obj->getRef().num + numOffset, obj->getRef().gen, 0, gTrue);
+ if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryCompressed) {
+ xRef->getEntry(obj->getRef().num + numOffset)->type = xrefEntryCompressed;
+ }
+ }
+ if (obj->getRef().num + (int) numOffset >= countRef->getNumObjects() ||
+ countRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree)
+ {
+ countRef->add(obj->getRef().num + numOffset, 1, 0, gTrue);
+ } else {
+ XRefEntry *entry = countRef->getEntry(obj->getRef().num + numOffset);
+ entry->gen++;
+ if (entry->gen > 9)
+ break;
+ }
+ Object obj1;
+ getXRef()->fetch(obj->getRef().num, obj->getRef().gen, &obj1);
+ markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum);
+ obj1.free();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void PDFDoc::replacePageDict(int pageNo, int rotate,
+ PDFRectangle *mediaBox,
+ PDFRectangle *cropBox)
+{
+ Ref *refPage = getCatalog()->getPageRef(pageNo);
+ Object page;
+ getXRef()->fetch(refPage->num, refPage->gen, &page);
+ Dict *pageDict = page.getDict();
+ pageDict->remove("MediaBoxssdf");
+ pageDict->remove("MediaBox");
+ pageDict->remove("CropBox");
+ pageDict->remove("ArtBox");
+ pageDict->remove("BleedBox");
+ pageDict->remove("TrimBox");
+ pageDict->remove("Rotate");
+ Object mediaBoxObj;
+ mediaBoxObj.initArray(getXRef());
+ Object murx;
+ murx.initReal(mediaBox->x1);
+ Object mury;
+ mury.initReal(mediaBox->y1);
+ Object mllx;
+ mllx.initReal(mediaBox->x2);
+ Object mlly;
+ mlly.initReal(mediaBox->y2);
+ mediaBoxObj.arrayAdd(&murx);
+ mediaBoxObj.arrayAdd(&mury);
+ mediaBoxObj.arrayAdd(&mllx);
+ mediaBoxObj.arrayAdd(&mlly);
+ pageDict->add(copyString("MediaBox"), &mediaBoxObj);
+ if (cropBox != NULL) {
+ Object cropBoxObj;
+ cropBoxObj.initArray(getXRef());
+ Object curx;
+ curx.initReal(cropBox->x1);
+ Object cury;
+ cury.initReal(cropBox->y1);
+ Object cllx;
+ cllx.initReal(cropBox->x2);
+ Object clly;
+ clly.initReal(cropBox->y2);
+ cropBoxObj.arrayAdd(&curx);
+ cropBoxObj.arrayAdd(&cury);
+ cropBoxObj.arrayAdd(&cllx);
+ cropBoxObj.arrayAdd(&clly);
+ pageDict->add(copyString("CropBox"), &cropBoxObj);
+ cropBoxObj.getArray()->incRef();
+ pageDict->add(copyString("TrimBox"), &cropBoxObj);
+ } else {
+ mediaBoxObj.getArray()->incRef();
+ pageDict->add(copyString("TrimBox"), &mediaBoxObj);
+ }
+ Object rotateObj;
+ rotateObj.initInt(rotate);
+ pageDict->add(copyString("Rotate"), &rotateObj);
+ getXRef()->setModifiedObject(&page, *refPage);
+ page.free();
+}
+
+void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum)
+{
+ pageDict->remove("OpenAction");
+ pageDict->remove("Outlines");
+ pageDict->remove("StructTreeRoot");
+
+ for (int n = 0; n < pageDict->getLength(); n++) {
+ const char *key = pageDict->getKey(n);
+ Object value; pageDict->getValNF(n, &value);
+ if (strcmp(key, "Parent") != 0 &&
+ strcmp(key, "Pages") != 0 &&
+ strcmp(key, "AcroForm") != 0 &&
+ strcmp(key, "Annots") != 0 &&
+ strcmp(key, "P") != 0 &&
+ strcmp(key, "Root") != 0) {
+ markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum);
+ }
+ value.free();
+ }
+}
+
+GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum) {
+ Object annots;
+ GBool modified = gFalse;
+ annotsObj->fetch(getXRef(), &annots);
+ if (annots.isArray()) {
+ Array *array = annots.getArray();
+ for (int i=array->getLength() - 1; i >= 0; i--) {
+ Object obj1;
+ if (array->get(i, &obj1)->isDict()) {
+ Object type;
+ Dict *dict = obj1.getDict();
+ dict->lookup("Type", &type);
+ if (type.isName() && strcmp(type.getName(), "Annot") == 0) {
+ Object obj2;
+ if (dict->lookupNF("P", &obj2)->isRef()) {
+ if (obj2.getRef().num == oldPageNum) {
+ Object obj3;
+ array->getNF(i, &obj3);
+ if (obj3.isRef()) {
+ Object *newRef = new Object();
+ newRef->initRef(newPageNum, 0);
+ dict->set("P", newRef);
+ getXRef()->setModifiedObject(&obj1, obj3.getRef());
+ }
+ obj3.free();
+ } else if (obj2.getRef().num == newPageNum) {
+ obj1.free();
+ obj2.free();
+ type.free();
+ continue;
+ } else {
+ Object page;
+ getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen, &page);
+ if (page.isDict()) {
+ Object pagetype;
+ Dict *dict = page.getDict();
+ dict->lookup("Type", &pagetype);
+ if (!pagetype.isName() || strcmp(pagetype.getName(), "Page") != 0) {
+ obj1.free();
+ obj2.free();
+ type.free();
+ page.free();
+ pagetype.free();
+ continue;
+ }
+ pagetype.free();
+ }
+ page.free();
+ obj1.free();
+ obj2.free();
+ type.free();
+ array->remove(i);
+ modified = gTrue;
+ continue;
+ }
+ }
+ obj2.free();
+ }
+ type.free();
+ markPageObjects(dict, xRef, countRef, numOffset, oldPageNum, newPageNum);
+ }
+ obj1.free();
+ array->getNF(i, &obj1);
+ if (obj1.isRef()) {
+ if (obj1.getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) {
+ if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryFree) {
+ continue; // already marked as free => should be replaced
+ }
+ xRef->add(obj1.getRef().num + numOffset, obj1.getRef().gen, 0, gTrue);
+ if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryCompressed) {
+ xRef->getEntry(obj1.getRef().num + numOffset)->type = xrefEntryCompressed;
+ }
+ }
+ if (obj1.getRef().num + (int) numOffset >= countRef->getNumObjects() ||
+ countRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree)
+ {
+ countRef->add(obj1.getRef().num + numOffset, 1, 0, gTrue);
+ } else {
+ XRefEntry *entry = countRef->getEntry(obj1.getRef().num + numOffset);
+ entry->gen++;
+ }
+ }
+ obj1.free();
+ }
+ }
+ if (annotsObj->isRef()) {
+ if (annotsObj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(annotsObj->getRef().num + numOffset)->type == xrefEntryFree) {
+ if (getXRef()->getEntry(annotsObj->getRef().num)->type == xrefEntryFree) {
+ return modified; // already marked as free => should be replaced
+ }
+ xRef->add(annotsObj->getRef().num + numOffset, annotsObj->getRef().gen, 0, gTrue);
+ if (getXRef()->getEntry(annotsObj->getRef().num)->type == xrefEntryCompressed) {
+ xRef->getEntry(annotsObj->getRef().num + numOffset)->type = xrefEntryCompressed;
+ }
+ }
+ if (annotsObj->getRef().num + (int) numOffset >= countRef->getNumObjects() ||
+ countRef->getEntry(annotsObj->getRef().num + numOffset)->type == xrefEntryFree)
+ {
+ countRef->add(annotsObj->getRef().num + numOffset, 1, 0, gTrue);
+ } else {
+ XRefEntry *entry = countRef->getEntry(annotsObj->getRef().num + numOffset);
+ entry->gen++;
+ }
+ getXRef()->setModifiedObject(&annots, annotsObj->getRef());
+ }
+ annots.free();
+ return modified;
+}
+
+void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) {
+ Object acroform;
+ GBool modified = gFalse;
+ afObj->fetch(getXRef(), &acroform);
+ if (acroform.isDict()) {
+ Dict *dict = acroform.getDict();
+ for (int i=0; i < dict->getLength(); i++) {
+ if (strcmp(dict->getKey(i), "Fields") == 0) {
+ Object fields;
+ modified = markAnnotations(dict->getValNF(i, &fields), xRef, countRef, numOffset, oldRefNum, newRefNum);
+ fields.free();
+ } else {
+ Object obj;
+ markObject(dict->getValNF(i, &obj), xRef, countRef, numOffset, oldRefNum, newRefNum);
+ obj.free();
+ }
+ }
+ }
+ if (afObj->isRef()) {
+ if (afObj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(afObj->getRef().num + numOffset)->type == xrefEntryFree) {
+ if (getXRef()->getEntry(afObj->getRef().num)->type == xrefEntryFree) {
+ return; // already marked as free => should be replaced
+ }
+ xRef->add(afObj->getRef().num + numOffset, afObj->getRef().gen, 0, gTrue);
+ if (getXRef()->getEntry(afObj->getRef().num)->type == xrefEntryCompressed) {
+ xRef->getEntry(afObj->getRef().num + numOffset)->type = xrefEntryCompressed;
+ }
+ }
+ if (afObj->getRef().num + (int) numOffset >= countRef->getNumObjects() ||
+ countRef->getEntry(afObj->getRef().num + numOffset)->type == xrefEntryFree)
+ {
+ countRef->add(afObj->getRef().num + numOffset, 1, 0, gTrue);
+ } else {
+ XRefEntry *entry = countRef->getEntry(afObj->getRef().num + numOffset);
+ entry->gen++;
+ }
+ if (modified){
+ getXRef()->setModifiedObject(&acroform, afObj->getRef());
+ }
+ }
+ acroform.free();
+ return;
+}
+
+Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, GBool combine)
+{
+ Guint objectsCount = 0; //count the number of objects in the XRef(s)
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ xRef->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
+
+ for (int n = numOffset; n < xRef->getNumObjects(); n++) {
+ if (xRef->getEntry(n)->type != xrefEntryFree) {
+ Object obj;
+ Ref ref;
+ ref.num = n;
+ ref.gen = xRef->getEntry(n)->gen;
+ objectsCount++;
+ getXRef()->fetch(ref.num - numOffset, ref.gen, &obj);
+ Goffset offset = writeObjectHeader(&ref, outStr);
+ if (combine) {
+ writeObject(&obj, outStr, getXRef(), numOffset, NULL, cryptRC4, 0, 0, 0);
+ } else if (xRef->getEntry(n)->getFlag(XRefEntry::Unencrypted)) {
+ writeObject(&obj, outStr, NULL, cryptRC4, 0, 0, 0);
+ } else {
+ writeObject(&obj, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
+ }
+ writeObjectFooter(outStr);
+ xRef->add(ref.num, ref.gen, offset, gTrue);
+ obj.free();
+ }
+ }
+ return objectsCount;
+}
+
+#ifndef DISABLE_OUTLINE
+Outline *PDFDoc::getOutline()
+{
+ if (!outline) {
+ pdfdocLocker();
+ // read outline
+ outline = new Outline(catalog->getOutline(), xref);
+ }
+
+ return outline;
+}
+#endif
+
+PDFDoc *PDFDoc::ErrorPDFDoc(int errorCode, GooString *fileNameA)
+{
+ PDFDoc *doc = new PDFDoc();
+ doc->errCode = errorCode;
+ doc->fileName = fileNameA;
+
+ return doc;
+}
+
+long long PDFDoc::strToLongLong(char *s) {
+ long long x, d;
+ char *p;
+
+ x = 0;
+ for (p = s; *p && isdigit(*p & 0xff); ++p) {
+ d = *p - '0';
+ if (x > (LLONG_MAX - d) / 10) {
+ break;
+ }
+ x = 10 * x + d;
+ }
+ return x;
+}
+
+// Read the 'startxref' position.
+Goffset PDFDoc::getStartXRef(GBool tryingToReconstruct)
+{
+ if (startXRefPos == -1) {
+
+ if (isLinearized(tryingToReconstruct)) {
+ char buf[linearizationSearchSize+1];
+ int c, n, i;
+
+ str->setPos(0);
+ for (n = 0; n < linearizationSearchSize; ++n) {
+ if ((c = str->getChar()) == EOF) {
+ break;
+ }
+ buf[n] = c;
+ }
+ buf[n] = '\0';
+
+ // find end of first obj (linearization dictionary)
+ startXRefPos = 0;
+ for (i = 0; i < n; i++) {
+ if (!strncmp("endobj", &buf[i], 6)) {
+ i += 6;
+ //skip whitespace
+ while (buf[i] && Lexer::isSpace(buf[i])) ++i;
+ startXRefPos = i;
+ break;
+ }
+ }
+ } else {
+ char buf[xrefSearchSize+1];
+ char *p;
+ int c, n, i;
+
+ // read last xrefSearchSize bytes
+ int segnum = 0;
+ int maxXRefSearch = 24576;
+ if (str->getLength() < maxXRefSearch) maxXRefSearch = str->getLength();
+ for (; (xrefSearchSize - 16) * segnum < maxXRefSearch; segnum++) {
+ str->setPos((xrefSearchSize - 16) * segnum + xrefSearchSize, -1);
+ for (n = 0; n < xrefSearchSize; ++n) {
+ if ((c = str->getChar()) == EOF) {
+ break;
+ }
+ buf[n] = c;
+ }
+ buf[n] = '\0';
+
+ // find startxref
+ for (i = n - 9; i >= 0; --i) {
+ if (!strncmp(&buf[i], "startxref", 9)) {
+ break;
+ }
+ }
+ if (i < 0) {
+ startXRefPos = 0;
+ } else {
+ for (p = &buf[i + 9]; isspace(*p); ++p);
+ startXRefPos = strToLongLong(p);
+ break;
+ }
+ }
+ }
+
+ }
+
+ return startXRefPos;
+}
+
+Goffset PDFDoc::getMainXRefEntriesOffset(GBool tryingToReconstruct)
+{
+ Guint mainXRefEntriesOffset = 0;
+
+ if (isLinearized(tryingToReconstruct)) {
+ mainXRefEntriesOffset = getLinearization()->getMainXRefEntriesOffset();
+ }
+
+ return mainXRefEntriesOffset;
+}
+
+int PDFDoc::getNumPages()
+{
+ if (isLinearized()) {
+ int n;
+ if ((n = getLinearization()->getNumPages())) {
+ return n;
+ }
+ }
+
+ return catalog->getNumPages();
+}
+
+Page *PDFDoc::parsePage(int page)
+{
+ Page *p = NULL;
+ Object obj;
+ Ref pageRef;
+ Dict *pageDict;
+
+ pageRef.num = getHints()->getPageObjectNum(page);
+ if (!pageRef.num) {
+ error(errSyntaxWarning, -1, "Failed to get object num from hint tables for page {0:d}", page);
+ return NULL;
+ }
+
+ // check for bogus ref - this can happen in corrupted PDF files
+ if (pageRef.num < 0 || pageRef.num >= xref->getNumObjects()) {
+ error(errSyntaxWarning, -1, "Invalid object num ({0:d}) for page {1:d}", pageRef.num, page);
+ return NULL;
+ }
+
+ pageRef.gen = xref->getEntry(pageRef.num)->gen;
+ xref->fetch(pageRef.num, pageRef.gen, &obj);
+ if (!obj.isDict("Page")) {
+ obj.free();
+ error(errSyntaxWarning, -1, "Object ({0:d} {1:d}) is not a pageDict", pageRef.num, pageRef.gen);
+ return NULL;
+ }
+ pageDict = obj.getDict();
+
+ p = new Page(this, page, pageDict, pageRef,
+ new PageAttrs(NULL, pageDict), catalog->getForm());
+ obj.free();
+
+ return p;
+}
+
+Page *PDFDoc::getPage(int page)
+{
+ if ((page < 1) || page > getNumPages()) return NULL;
+
+ if (isLinearized()) {
+ pdfdocLocker();
+ if (!pageCache) {
+ pageCache = (Page **) gmallocn(getNumPages(), sizeof(Page *));
+ for (int i = 0; i < getNumPages(); i++) {
+ pageCache[i] = NULL;
+ }
+ }
+ if (!pageCache[page-1]) {
+ pageCache[page-1] = parsePage(page);
+ }
+ if (pageCache[page-1]) {
+ return pageCache[page-1];
+ } else {
+ error(errSyntaxWarning, -1, "Failed parsing page {0:d} using hint tables", page);
+ }
+ }
+
+ return catalog->getPage(page);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDoc.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDoc.h
new file mode 100644
index 00000000000..6c40f7b0c0c
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDoc.h
@@ -0,0 +1,343 @@
+//========================================================================
+//
+// PDFDoc.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2006, 2008 Brad Hards <bradh@frogmouth.net>
+// Copyright (C) 2005, 2009, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2008 Pino Toscano <pino@kde.org>
+// Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009 Eric Toombs <ewtoombs@uwaterloo.ca>
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2010, 2014 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2010 Srinivas Adicherla <srinivas.adicherla@geodesic.com>
+// Copyright (C) 2011, 2013, 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Adam Reichold <adamreichold@myopera.com>
+// Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef PDFDOC_H
+#define PDFDOC_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include <stdio.h>
+#include "goo/GooMutex.h"
+#include "XRef.h"
+#include "Catalog.h"
+#include "Page.h"
+#include "Annot.h"
+#include "OptionalContent.h"
+#include "Stream.h"
+
+class GooString;
+class GooFile;
+class BaseStream;
+class OutputDev;
+class Links;
+class LinkAction;
+class LinkDest;
+class Outline;
+class Linearization;
+class SecurityHandler;
+class Hints;
+class StructTreeRoot;
+
+enum PDFWriteMode {
+ writeStandard,
+ writeForceRewrite,
+ writeForceIncremental
+};
+
+//------------------------------------------------------------------------
+// PDFDoc
+//------------------------------------------------------------------------
+
+class PDFDoc {
+public:
+
+ PDFDoc(GooString *fileNameA, GooString *ownerPassword = NULL,
+ GooString *userPassword = NULL, void *guiDataA = NULL);
+
+#ifdef _WIN32
+ PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword = NULL,
+ GooString *userPassword = NULL, void *guiDataA = NULL);
+#endif
+
+ PDFDoc(BaseStream *strA, GooString *ownerPassword = NULL,
+ GooString *userPassword = NULL, void *guiDataA = NULL);
+ ~PDFDoc();
+
+ static PDFDoc *ErrorPDFDoc(int errorCode, GooString *fileNameA = NULL);
+
+ // Was PDF document successfully opened?
+ GBool isOk() { return ok; }
+
+ // Get the error code (if isOk() returns false).
+ int getErrorCode() { return errCode; }
+
+ // Get the error code returned by fopen() (if getErrorCode() ==
+ // errOpenFile).
+ int getFopenErrno() { return fopenErrno; }
+
+ // Get file name.
+ GooString *getFileName() { return fileName; }
+#ifdef _WIN32
+ wchar_t *getFileNameU() { return fileNameU; }
+#endif
+
+ // Get the linearization table.
+ Linearization *getLinearization();
+
+ // Get the xref table.
+ XRef *getXRef() { return xref; }
+
+ // Get catalog.
+ Catalog *getCatalog() { return catalog; }
+
+ // Get optional content configuration
+ OCGs *getOptContentConfig() { return catalog->getOptContentConfig(); }
+
+ // Get base stream.
+ BaseStream *getBaseStream() { return str; }
+
+ // Get page parameters.
+ double getPageMediaWidth(int page)
+ { return getPage(page) ? getPage(page)->getMediaWidth() : 0.0 ; }
+ double getPageMediaHeight(int page)
+ { return getPage(page) ? getPage(page)->getMediaHeight() : 0.0 ; }
+ double getPageCropWidth(int page)
+ { return getPage(page) ? getPage(page)->getCropWidth() : 0.0 ; }
+ double getPageCropHeight(int page)
+ { return getPage(page) ? getPage(page)->getCropHeight() : 0.0 ; }
+ int getPageRotate(int page)
+ { return getPage(page) ? getPage(page)->getRotate() : 0 ; }
+
+ // Get number of pages.
+ int getNumPages();
+
+ // Return the contents of the metadata stream, or NULL if there is
+ // no metadata.
+ GooString *readMetadata() { return catalog->readMetadata(); }
+
+ // Return the structure tree root object.
+ StructTreeRoot *getStructTreeRoot() { return catalog->getStructTreeRoot(); }
+
+ // Get page.
+ Page *getPage(int page);
+
+ // Display a page.
+ void displayPage(OutputDev *out, int page,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+ void *annotDisplayDecideCbkData = NULL, GBool copyXRef = gFalse);
+
+ // Display a range of pages.
+ void displayPages(OutputDev *out, int firstPage, int lastPage,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+ void *annotDisplayDecideCbkData = NULL);
+
+ // Display part of a page.
+ void displayPageSlice(OutputDev *out, int page,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+ void *annotDisplayDecideCbkData = NULL, GBool copyXRef = gFalse);
+
+ // Find a page, given its object ID. Returns page number, or 0 if
+ // not found.
+ int findPage(int num, int gen) { return catalog->findPage(num, gen); }
+
+ // Returns the links for the current page, transferring ownership to
+ // the caller.
+ Links *getLinks(int page);
+
+ // Find a named destination. Returns the link destination, or
+ // NULL if <name> is not a destination.
+ LinkDest *findDest(GooString *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();
+#endif
+
+ // Is the file encrypted?
+ GBool isEncrypted() { return xref->isEncrypted(); }
+
+ // Check various permissions.
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToPrint(ignoreOwnerPW); }
+ GBool okToPrintHighRes(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToPrintHighRes(ignoreOwnerPW); }
+ GBool okToChange(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToChange(ignoreOwnerPW); }
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToCopy(ignoreOwnerPW); }
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToAddNotes(ignoreOwnerPW); }
+ GBool okToFillForm(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToFillForm(ignoreOwnerPW); }
+ GBool okToAccessibility(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToAccessibility(ignoreOwnerPW); }
+ GBool okToAssemble(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToAssemble(ignoreOwnerPW); }
+
+
+ // Is this document linearized?
+ GBool isLinearized(GBool tryingToReconstruct = gFalse);
+
+ // Return the document's Info dictionary (if any).
+ Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); }
+ Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); }
+
+ // Return the PDF version specified by the file.
+ int getPDFMajorVersion() { return pdfMajorVersion; }
+ int getPDFMinorVersion() { return pdfMinorVersion; }
+
+ //Return the PDF ID in the trailer dictionary (if any).
+ GBool getID(GooString *permanent_id, GooString *update_id);
+
+ // Save one page with another name.
+ int savePageAs(GooString *name, int pageNo);
+ // Save this file with another name.
+ int saveAs(GooString *name, PDFWriteMode mode=writeStandard);
+ // Save this file in the given output stream.
+ int saveAs(OutStream *outStr, PDFWriteMode mode=writeStandard);
+ // Save this file with another name without saving changes
+ int saveWithoutChangesAs(GooString *name);
+ // Save this file in the given output stream without saving changes
+ int saveWithoutChangesAs(OutStream *outStr);
+
+ // Return a pointer to the GUI (XPDFCore or WinPDFCore object).
+ void *getGUIData() { return guiData; }
+
+ // rewrite pageDict with MediaBox, CropBox and new page CTM
+ void replacePageDict(int pageNo, int rotate, PDFRectangle *mediaBox, PDFRectangle *cropBox);
+ void markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum);
+ GBool markAnnotations(Object *annots, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum);
+ void markAcroForm(Object *acrpForm, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum);
+ // write all objects used by pageDict to outStr
+ Guint writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, GBool combine = gFalse);
+ static void writeObject (Object *obj, OutStream* outStr, XRef *xref, Guint numOffset, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen);
+ static void writeHeader(OutStream *outStr, int major, int minor);
+
+ // Ownership goes to the caller
+ static Dict *createTrailerDict (int uxrefSize, GBool incrUpdate, Goffset startxRef,
+ Ref *root, XRef *xRef, const char *fileName, Goffset fileSize);
+ static void writeXRefTableTrailer (Dict *trailerDict, XRef *uxref, GBool writeAllEntries,
+ Goffset uxrefOffset, OutStream* outStr, XRef *xRef);
+ static void writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefStreamRef,
+ Goffset uxrefOffset, OutStream* outStr, XRef *xRef);
+
+private:
+ // insert referenced objects in XRef
+ void markDictionnary (Dict* dict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum);
+ void markObject (Object *obj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum);
+ static void writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen);
+
+ // Write object header to current file stream and return its offset
+ static Goffset writeObjectHeader (Ref *ref, OutStream* outStr);
+ static void writeObjectFooter (OutStream* outStr);
+
+ void writeObject (Object *obj, OutStream* outStr, Guchar *fileKey, CryptAlgorithm encAlgorithm,
+ int keyLength, int objNum, int objGen)
+ { writeObject(obj, outStr, getXRef(), 0, fileKey, encAlgorithm, keyLength, objNum, objGen); }
+ void writeDictionnary (Dict* dict, OutStream* outStr, Guchar *fileKey, CryptAlgorithm encAlgorithm,
+ int keyLength, int objNum, int objGen)
+ { writeDictionnary(dict, outStr, getXRef(), 0, fileKey, encAlgorithm, keyLength, objNum, objGen); }
+ static void writeStream (Stream* str, OutStream* outStr);
+ static void writeRawStream (Stream* str, OutStream* outStr);
+ void writeXRefTableTrailer (Goffset uxrefOffset, XRef *uxref, GBool writeAllEntries,
+ int uxrefSize, OutStream* outStr, GBool incrUpdate);
+ static void writeString (GooString* s, OutStream* outStr, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen);
+ void saveIncrementalUpdate (OutStream* outStr);
+ void saveCompleteRewrite (OutStream* outStr);
+
+ Page *parsePage(int page);
+
+ // Get hints.
+ Hints *getHints();
+
+ PDFDoc();
+ void init();
+ GBool setup(GooString *ownerPassword, GooString *userPassword);
+ GBool checkFooter();
+ void checkHeader();
+ GBool checkEncryption(GooString *ownerPassword, GooString *userPassword);
+ // Get the offset of the start xref table.
+ Goffset getStartXRef(GBool tryingToReconstruct = gFalse);
+ // Get the offset of the entries in the main XRef table of a
+ // linearized document (0 for non linearized documents).
+ Goffset getMainXRefEntriesOffset(GBool tryingToReconstruct = gFalse);
+ long long strToLongLong(char *s);
+
+ GooString *fileName;
+#ifdef _WIN32
+ wchar_t *fileNameU;
+#endif
+ GooFile *file;
+ BaseStream *str;
+ void *guiData;
+ int pdfMajorVersion;
+ int pdfMinorVersion;
+ Linearization *linearization;
+ XRef *xref;
+ SecurityHandler *secHdlr;
+ Catalog *catalog;
+ Hints *hints;
+#ifndef DISABLE_OUTLINE
+ Outline *outline;
+#endif
+ Page **pageCache;
+
+ GBool ok;
+ int errCode;
+ //If there is an error opening the PDF file with fopen() in the constructor,
+ //then the POSIX errno will be here.
+ int fopenErrno;
+
+ Goffset startXRefPos; // offset of last xref table
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocBuilder.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocBuilder.h
new file mode 100644
index 00000000000..d6eccf5487a
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocBuilder.h
@@ -0,0 +1,42 @@
+//========================================================================
+//
+// PDFDocBuilder.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef PDFDOCBUILDER_H
+#define PDFDOCBUILDER_H
+
+#include "PDFDoc.h"
+class GooString;
+
+//------------------------------------------------------------------------
+// PDFDocBuilder
+//
+// PDFDocBuilder is an abstract class that specifies the interface for
+// constructing PDFDocs.
+//------------------------------------------------------------------------
+
+class PDFDocBuilder {
+
+public:
+
+ virtual ~PDFDocBuilder() {};
+
+ // Builds a new PDFDoc. Returns a PDFDoc. You should check this PDFDoc
+ // with PDFDoc::isOk() for failures.
+ // The caller is responsible for deleting ownerPassword, userPassWord and guiData.
+ virtual PDFDoc *buildPDFDoc(const GooString &uri, GooString *ownerPassword = NULL,
+ GooString *userPassword = NULL, void *guiDataA = NULL) = 0;
+
+ // Returns gTrue if the builder supports building a PDFDoc from the URI.
+ virtual GBool supports(const GooString &uri) = 0;
+
+};
+
+#endif /* PDFDOCBUILDER_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocEncoding.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocEncoding.cc
new file mode 100644
index 00000000000..79408346419
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocEncoding.cc
@@ -0,0 +1,69 @@
+//========================================================================
+//
+// PDFDocEncoding.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include "PDFDocEncoding.h"
+
+// Mapping of PDFDocEncoding (used to represent text values such as document
+// metadata or annotation text) to Unicode codepoints. Not all 8-bit values in
+// PDFDocEncoding are defined; undefined bytes are mapped to U+FFFD (Unicode
+// replacement character).
+//
+// PDFDocEncoding is only directly defined for printable characters, but some
+// control characters such as carriage return will still be used. We define
+// mappings of the standard whitespace control characters (tabs, newlines) to
+// the corresponding Unicode values. Other control characters are left
+// undefined.
+
+Unicode pdfDocEncoding[256] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, // 00
+ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, // 10
+ 0x02d8, 0x02c7, 0x02c6, 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0xfffd,
+ 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, // 80
+ 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018,
+ 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, // 90
+ 0x0178, 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0xfffd,
+ 0x20ac, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, // a0
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0xfffd, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, // b0
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, // c0
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, // d0
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, // e0
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, // f0
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+};
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocEncoding.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocEncoding.h
new file mode 100644
index 00000000000..4f0840bb28a
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocEncoding.h
@@ -0,0 +1,34 @@
+//========================================================================
+//
+// PDFDocEncoding.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2007 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef PDFDOCENCODING_H
+#define PDFDOCENCODING_H
+
+#include "CharTypes.h"
+
+class GooString;
+
+extern Unicode pdfDocEncoding[256];
+
+char* pdfDocEncodingToUTF16 (GooString* orig, int* length);
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocFactory.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocFactory.cc
new file mode 100644
index 00000000000..1ec46477237
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocFactory.cc
@@ -0,0 +1,72 @@
+//========================================================================
+//
+// PDFDocFactory.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "PDFDocFactory.h"
+
+#include "goo/GooList.h"
+#include "goo/GooString.h"
+#include "PDFDoc.h"
+#include "LocalPDFDocBuilder.h"
+#include "StdinPDFDocBuilder.h"
+#if ENABLE_LIBCURL
+#include "CurlPDFDocBuilder.h"
+#endif
+#include "ErrorCodes.h"
+
+//------------------------------------------------------------------------
+// PDFDocFactory
+//------------------------------------------------------------------------
+
+PDFDocFactory::PDFDocFactory(GooList *pdfDocBuilders)
+{
+ if (pdfDocBuilders) {
+ builders = pdfDocBuilders;
+ } else {
+ builders = new GooList();
+ }
+#if ENABLE_LIBCURL
+ builders->insert(0, new CurlPDFDocBuilder());
+#endif
+ builders->insert(0, new StdinPDFDocBuilder());
+ builders->insert(0, new LocalPDFDocBuilder());
+}
+
+PDFDocFactory::~PDFDocFactory()
+{
+ if (builders) {
+ deleteGooList(builders, PDFDocBuilder);
+ }
+}
+
+PDFDoc *
+PDFDocFactory::createPDFDoc(const GooString &uri, GooString *ownerPassword,
+ GooString *userPassword, void *guiDataA)
+{
+ for (int i = builders->getLength() - 1; i >= 0 ; i--) {
+ PDFDocBuilder *builder = (PDFDocBuilder *) builders->get(i);
+ if (builder->supports(uri)) {
+ return builder->buildPDFDoc(uri, ownerPassword, userPassword, guiDataA);
+ }
+ }
+
+ error(errInternal, -1, "Cannot handle URI '{0:t}'.", &uri);
+ GooString *fileName = uri.copy();
+ return PDFDoc::ErrorPDFDoc(errOpenFile, fileName);
+}
+
+void PDFDocFactory::registerPDFDocBuilder(PDFDocBuilder *pdfDocBuilder)
+{
+ builders->append(pdfDocBuilder);
+}
+
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocFactory.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocFactory.h
new file mode 100644
index 00000000000..dbceaa567ee
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PDFDocFactory.h
@@ -0,0 +1,55 @@
+//========================================================================
+//
+// PDFDocFactory.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef PDFDOCFACTORY_H
+#define PDFDOCFACTORY_H
+
+#include "PDFDoc.h"
+
+class GooList;
+class GooString;
+class PDFDocBuilder;
+
+//------------------------------------------------------------------------
+// PDFDocFactory
+//
+// PDFDocFactory allows the construction of PDFDocs from different URIs.
+//
+// By default, it supports local files, 'file://' and 'fd:0' (stdin). When
+// compiled with libcurl, it also supports 'http://' and 'https://'.
+//
+// You can extend the supported URIs by giving a list of PDFDocBuilders to
+// the constructor, or by registering a new PDFDocBuilder afterwards.
+//------------------------------------------------------------------------
+
+class PDFDocFactory {
+
+public:
+
+ PDFDocFactory(GooList *pdfDocBuilders = NULL);
+ ~PDFDocFactory();
+
+ // Create a PDFDoc. Returns a PDFDoc. You should check this PDFDoc
+ // with PDFDoc::isOk() for failures.
+ // The caller is responsible for deleting ownerPassword, userPassWord and guiData.
+ PDFDoc *createPDFDoc(const GooString &uri, GooString *ownerPassword = NULL,
+ GooString *userPassword = NULL, void *guiDataA = NULL);
+
+ // Extend supported URIs with the ones from the PDFDocBuilder.
+ void registerPDFDocBuilder(PDFDocBuilder *pdfDocBuilder);
+
+private:
+
+ GooList *builders;
+
+};
+
+#endif /* PDFDOCFACTORY_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PSOutputDev.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PSOutputDev.cc
new file mode 100644
index 00000000000..7b93e3bf65a
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PSOutputDev.cc
@@ -0,0 +1,7565 @@
+//========================================================================
+//
+// PSOutputDev.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
+// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006-2009, 2011-2013, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2007, 2008 Brad Hards <bradh@kde.org>
+// Copyright (C) 2008, 2009 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2008, 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2009 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009, 2011, 2012, 2014, 2015 William Bader <williambader@hotmail.com>
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2009-2011, 2013, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012, 2014 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012 Lu Wang <coolwanglu@gmail.com>
+// Copyright (C) 2014 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2015 Marek Kasik <mkasik@redhat.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <math.h>
+#include <limits.h>
+#include "goo/GooString.h"
+#include "goo/GooList.h"
+#include "goo/GooHash.h"
+#include "poppler-config.h"
+#include "GlobalParams.h"
+#include "Object.h"
+#include "Error.h"
+#include "Function.h"
+#include "Gfx.h"
+#include "GfxState.h"
+#include "GfxFont.h"
+#include "UnicodeMap.h"
+#include <fofi/FoFiType1C.h>
+#include <fofi/FoFiTrueType.h>
+#include "Catalog.h"
+#include "Page.h"
+#include "Stream.h"
+#include "Annot.h"
+#include "XRef.h"
+#include "PreScanOutputDev.h"
+#include "FileSpec.h"
+#include "CharCodeToUnicode.h"
+#if HAVE_SPLASH
+# include "splash/Splash.h"
+# include "splash/SplashBitmap.h"
+# include "SplashOutputDev.h"
+#endif
+#include "PSOutputDev.h"
+#include "PDFDoc.h"
+
+#ifdef MACOS
+// needed for setting type/creator of MacOS files
+#include "ICSupport.h"
+#endif
+
+// the MSVC math.h doesn't define this
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//------------------------------------------------------------------------
+
+// Max size of a slice when rasterizing pages, in pixels.
+#define rasterizationSliceSize 20000000
+
+//------------------------------------------------------------------------
+// PostScript prolog and setup
+//------------------------------------------------------------------------
+
+// The '~' escapes mark prolog code that is emitted only in certain
+// levels:
+//
+// ~[123][sn]
+// ^ ^----- s=psLevel*Sep, n=psLevel*
+// +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3*
+
+static const char *prolog[] = {
+ "/xpdf 75 dict def xpdf begin",
+ "% PDF special state",
+ "/pdfDictSize 15 def",
+ "~1sn",
+ "/pdfStates 64 array def",
+ " 0 1 63 {",
+ " pdfStates exch pdfDictSize dict",
+ " dup /pdfStateIdx 3 index put",
+ " put",
+ " } for",
+ "~123sn",
+ "/pdfSetup {",
+ " /setpagedevice where {",
+ " pop 2 dict begin",
+ " /Policies 1 dict dup begin /PageSize 6 def end def",
+ " { /Duplex true def } if",
+ " currentdict end setpagedevice",
+ " } {",
+ " pop",
+ " } ifelse",
+ "} def",
+ "/pdfSetupPaper {",
+ " % Change paper size, but only if different from previous paper size otherwise",
+ " % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size",
+ " % so we use the same when checking if the size changes.",
+ " /setpagedevice where {",
+ " pop currentpagedevice",
+ " /PageSize known {",
+ " 2 copy",
+ " currentpagedevice /PageSize get aload pop",
+ " exch 4 1 roll",
+ " sub abs 5 gt",
+ " 3 1 roll",
+ " sub abs 5 gt",
+ " or",
+ " } {",
+ " true",
+ " } ifelse",
+ " {",
+ " 2 array astore",
+ " 2 dict begin",
+ " /PageSize exch def",
+ " /ImagingBBox null def",
+ " currentdict end",
+ " setpagedevice",
+ " } {",
+ " pop pop",
+ " } ifelse",
+ " } {",
+ " pop",
+ " } ifelse",
+ "} def",
+ "~1sn",
+ "/pdfOpNames [",
+ " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
+ " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender /pdfPatternCS",
+ " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
+ "] def",
+ "~123sn",
+ "/pdfStartPage {",
+ "~1sn",
+ " pdfStates 0 get begin",
+ "~23sn",
+ " pdfDictSize dict begin",
+ "~23n",
+ " /pdfFillCS [] def",
+ " /pdfFillXform {} def",
+ " /pdfStrokeCS [] def",
+ " /pdfStrokeXform {} def",
+ "~1n",
+ " /pdfFill 0 def",
+ " /pdfStroke 0 def",
+ "~1s",
+ " /pdfFill [0 0 0 1] def",
+ " /pdfStroke [0 0 0 1] def",
+ "~23sn",
+ " /pdfFill [0] def",
+ " /pdfStroke [0] def",
+ " /pdfFillOP false def",
+ " /pdfStrokeOP false def",
+ "~3sn",
+ " /pdfOPM false def",
+ "~123sn",
+ " /pdfLastFill false def",
+ " /pdfLastStroke false def",
+ " /pdfTextMat [1 0 0 1 0 0] def",
+ " /pdfFontSize 0 def",
+ " /pdfCharSpacing 0 def",
+ " /pdfTextRender 0 def",
+ " /pdfPatternCS false def",
+ " /pdfTextRise 0 def",
+ " /pdfWordSpacing 0 def",
+ " /pdfHorizScaling 1 def",
+ " /pdfTextClipPath [] def",
+ "} def",
+ "/pdfEndPage { end } def",
+ "~23s",
+ "% separation convention operators",
+ "/findcmykcustomcolor where {",
+ " pop",
+ "}{",
+ " /findcmykcustomcolor { 5 array astore } def",
+ "} ifelse",
+ "/setcustomcolor where {",
+ " pop",
+ "}{",
+ " /setcustomcolor {",
+ " exch",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval cvx",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace setcolor",
+ " } def",
+ "} ifelse",
+ "/customcolorimage where {",
+ " pop",
+ "}{",
+ " /customcolorimage {",
+ " gsave",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace",
+ " 10 dict begin",
+ " /ImageType 1 def",
+ " /DataSource exch def",
+ " /ImageMatrix exch def",
+ " /BitsPerComponent exch def",
+ " /Height exch def",
+ " /Width exch def",
+ " /Decode [1 0] def",
+ " currentdict end",
+ " image",
+ " grestore",
+ " } def",
+ "} ifelse",
+ "~123sn",
+ "% PDF color state",
+ "~1n",
+ "/g { dup /pdfFill exch def setgray",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/G { dup /pdfStroke exch def setgray",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFill setgray",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStroke setgray",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "~1s",
+ "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFill aload pop setcmykcolor",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStroke aload pop setcmykcolor",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "~3n",
+ "/opm { dup /pdfOPM exch def",
+ " /setoverprintmode where{pop setoverprintmode}{pop}ifelse } def",
+ "~23n",
+ "/cs { /pdfFillXform exch def dup /pdfFillCS exch def",
+ " setcolorspace } def",
+ "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def",
+ " setcolorspace } def",
+ "/sc { pdfLastFill not { pdfFillCS setcolorspace } if",
+ " dup /pdfFill exch def aload pop pdfFillXform setcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if",
+ " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/op { /pdfFillOP exch def",
+ " pdfLastFill { pdfFillOP setoverprint } if } def",
+ "/OP { /pdfStrokeOP exch def",
+ " pdfLastStroke { pdfStrokeOP setoverprint } if } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFillCS setcolorspace",
+ " pdfFill aload pop pdfFillXform setcolor",
+ " pdfFillOP setoverprint",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStrokeCS setcolorspace",
+ " pdfStroke aload pop pdfStrokeXform setcolor",
+ " pdfStrokeOP setoverprint",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "~3s",
+ "/opm { dup /pdfOPM exch def",
+ " /setoverprintmode where{pop setoverprintmode}{pop}ifelse } def",
+ "~23s",
+ "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/ck { 6 copy 6 array astore /pdfFill exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/CK { 6 copy 6 array astore /pdfStroke exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/op { /pdfFillOP exch def",
+ " pdfLastFill { pdfFillOP setoverprint } if } def",
+ "/OP { /pdfStrokeOP exch def",
+ " pdfLastStroke { pdfStrokeOP setoverprint } if } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFill aload length 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " pdfFillOP setoverprint",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStroke aload length 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " pdfStrokeOP setoverprint",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "~123sn",
+ "% build a font",
+ "/pdfMakeFont {",
+ " 4 3 roll findfont",
+ " 4 2 roll matrix scale makefont",
+ " dup length dict begin",
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall",
+ " /Encoding exch def",
+ " currentdict",
+ " end",
+ " definefont pop",
+ "} def",
+ "/pdfMakeFont16 {",
+ " exch findfont",
+ " dup length dict begin",
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall",
+ " /WMode exch def",
+ " currentdict",
+ " end",
+ " definefont pop",
+ "} def",
+ "~3sn",
+ "/pdfMakeFont16L3 {",
+ " 1 index /CIDFont resourcestatus {",
+ " pop pop 1 index /CIDFont findresource /CIDFontType known",
+ " } {",
+ " false",
+ " } ifelse",
+ " {",
+ " 0 eq { /Identity-H } { /Identity-V } ifelse",
+ " exch 1 array astore composefont pop",
+ " } {",
+ " pdfMakeFont16",
+ " } ifelse",
+ "} def",
+ "~123sn",
+ "% graphics state operators",
+ "~1sn",
+ "/q {",
+ " gsave",
+ " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
+ " pdfStates pdfStateIdx 1 add get begin",
+ " pdfOpNames { exch def } forall",
+ "} def",
+ "/Q { end grestore } def",
+ "~23sn",
+ "/q { gsave pdfDictSize dict begin } def",
+ "/Q {",
+ " end grestore",
+ " /pdfLastFill where {",
+ " pop",
+ " pdfLastFill {",
+ " pdfFillOP setoverprint",
+ " } {",
+ " pdfStrokeOP setoverprint",
+ " } ifelse",
+ " } if",
+ "~3sn",
+ " /pdfOPM where {",
+ " pop",
+ " pdfOPM /setoverprintmode where{pop setoverprintmode}{pop}ifelse ",
+ " } if",
+ "~23sn",
+ "} def",
+ "~123sn",
+ "/cm { concat } def",
+ "/d { setdash } def",
+ "/i { setflat } def",
+ "/j { setlinejoin } def",
+ "/J { setlinecap } def",
+ "/M { setmiterlimit } def",
+ "/w { setlinewidth } def",
+ "% path segment operators",
+ "/m { moveto } def",
+ "/l { lineto } def",
+ "/c { curveto } def",
+ "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
+ " neg 0 rlineto closepath } def",
+ "/h { closepath } def",
+ "% path painting operators",
+ "/S { sCol stroke } def",
+ "/Sf { fCol stroke } def",
+ "/f { fCol fill } def",
+ "/f* { fCol eofill } def",
+ "% clipping operators",
+ "/W { clip newpath } def",
+ "/W* { eoclip newpath } def",
+ "/Ws { strokepath clip newpath } def",
+ "% text state operators",
+ "/Tc { /pdfCharSpacing exch def } def",
+ "/Tf { dup /pdfFontSize exch def",
+ " dup pdfHorizScaling mul exch matrix scale",
+ " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
+ " exch findfont exch makefont setfont } def",
+ "/Tr { /pdfTextRender exch def } def",
+ "/Tp { /pdfPatternCS exch def } def",
+ "/Ts { /pdfTextRise exch def } def",
+ "/Tw { /pdfWordSpacing exch def } def",
+ "/Tz { /pdfHorizScaling exch def } def",
+ "% text positioning operators",
+ "/Td { pdfTextMat transform moveto } def",
+ "/Tm { /pdfTextMat exch def } def",
+ "% text string operators",
+ "/xyshow where {",
+ " pop",
+ " /xyshow2 {",
+ " dup length array",
+ " 0 2 2 index length 1 sub {",
+ " 2 index 1 index 2 copy get 3 1 roll 1 add get",
+ " pdfTextMat dtransform",
+ " 4 2 roll 2 copy 6 5 roll put 1 add 3 1 roll dup 4 2 roll put",
+ " } for",
+ " exch pop",
+ " xyshow",
+ " } def",
+ "}{",
+ " /xyshow2 {",
+ " currentfont /FontType get 0 eq {",
+ " 0 2 3 index length 1 sub {",
+ " currentpoint 4 index 3 index 2 getinterval show moveto",
+ " 2 copy get 2 index 3 2 roll 1 add get",
+ " pdfTextMat dtransform rmoveto",
+ " } for",
+ " } {",
+ " 0 1 3 index length 1 sub {",
+ " currentpoint 4 index 3 index 1 getinterval show moveto",
+ " 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get",
+ " pdfTextMat dtransform rmoveto",
+ " } for",
+ " } ifelse",
+ " pop pop",
+ " } def",
+ "} ifelse",
+ "/cshow where {",
+ " pop",
+ " /xycp {", // xycharpath
+ " 0 3 2 roll",
+ " {",
+ " pop pop currentpoint 3 2 roll",
+ " 1 string dup 0 4 3 roll put false charpath moveto",
+ " 2 copy get 2 index 2 index 1 add get",
+ " pdfTextMat dtransform rmoveto",
+ " 2 add",
+ " } exch cshow",
+ " pop pop",
+ " } def",
+ "}{",
+ " /xycp {", // xycharpath
+ " currentfont /FontType get 0 eq {",
+ " 0 2 3 index length 1 sub {",
+ " currentpoint 4 index 3 index 2 getinterval false charpath moveto",
+ " 2 copy get 2 index 3 2 roll 1 add get",
+ " pdfTextMat dtransform rmoveto",
+ " } for",
+ " } {",
+ " 0 1 3 index length 1 sub {",
+ " currentpoint 4 index 3 index 1 getinterval false charpath moveto",
+ " 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get",
+ " pdfTextMat dtransform rmoveto",
+ " } for",
+ " } ifelse",
+ " pop pop",
+ " } def",
+ "} ifelse",
+ "/Tj {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 0 pdfTextRise pdfTextMat dtransform rmoveto",
+ " currentpoint 4 2 roll",
+ " pdfTextRender 1 and 0 eq {",
+ " 2 copy xyshow2",
+ " } if",
+ " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
+ " 3 index 3 index moveto",
+ " 2 copy",
+ " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
+ " xycp currentpoint stroke moveto",
+ " } if",
+ " pdfTextRender 4 and 0 ne {",
+ " 4 2 roll moveto xycp",
+ " /pdfTextClipPath [ pdfTextClipPath aload pop",
+ " {/moveto cvx}",
+ " {/lineto cvx}",
+ " {/curveto cvx}",
+ " {/closepath cvx}",
+ " pathforall ] def",
+ " currentpoint newpath moveto",
+ " } {",
+ " pop pop pop pop",
+ " } ifelse",
+ " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
+ "} def",
+ "/TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0",
+ " pdfTextMat dtransform rmoveto } def",
+ "/TJmV { 0.001 mul pdfFontSize mul neg 0 exch",
+ " pdfTextMat dtransform rmoveto } def",
+ "/Tclip { pdfTextClipPath cvx exec clip newpath",
+ " /pdfTextClipPath [] def } def",
+ "/Tclip* { pdfTextClipPath cvx exec eoclip newpath",
+ " /pdfTextClipPath [] def } def",
+ "~1ns",
+ "% Level 1 image operators",
+ "/pdfIm1 {",
+ " /pdfImBuf1 4 index string def",
+ " { currentfile pdfImBuf1 readhexstring pop } image",
+ "} def",
+ "/pdfIm1Bin {",
+ " /pdfImBuf1 4 index string def",
+ " { currentfile pdfImBuf1 readstring pop } image",
+ "} def",
+ "~1s",
+ "/pdfIm1Sep {",
+ " /pdfImBuf1 4 index string def",
+ " /pdfImBuf2 4 index string def",
+ " /pdfImBuf3 4 index string def",
+ " /pdfImBuf4 4 index string def",
+ " { currentfile pdfImBuf1 readhexstring pop }",
+ " { currentfile pdfImBuf2 readhexstring pop }",
+ " { currentfile pdfImBuf3 readhexstring pop }",
+ " { currentfile pdfImBuf4 readhexstring pop }",
+ " true 4 colorimage",
+ "} def",
+ "/pdfIm1SepBin {",
+ " /pdfImBuf1 4 index string def",
+ " /pdfImBuf2 4 index string def",
+ " /pdfImBuf3 4 index string def",
+ " /pdfImBuf4 4 index string def",
+ " { currentfile pdfImBuf1 readstring pop }",
+ " { currentfile pdfImBuf2 readstring pop }",
+ " { currentfile pdfImBuf3 readstring pop }",
+ " { currentfile pdfImBuf4 readstring pop }",
+ " true 4 colorimage",
+ "} def",
+ "~1ns",
+ "/pdfImM1 {",
+ " fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
+ " { currentfile pdfImBuf1 readhexstring pop } imagemask",
+ "} def",
+ "/pdfImM1Bin {",
+ " fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
+ " { currentfile pdfImBuf1 readstring pop } imagemask",
+ "} def",
+ "/pdfImStr {",
+ " 2 copy exch length lt {",
+ " 2 copy get exch 1 add exch",
+ " } {",
+ " ()",
+ " } ifelse",
+ "} def",
+ "/pdfImM1a {",
+ " { pdfImStr } imagemask",
+ " pop pop",
+ "} def",
+ "~23sn",
+ "% Level 2/3 image operators",
+ "/pdfImBuf 100 string def",
+ "/pdfImStr {",
+ " 2 copy exch length lt {",
+ " 2 copy get exch 1 add exch",
+ " } {",
+ " ()",
+ " } ifelse",
+ "} def",
+ "/skipEOD {",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "/pdfIm { image skipEOD } def",
+ "~3sn",
+ "/pdfMask {",
+ " /ReusableStreamDecode filter",
+ " skipEOD",
+ " /maskStream exch def",
+ "} def",
+ "/pdfMaskEnd { maskStream closefile } def",
+ "/pdfMaskInit {",
+ " /maskArray exch def",
+ " /maskIdx 0 def",
+ "} def",
+ "/pdfMaskSrc {",
+ " maskIdx maskArray length lt {",
+ " maskArray maskIdx get",
+ " /maskIdx maskIdx 1 add def",
+ " } {",
+ " ()",
+ " } ifelse",
+ "} def",
+ "~23s",
+ "/pdfImSep {",
+ " findcmykcustomcolor exch",
+ " dup /Width get /pdfImBuf1 exch string def",
+ " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
+ " /pdfImDecodeLow exch def",
+ " begin Width Height BitsPerComponent ImageMatrix DataSource end",
+ " /pdfImData exch def",
+ " { pdfImData pdfImBuf1 readstring pop",
+ " 0 1 2 index length 1 sub {",
+ " 1 index exch 2 copy get",
+ " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
+ " 255 exch sub put",
+ " } for }",
+ " 6 5 roll customcolorimage",
+ " skipEOD",
+ "} def",
+ "~23sn",
+ "/pdfImM { fCol imagemask skipEOD } def",
+ "~123sn",
+ "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def",
+ "/pdfImClip {",
+ " gsave",
+ " 0 2 4 index length 1 sub {",
+ " dup 4 index exch 2 copy",
+ " get 5 index div put",
+ " 1 add 3 index exch 2 copy",
+ " get 3 index div put",
+ " } for",
+ " pop pop rectclip",
+ "} def",
+ "/pdfImClipEnd { grestore } def",
+ "~23sn",
+ "% shading operators",
+ "/colordelta {",
+ " false 0 1 3 index length 1 sub {",
+ " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {",
+ " pop true",
+ " } if",
+ " } for",
+ " exch pop exch pop",
+ "} def",
+ "/funcCol { func n array astore } def",
+ "/funcSH {",
+ " dup 0 eq {",
+ " true",
+ " } {",
+ " dup 6 eq {",
+ " false",
+ " } {",
+ " 4 index 4 index funcCol dup",
+ " 6 index 4 index funcCol dup",
+ " 3 1 roll colordelta 3 1 roll",
+ " 5 index 5 index funcCol dup",
+ " 3 1 roll colordelta 3 1 roll",
+ " 6 index 8 index funcCol dup",
+ " 3 1 roll colordelta 3 1 roll",
+ " colordelta or or or",
+ " } ifelse",
+ " } ifelse",
+ " {",
+ " 1 add",
+ " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch",
+ " 6 index 6 index 4 index 4 index 4 index funcSH",
+ " 2 index 6 index 6 index 4 index 4 index funcSH",
+ " 6 index 2 index 4 index 6 index 4 index funcSH",
+ " 5 3 roll 3 2 roll funcSH pop pop",
+ " } {",
+ " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul",
+ "~23n",
+ " funcCol sc",
+ "~23s",
+ " funcCol aload pop k",
+ "~23sn",
+ " dup 4 index exch mat transform m",
+ " 3 index 3 index mat transform l",
+ " 1 index 3 index mat transform l",
+ " mat transform l pop pop h f*",
+ " } ifelse",
+ "} def",
+ "/axialCol {",
+ " dup 0 lt {",
+ " pop t0",
+ " } {",
+ " dup 1 gt {",
+ " pop t1",
+ " } {",
+ " dt mul t0 add",
+ " } ifelse",
+ " } ifelse",
+ " func n array astore",
+ "} def",
+ "/axialSH {",
+ " dup 0 eq {",
+ " true",
+ " } {",
+ " dup 8 eq {",
+ " false",
+ " } {",
+ " 2 index axialCol 2 index axialCol colordelta",
+ " } ifelse",
+ " } ifelse",
+ " {",
+ " 1 add 3 1 roll 2 copy add 0.5 mul",
+ " dup 4 3 roll exch 4 index axialSH",
+ " exch 3 2 roll axialSH",
+ " } {",
+ " pop 2 copy add 0.5 mul",
+ "~23n",
+ " axialCol sc",
+ "~23s",
+ " axialCol aload pop k",
+ "~23sn",
+ " exch dup dx mul x0 add exch dy mul y0 add",
+ " 3 2 roll dup dx mul x0 add exch dy mul y0 add",
+ " dx abs dy abs ge {",
+ " 2 copy yMin sub dy mul dx div add yMin m",
+ " yMax sub dy mul dx div add yMax l",
+ " 2 copy yMax sub dy mul dx div add yMax l",
+ " yMin sub dy mul dx div add yMin l",
+ " h f*",
+ " } {",
+ " exch 2 copy xMin sub dx mul dy div add xMin exch m",
+ " xMax sub dx mul dy div add xMax exch l",
+ " exch 2 copy xMax sub dx mul dy div add xMax exch l",
+ " xMin sub dx mul dy div add xMin exch l",
+ " h f*",
+ " } ifelse",
+ " } ifelse",
+ "} def",
+ "/radialCol {",
+ " dup t0 lt {",
+ " pop t0",
+ " } {",
+ " dup t1 gt {",
+ " pop t1",
+ " } if",
+ " } ifelse",
+ " func n array astore",
+ "} def",
+ "/radialSH {",
+ " dup 0 eq {",
+ " true",
+ " } {",
+ " dup 8 eq {",
+ " false",
+ " } {",
+ " 2 index dt mul t0 add radialCol",
+ " 2 index dt mul t0 add radialCol colordelta",
+ " } ifelse",
+ " } ifelse",
+ " {",
+ " 1 add 3 1 roll 2 copy add 0.5 mul",
+ " dup 4 3 roll exch 4 index radialSH",
+ " exch 3 2 roll radialSH",
+ " } {",
+ " pop 2 copy add 0.5 mul dt mul t0 add",
+ "~23n",
+ " radialCol sc",
+ "~23s",
+ " radialCol aload pop k",
+ "~23sn",
+ " encl {",
+ " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " 0 360 arc h",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " 360 0 arcn h f",
+ " } {",
+ " 2 copy",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " a1 a2 arcn",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " a2 a1 arcn h",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " a1 a2 arc",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " a2 a1 arc h f",
+ " } ifelse",
+ " } ifelse",
+ "} def",
+ "~123sn",
+ "end",
+ NULL
+};
+
+static const char *cmapProlog[] = {
+ "/CIDInit /ProcSet findresource begin",
+ "10 dict begin",
+ " begincmap",
+ " /CMapType 1 def",
+ " /CMapName /Identity-H def",
+ " /CIDSystemInfo 3 dict dup begin",
+ " /Registry (Adobe) def",
+ " /Ordering (Identity) def",
+ " /Supplement 0 def",
+ " end def",
+ " 1 begincodespacerange",
+ " <0000> <ffff>",
+ " endcodespacerange",
+ " 0 usefont",
+ " 1 begincidrange",
+ " <0000> <ffff> 0",
+ " endcidrange",
+ " endcmap",
+ " currentdict CMapName exch /CMap defineresource pop",
+ "end",
+ "10 dict begin",
+ " begincmap",
+ " /CMapType 1 def",
+ " /CMapName /Identity-V def",
+ " /CIDSystemInfo 3 dict dup begin",
+ " /Registry (Adobe) def",
+ " /Ordering (Identity) def",
+ " /Supplement 0 def",
+ " end def",
+ " /WMode 1 def",
+ " 1 begincodespacerange",
+ " <0000> <ffff>",
+ " endcodespacerange",
+ " 0 usefont",
+ " 1 begincidrange",
+ " <0000> <ffff> 0",
+ " endcidrange",
+ " endcmap",
+ " currentdict CMapName exch /CMap defineresource pop",
+ "end",
+ "end",
+ NULL
+};
+
+//------------------------------------------------------------------------
+// Fonts
+//------------------------------------------------------------------------
+
+struct PSSubstFont {
+ const char *psName; // PostScript name
+ double mWidth; // width of 'm' character
+};
+
+// NB: must be in same order as base14SubstFonts in GfxFont.cc
+static PSSubstFont psBase14SubstFonts[14] = {
+ {"Courier", 0.600},
+ {"Courier-Oblique", 0.600},
+ {"Courier-Bold", 0.600},
+ {"Courier-BoldOblique", 0.600},
+ {"Helvetica", 0.833},
+ {"Helvetica-Oblique", 0.833},
+ {"Helvetica-Bold", 0.889},
+ {"Helvetica-BoldOblique", 0.889},
+ {"Times-Roman", 0.788},
+ {"Times-Italic", 0.722},
+ {"Times-Bold", 0.833},
+ {"Times-BoldItalic", 0.778},
+ // the last two are never used for substitution
+ {"Symbol", 0},
+ {"ZapfDingbats", 0}
+};
+
+// Mapping from Type 1/1C font file to PS font name.
+struct PST1FontName {
+ Ref fontFileID;
+ GooString *psName; // PostScript font name used for this
+ // embedded font file
+};
+
+// Info for 8-bit fonts
+struct PSFont8Info {
+ Ref fontID;
+ int *codeToGID; // code-to-GID mapping for TrueType fonts
+};
+
+// Encoding info for substitute 16-bit font
+struct PSFont16Enc {
+ Ref fontID;
+ GooString *enc;
+};
+
+//------------------------------------------------------------------------
+// process colors
+//------------------------------------------------------------------------
+
+#define psProcessCyan 1
+#define psProcessMagenta 2
+#define psProcessYellow 4
+#define psProcessBlack 8
+#define psProcessCMYK 15
+
+//------------------------------------------------------------------------
+// PSOutCustomColor
+//------------------------------------------------------------------------
+
+class PSOutCustomColor {
+public:
+
+ PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GooString *nameA);
+ ~PSOutCustomColor();
+
+ double c, m, y, k;
+ GooString *name;
+ PSOutCustomColor *next;
+};
+
+PSOutCustomColor::PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GooString *nameA) {
+ c = cA;
+ m = mA;
+ y = yA;
+ k = kA;
+ name = nameA;
+ next = NULL;
+}
+
+PSOutCustomColor::~PSOutCustomColor() {
+ delete name;
+}
+
+//------------------------------------------------------------------------
+
+struct PSOutImgClipRect {
+ int x0, x1, y0, y1;
+};
+
+//------------------------------------------------------------------------
+
+struct PSOutPaperSize {
+ PSOutPaperSize(GooString *nameA, int wA, int hA) { name = nameA; w = wA; h = hA; }
+ ~PSOutPaperSize() { delete name; }
+ GooString *name;
+ int w, h;
+};
+
+//------------------------------------------------------------------------
+// DeviceNRecoder
+//------------------------------------------------------------------------
+
+class DeviceNRecoder: public FilterStream {
+public:
+
+ DeviceNRecoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA);
+ virtual ~DeviceNRecoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; }
+ virtual int lookChar()
+ { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; }
+ virtual GooString *getPSFilter(int psLevel, const char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ GBool fillBuf();
+
+ int width, height;
+ GfxImageColorMap *colorMap;
+ Function *func;
+ ImageStream *imgStr;
+ int buf[gfxColorMaxComps];
+ int pixelIdx;
+ int bufIdx;
+ int bufSize;
+};
+
+DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA):
+ FilterStream(strA) {
+ width = widthA;
+ height = heightA;
+ colorMap = colorMapA;
+ imgStr = NULL;
+ pixelIdx = 0;
+ bufIdx = gfxColorMaxComps;
+ bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getAlt()->getNComps();
+ func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getTintTransformFunc();
+}
+
+DeviceNRecoder::~DeviceNRecoder() {
+ if (imgStr) {
+ delete imgStr;
+ }
+ if (str->isEncoder()) {
+ delete str;
+ }
+}
+
+void DeviceNRecoder::reset() {
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+}
+
+GBool DeviceNRecoder::fillBuf() {
+ Guchar pixBuf[gfxColorMaxComps];
+ GfxColor color;
+ double x[gfxColorMaxComps], y[gfxColorMaxComps];
+ int i;
+
+ if (pixelIdx >= width * height) {
+ return gFalse;
+ }
+ imgStr->getPixel(pixBuf);
+ colorMap->getColor(pixBuf, &color);
+ for (i = 0;
+ i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps();
+ ++i) {
+ x[i] = colToDbl(color.c[i]);
+ }
+ func->transform(x, y);
+ for (i = 0; i < bufSize; ++i) {
+ buf[i] = (int)(y[i] * 255 + 0.5);
+ }
+ bufIdx = 0;
+ ++pixelIdx;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// PSOutputDev
+//------------------------------------------------------------------------
+
+extern "C" {
+typedef void (*SignalFunc)(int);
+}
+
+static void outputToFile(void *stream, const char *data, int len) {
+ fwrite(data, 1, len, (FILE *)stream);
+}
+
+PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *doc,
+ char *psTitleA,
+ const std::vector<int> &pages, PSOutMode modeA,
+ int paperWidthA, int paperHeightA,
+ GBool noCropA, GBool duplexA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool forceRasterizeA,
+ GBool manualCtrlA,
+ PSOutCustomCodeCbk customCodeCbkA,
+ void *customCodeCbkDataA) {
+ FILE *f;
+ PSFileType fileTypeA;
+
+ underlayCbk = NULL;
+ underlayCbkData = NULL;
+ overlayCbk = NULL;
+ overlayCbkData = NULL;
+ customCodeCbk = customCodeCbkA;
+ customCodeCbkData = customCodeCbkDataA;
+
+ fontIDs = NULL;
+ fontNames = new GooHash(gTrue);
+ t1FontNames = NULL;
+ font8Info = NULL;
+ font16Enc = NULL;
+ imgIDs = NULL;
+ formIDs = NULL;
+ paperSizes = NULL;
+ embFontList = NULL;
+ customColors = NULL;
+ haveTextClip = gFalse;
+ t3String = NULL;
+ forceRasterize = forceRasterizeA;
+ psTitle = NULL;
+
+ // open file or pipe
+ if (!strcmp(fileName, "-")) {
+ fileTypeA = psStdout;
+ f = stdout;
+ } else if (fileName[0] == '|') {
+ fileTypeA = psPipe;
+#ifdef HAVE_POPEN
+#ifndef _WIN32
+ signal(SIGPIPE, (SignalFunc)SIG_IGN);
+#endif
+ if (!(f = popen(fileName + 1, "w"))) {
+ error(errIO, -1, "Couldn't run print command '{0:s}'", fileName);
+ ok = gFalse;
+ return;
+ }
+#else
+ error(errIO, -1, "Print commands are not supported ('{0:s}')", fileName);
+ ok = gFalse;
+ return;
+#endif
+ } else {
+ fileTypeA = psFile;
+ if (!(f = fopen(fileName, "w"))) {
+ error(errIO, -1, "Couldn't open PostScript file '{0:s}'", fileName);
+ ok = gFalse;
+ return;
+ }
+ }
+
+ init(outputToFile, f, fileTypeA, psTitleA,
+ doc, pages, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
+ paperWidthA, paperHeightA, noCropA, duplexA);
+}
+
+PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
+ char *psTitleA,
+ PDFDoc *doc,
+ const std::vector<int> &pages, PSOutMode modeA,
+ int paperWidthA, int paperHeightA,
+ GBool noCropA, GBool duplexA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool forceRasterizeA,
+ GBool manualCtrlA,
+ PSOutCustomCodeCbk customCodeCbkA,
+ void *customCodeCbkDataA) {
+ underlayCbk = NULL;
+ underlayCbkData = NULL;
+ overlayCbk = NULL;
+ overlayCbkData = NULL;
+ customCodeCbk = customCodeCbkA;
+ customCodeCbkData = customCodeCbkDataA;
+
+ fontIDs = NULL;
+ fontNames = new GooHash(gTrue);
+ t1FontNames = NULL;
+ font8Info = NULL;
+ font16Enc = NULL;
+ imgIDs = NULL;
+ formIDs = NULL;
+ paperSizes = NULL;
+ embFontList = NULL;
+ customColors = NULL;
+ haveTextClip = gFalse;
+ t3String = NULL;
+ forceRasterize = forceRasterizeA;
+ psTitle = NULL;
+
+ init(outputFuncA, outputStreamA, psGeneric, psTitleA,
+ doc, pages, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
+ paperWidthA, paperHeightA, noCropA, duplexA);
+}
+
+struct StandardMedia {
+ const char *name;
+ int width;
+ int height;
+};
+
+static const StandardMedia standardMedia[] =
+{
+ { "A0", 2384, 3371 },
+ { "A1", 1685, 2384 },
+ { "A2", 1190, 1684 },
+ { "A3", 842, 1190 },
+ { "A4", 595, 842 },
+ { "A5", 420, 595 },
+ { "B4", 729, 1032 },
+ { "B5", 516, 729 },
+ { "Letter", 612, 792 },
+ { "Tabloid", 792, 1224 },
+ { "Ledger", 1224, 792 },
+ { "Legal", 612, 1008 },
+ { "Statement", 396, 612 },
+ { "Executive", 540, 720 },
+ { "Folio", 612, 936 },
+ { "Quarto", 610, 780 },
+ { "10x14", 720, 1008 },
+ { NULL, 0, 0 }
+};
+
+/* PLRM specifies a tolerance of 5 points when matching page sizes */
+static bool pageDimensionEqual(int a, int b) {
+ return (abs (a - b) < 5);
+}
+
+// Shared initialization of PSOutputDev members.
+// Store the values but do not process them so the function that
+// created the PSOutputDev can use the various setters to change defaults.
+
+void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
+ PSFileType fileTypeA, char *psTitleA, PDFDoc *docA,
+ const std::vector<int> &pagesA, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA, int paperWidthA, int paperHeightA,
+ GBool noCropA, GBool duplexA) {
+
+ if (pagesA.empty()) {
+ ok = gFalse;
+ return;
+ }
+
+ // initialize
+ postInitDone = gFalse;
+ embedType1 = gTrue;
+ embedTrueType = gTrue;
+ embedCIDPostScript = gTrue;
+ embedCIDTrueType = gTrue;
+ fontPassthrough = gFalse;
+ optimizeColorSpace = gFalse;
+ preloadImagesForms = gFalse;
+ generateOPI = gFalse;
+ useASCIIHex = gFalse;
+ useBinary = gFalse;
+ rasterMono = gFalse;
+ rasterResolution = 300;
+ uncompressPreloadedImages = gFalse;
+ rasterAntialias = gFalse;
+ displayText = gTrue;
+ ok = gTrue;
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
+ fileType = fileTypeA;
+ psTitle = (psTitleA? strdup(psTitleA): NULL);
+ doc = docA;
+ level = globalParams->getPSLevel();
+ pages = pagesA;
+ mode = modeA;
+ paperWidth = paperWidthA;
+ paperHeight = paperHeightA;
+ noCrop = noCropA;
+ duplex = duplexA;
+ imgLLX = imgLLXA;
+ imgLLY = imgLLYA;
+ imgURX = imgURXA;
+ imgURY = imgURYA;
+ manualCtrl = manualCtrlA;
+
+ xref = NULL;
+
+ processColors = 0;
+ inType3Char = gFalse;
+ inUncoloredPattern = gFalse;
+ t3FillColorOnly = gFalse;
+
+#if OPI_SUPPORT
+ // initialize OPI nesting levels
+ opi13Nest = 0;
+ opi20Nest = 0;
+#endif
+
+ tx0 = ty0 = -1;
+ xScale0 = yScale0 = 0;
+ rotate0 = -1;
+ clipLLX0 = clipLLY0 = 0;
+ clipURX0 = clipURY0 = -1;
+
+ // initialize sequential page number
+ seqPage = 1;
+}
+
+// Complete the initialization after the function that created the PSOutputDev
+// has had a chance to modify default values with the various setters.
+
+void PSOutputDev::postInit()
+{
+ Catalog *catalog;
+ PDFRectangle *box;
+ PSOutPaperSize *size;
+ GooList *names;
+ int w, h, i;
+
+ if (postInitDone || !ok) {
+ return;
+ }
+
+ postInitDone = gTrue;
+
+ xref = doc->getXRef();
+ catalog = doc->getCatalog();
+
+ if (paperWidth < 0 || paperHeight < 0) {
+ paperMatch = gTrue;
+ } else {
+ paperMatch = gFalse;
+ }
+ Page *page;
+ paperSizes = new GooList();
+ for (size_t pgi = 0; pgi < pages.size(); ++pgi) {
+ const int pg = pages[pgi];
+ page = catalog->getPage(pg);
+ if (page == NULL)
+ paperMatch = gFalse;
+ if (!paperMatch) {
+ w = paperWidth;
+ h = paperHeight;
+ if (w < 0 || h < 0) {
+ // Unable to obtain a paper size from the document and no page size
+ // specified. In this case use A4 as the page size to ensure the PS output is
+ // valid. This will only occur if the PDF is very broken.
+ w = 595;
+ h = 842;
+ }
+ } else if (noCrop) {
+ w = (int)ceil(page->getMediaWidth());
+ h = (int)ceil(page->getMediaHeight());
+ } else {
+ w = (int)ceil(page->getCropWidth());
+ h = (int)ceil(page->getCropHeight());
+ }
+ if (paperMatch) {
+ int rotate = page->getRotate();
+ if (rotate == 90 || rotate == 270)
+ std::swap(w, h);
+ }
+ if (w > paperWidth)
+ paperWidth = w;
+ if (h > paperHeight)
+ paperHeight = h;
+ for (i = 0; i < paperSizes->getLength(); ++i) {
+ size = (PSOutPaperSize *)paperSizes->get(i);
+ if (pageDimensionEqual(w, size->w) && pageDimensionEqual(h, size->h))
+ break;
+ }
+ if (i == paperSizes->getLength()) {
+ const StandardMedia *media = standardMedia;
+ GooString *name = NULL;
+ while (media->name) {
+ if (pageDimensionEqual(w, media->width) && pageDimensionEqual(h, media->height)) {
+ name = new GooString(media->name);
+ w = media->width;
+ h = media->height;
+ break;
+ }
+ media++;
+ }
+ if (!name)
+ name = GooString::format("{0:d}x{1:d}mm", int(w*25.4/72), int(h*25.4/72));
+ paperSizes->append(new PSOutPaperSize(name, w, h));
+ }
+ pagePaperSize.insert(std::pair<int,int>(pg, i));
+ if (!paperMatch)
+ break; // we only need one entry when all pages are the same size
+ }
+ if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
+ imgLLX = imgLLY = 0;
+ imgURX = paperWidth;
+ imgURY = paperHeight;
+ }
+ std::vector<int> pageList;
+ if (mode == psModeForm) {
+ pageList.push_back(pages[0]);
+ } else {
+ pageList = pages;
+ }
+
+ // initialize fontIDs, fontFileIDs, and fontFileNames lists
+ fontIDSize = 64;
+ fontIDLen = 0;
+ fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
+ for (i = 0; i < 14; ++i) {
+ fontNames->add(new GooString(psBase14SubstFonts[i].psName), 1);
+ }
+ names = globalParams->getPSResidentFonts();
+ for (i = 0; i < names->getLength(); ++i) {
+ fontNames->add((GooString *)names->get(i), 1);
+ }
+ delete names;
+ t1FontNameSize = 64;
+ t1FontNameLen = 0;
+ t1FontNames = (PST1FontName *)gmallocn(t1FontNameSize, sizeof(PST1FontName));
+ font8InfoLen = 0;
+ font8InfoSize = 0;
+ font16EncLen = 0;
+ font16EncSize = 0;
+ imgIDLen = 0;
+ imgIDSize = 0;
+ formIDLen = 0;
+ formIDSize = 0;
+
+ numSaves = 0;
+ numTilingPatterns = 0;
+ nextFunc = 0;
+
+ // initialize embedded font resource comment list
+ embFontList = new GooString();
+
+ if (!manualCtrl) {
+ Page *page;
+ // this check is needed in case the document has zero pages
+ if ((page = doc->getPage(pageList[0]))) {
+ writeHeader(pageList,
+ page->getMediaBox(),
+ page->getCropBox(),
+ page->getRotate(),
+ psTitle);
+ } else {
+ error(errSyntaxError, -1, "Invalid page {0:d}", pageList[0]);
+ box = new PDFRectangle(0, 0, 1, 1);
+ writeHeader(pageList, box, box, 0, psTitle);
+ delete box;
+ }
+ if (mode != psModeForm) {
+ writePS("%%BeginProlog\n");
+ }
+ writeXpdfProcset();
+ if (mode != psModeForm) {
+ writePS("%%EndProlog\n");
+ writePS("%%BeginSetup\n");
+ }
+ writeDocSetup(doc, catalog, pageList, duplex);
+ if (mode != psModeForm) {
+ writePS("%%EndSetup\n");
+ }
+ }
+}
+
+PSOutputDev::~PSOutputDev() {
+ PSOutCustomColor *cc;
+ int i;
+
+ if (ok) {
+ if (!postInitDone) {
+ postInit();
+ }
+ if (!manualCtrl) {
+ writePS("%%Trailer\n");
+ writeTrailer();
+ if (mode != psModeForm) {
+ writePS("%%EOF\n");
+ }
+ }
+ if (fileType == psFile) {
+#ifdef MACOS
+ ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
+#endif
+ fclose((FILE *)outputStream);
+ }
+#ifdef HAVE_POPEN
+ else if (fileType == psPipe) {
+ pclose((FILE *)outputStream);
+#ifndef _WIN32
+ signal(SIGPIPE, (SignalFunc)SIG_DFL);
+#endif
+ }
+#endif
+ }
+ if (paperSizes) {
+ deleteGooList(paperSizes, PSOutPaperSize);
+ }
+ if (embFontList) {
+ delete embFontList;
+ }
+ if (fontIDs) {
+ gfree(fontIDs);
+ }
+ delete fontNames;
+ if (t1FontNames) {
+ for (i = 0; i < t1FontNameLen; ++i) {
+ delete t1FontNames[i].psName;
+ }
+ gfree(t1FontNames);
+ }
+ if (font8Info) {
+ for (i = 0; i < font8InfoLen; ++i) {
+ gfree(font8Info[i].codeToGID);
+ }
+ gfree(font8Info);
+ }
+ if (font16Enc) {
+ for (i = 0; i < font16EncLen; ++i) {
+ if (font16Enc[i].enc) {
+ delete font16Enc[i].enc;
+ }
+ }
+ gfree(font16Enc);
+ }
+ gfree(imgIDs);
+ gfree(formIDs);
+ while (customColors) {
+ cc = customColors;
+ customColors = cc->next;
+ delete cc;
+ }
+ gfree(psTitle);
+}
+
+void PSOutputDev::writeHeader(const std::vector<int> &pages,
+ PDFRectangle *mediaBox, PDFRectangle *cropBox,
+ int pageRotate, char *psTitle) {
+ Object info, obj1;
+ PSOutPaperSize *size;
+ double x1, y1, x2, y2;
+ int i;
+
+ switch (mode) {
+ case psModePS:
+ writePS("%!PS-Adobe-3.0\n");
+ break;
+ case psModeEPS:
+ writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
+ break;
+ case psModeForm:
+ writePS("%!PS-Adobe-3.0 Resource-Form\n");
+ break;
+ }
+ writePSFmt("%Produced by poppler pdftops version: {0:s} (http://poppler.freedesktop.org)\n", PACKAGE_VERSION);
+ xref->getDocInfo(&info);
+ if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
+ writePS("%%Creator: ");
+ writePSTextLine(obj1.getString());
+ }
+ obj1.free();
+ info.free();
+ if(psTitle) {
+ char *sanitizedTitle = strdup(psTitle);
+ for (Guint i = 0; i < strlen(sanitizedTitle); ++i) {
+ if (sanitizedTitle[i] == '\n' || sanitizedTitle[i] == '\r') {
+ sanitizedTitle[i] = ' ';
+ }
+ }
+ writePSFmt("%%Title: {0:s}\n", sanitizedTitle);
+ free(sanitizedTitle);
+ }
+ writePSFmt("%%LanguageLevel: {0:d}\n",
+ (level == psLevel1 || level == psLevel1Sep) ? 1 :
+ (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+ if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors: (atend)\n");
+ writePS("%%DocumentCustomColors: (atend)\n");
+ }
+ writePS("%%DocumentSuppliedResources: (atend)\n");
+ if ((level == psLevel1 || level == psLevel1Sep) && useBinary) {
+ writePS("%%DocumentData: Binary\n");
+ }
+
+ switch (mode) {
+ case psModePS:
+ for (i = 0; i < paperSizes->getLength(); ++i) {
+ size = (PSOutPaperSize *)paperSizes->get(i);
+ writePSFmt("%%{0:s} {1:t} {2:d} {3:d} 0 () ()\n",
+ i==0 ? "DocumentMedia:" : "+", size->name, size->w, size->h);
+ }
+ writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight);
+ writePSFmt("%%Pages: {0:d}\n", static_cast<int>(pages.size()));
+ writePS("%%EndComments\n");
+ if (!paperMatch) {
+ size = (PSOutPaperSize *)paperSizes->get(0);
+ writePS("%%BeginDefaults\n");
+ writePSFmt("%%PageMedia: {0:t}\n", size->name);
+ writePS("%%EndDefaults\n");
+ }
+ break;
+ case psModeEPS:
+ epsX1 = cropBox->x1;
+ epsY1 = cropBox->y1;
+ epsX2 = cropBox->x2;
+ epsY2 = cropBox->y2;
+ if (pageRotate == 0 || pageRotate == 180) {
+ x1 = epsX1;
+ y1 = epsY1;
+ x2 = epsX2;
+ y2 = epsY2;
+ } else { // pageRotate == 90 || pageRotate == 270
+ x1 = 0;
+ y1 = 0;
+ x2 = epsY2 - epsY1;
+ y2 = epsX2 - epsX1;
+ }
+ writePSFmt("%%BoundingBox: {0:d} {1:d} {2:d} {3:d}\n",
+ (int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2));
+ writePSFmt("%%HiResBoundingBox: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
+ x1, y1, x2, y2);
+ writePS("%%DocumentSuppliedResources: (atend)\n");
+ writePS("%%EndComments\n");
+ break;
+ case psModeForm:
+ writePS("%%EndComments\n");
+ writePS("32 dict dup begin\n");
+ writePSFmt("/BBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+ (int)floor(mediaBox->x1), (int)floor(mediaBox->y1),
+ (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2));
+ writePS("/FormType 1 def\n");
+ writePS("/Matrix [1 0 0 1 0 0] def\n");
+ break;
+ }
+}
+
+void PSOutputDev::writeXpdfProcset() {
+ GBool lev1, lev2, lev3, sep, nonSep;
+ const char **p;
+ const char *q;
+
+ writePSFmt("%%BeginResource: procset xpdf {0:s} 0\n", "3.00");
+ writePSFmt("%%Copyright: {0:s}\n", xpdfCopyright);
+ lev1 = lev2 = lev3 = sep = nonSep = gTrue;
+ for (p = prolog; *p; ++p) {
+ if ((*p)[0] == '~') {
+ lev1 = lev2 = lev3 = sep = nonSep = gFalse;
+ for (q = *p + 1; *q; ++q) {
+ switch (*q) {
+ case '1': lev1 = gTrue; break;
+ case '2': lev2 = gTrue; break;
+ case '3': lev3 = gTrue; break;
+ case 's': sep = gTrue; break;
+ case 'n': nonSep = gTrue; break;
+ }
+ }
+ } else if ((level == psLevel1 && lev1 && nonSep) ||
+ (level == psLevel1Sep && lev1 && sep) ||
+ (level == psLevel2 && lev2 && nonSep) ||
+ (level == psLevel2Sep && lev2 && sep) ||
+ (level == psLevel3 && lev3 && nonSep) ||
+ (level == psLevel3Sep && lev3 && sep)) {
+ writePSFmt("{0:s}\n", *p);
+ }
+ }
+ writePS("%%EndResource\n");
+
+ if (level >= psLevel3) {
+ for (p = cmapProlog; *p; ++p) {
+ writePSFmt("{0:s}\n", *p);
+ }
+ }
+}
+
+void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
+ const std::vector<int> &pages,
+ GBool duplexA) {
+ Page *page;
+ Dict *resDict;
+ Annots *annots;
+ Object *acroForm;
+ Object obj1, obj2, obj3;
+ GooString *s;
+ int i;
+
+ if (mode == psModeForm) {
+ // swap the form and xpdf dicts
+ writePS("xpdf end begin dup begin\n");
+ } else {
+ writePS("xpdf begin\n");
+ }
+ for (size_t pgi = 0; pgi < pages.size(); ++pgi) {
+ const int pg = pages[pgi];
+ page = doc->getPage(pg);
+ if (!page) {
+ error(errSyntaxError, -1, "Failed writing resources for page {0:d}", pg);
+ continue;
+ }
+ if ((resDict = page->getResourceDict())) {
+ setupResources(resDict);
+ }
+ annots = page->getAnnots();
+ for (i = 0; i < annots->getNumAnnots(); ++i) {
+ if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) {
+ setupResources(obj1.getDict());
+ }
+ obj1.free();
+ }
+ }
+ if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) {
+ if (acroForm->dictLookup("DR", &obj1)->isDict()) {
+ setupResources(obj1.getDict());
+ }
+ obj1.free();
+ if (acroForm->dictLookup("Fields", &obj1)->isArray()) {
+ for (i = 0; i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &obj2)->isDict()) {
+ if (obj2.dictLookup("DR", &obj3)->isDict()) {
+ setupResources(obj3.getDict());
+ }
+ obj3.free();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+ }
+ if (mode != psModeForm) {
+ if (mode != psModeEPS && !manualCtrl) {
+ writePSFmt("{0:s} pdfSetup\n",
+ duplexA ? "true" : "false");
+ if (!paperMatch) {
+ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", paperWidth, paperHeight);
+ }
+ }
+#if OPI_SUPPORT
+ if (generateOPI) {
+ writePS("/opiMatrix matrix currentmatrix def\n");
+ }
+#endif
+ }
+ if (customCodeCbk) {
+ if ((s = (*customCodeCbk)(this, psOutCustomDocSetup, 0,
+ customCodeCbkData))) {
+ writePS(s->getCString());
+ delete s;
+ }
+ }
+}
+
+void PSOutputDev::writePageTrailer() {
+ if (mode != psModeForm) {
+ writePS("pdfEndPage\n");
+ }
+}
+
+void PSOutputDev::writeTrailer() {
+ PSOutCustomColor *cc;
+
+ if (mode == psModeForm) {
+ writePS("/Foo exch /Form defineresource pop\n");
+ } else {
+ writePS("end\n");
+ writePS("%%DocumentSuppliedResources:\n");
+ writePS(embFontList->getCString());
+ if (level == psLevel1Sep || level == psLevel2Sep ||
+ level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors:");
+ if (processColors & psProcessCyan) {
+ writePS(" Cyan");
+ }
+ if (processColors & psProcessMagenta) {
+ writePS(" Magenta");
+ }
+ if (processColors & psProcessYellow) {
+ writePS(" Yellow");
+ }
+ if (processColors & psProcessBlack) {
+ writePS(" Black");
+ }
+ writePS("\n");
+ writePS("%%DocumentCustomColors:");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePS(" ");
+ writePSString(cc->name);
+ }
+ writePS("\n");
+ writePS("%%CMYKCustomColor:\n");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePSFmt("%%+ {0:.4g} {1:.4g} {2:.4g} {3:.4g} ",
+ cc->c, cc->m, cc->y, cc->k);
+ writePSString(cc->name);
+ writePS("\n");
+ }
+ }
+ }
+}
+
+void PSOutputDev::setupResources(Dict *resDict) {
+ Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj;
+ Ref ref0;
+ GBool skip;
+ int i;
+
+ setupFonts(resDict);
+ setupImages(resDict);
+ setupForms(resDict);
+
+ //----- recursively scan XObjects
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+
+ // avoid infinite recursion on XObjects
+ skip = gFalse;
+ if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
+ ref0 = xObjRef.getRef();
+ if (resourceIDs.find(ref0.num) != resourceIDs.end()) {
+ skip = gTrue;
+ } else {
+ resourceIDs.insert(ref0.num);
+ }
+ }
+ if (!skip) {
+
+ // process the XObject's resource dictionary
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict()) {
+ setupResources(resObj.getDict());
+ }
+ resObj.free();
+ }
+ xObj.free();
+ }
+
+ xObjRef.free();
+ }
+ }
+ xObjDict.free();
+
+ //----- recursively scan Patterns
+ resDict->lookup("Pattern", &patDict);
+ if (patDict.isDict()) {
+ inType3Char = gTrue;
+ for (i = 0; i < patDict.dictGetLength(); ++i) {
+
+ // avoid infinite recursion on Patterns
+ skip = gFalse;
+ if ((patDict.dictGetValNF(i, &patRef)->isRef())) {
+ ref0 = patRef.getRef();
+ if (resourceIDs.find(ref0.num) != resourceIDs.end()) {
+ skip = gTrue;
+ } else {
+ resourceIDs.insert(ref0.num);
+ }
+ }
+ if (!skip) {
+
+ // process the Pattern's resource dictionary
+ patDict.dictGetVal(i, &pat);
+ if (pat.isStream()) {
+ pat.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict()) {
+ setupResources(resObj.getDict());
+ }
+ resObj.free();
+ }
+ pat.free();
+ }
+
+ patRef.free();
+ }
+ inType3Char = gFalse;
+ }
+ patDict.free();
+}
+
+void PSOutputDev::setupFonts(Dict *resDict) {
+ Object obj1, obj2;
+ Ref r;
+ GfxFontDict *gfxFontDict;
+ GfxFont *font;
+ int i;
+
+ gfxFontDict = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
+ }
+ if (gfxFontDict) {
+ for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
+ if ((font = gfxFontDict->getFont(i))) {
+ setupFont(font, resDict);
+ }
+ }
+ delete gfxFontDict;
+ }
+ obj1.free();
+}
+
+void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
+ GfxFontLoc *fontLoc;
+ GooString *psName;
+ char buf[16];
+ GBool subst;
+ UnicodeMap *uMap;
+ const char *charName;
+ double xs, ys;
+ int code;
+ double w1, w2;
+ int i, j;
+
+ // check if font is already set up
+ for (i = 0; i < fontIDLen; ++i) {
+ if (fontIDs[i].num == font->getID()->num &&
+ fontIDs[i].gen == font->getID()->gen) {
+ return;
+ }
+ }
+
+ // add entry to fontIDs list
+ if (fontIDLen >= fontIDSize) {
+ fontIDSize += 64;
+ fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref));
+ }
+ fontIDs[fontIDLen++] = *font->getID();
+
+ psName = NULL;
+ xs = ys = 1;
+ subst = gFalse;
+
+ if (font->getType() == fontType3) {
+ psName = GooString::format("T3_{0:d}_{1:d}",
+ font->getID()->num, font->getID()->gen);
+ setupType3Font(font, psName, parentResDict);
+ } else {
+ fontLoc = font->locateFont(xref, this);
+ if (fontLoc != NULL) {
+ switch (fontLoc->locType) {
+ case gfxFontLocEmbedded:
+ switch (fontLoc->fontType) {
+ case fontType1:
+ // this assumes that the PS font name matches the PDF font name
+ psName = font->getEmbeddedFontName() ? font->getEmbeddedFontName()->copy() : new GooString();
+ setupEmbeddedType1Font(&fontLoc->embFontID, psName);
+ break;
+ case fontType1C:
+ psName = makePSFontName(font, &fontLoc->embFontID);
+ setupEmbeddedType1CFont(font, &fontLoc->embFontID, psName);
+ break;
+ case fontType1COT:
+ psName = makePSFontName(font, &fontLoc->embFontID);
+ setupEmbeddedOpenTypeT1CFont(font, &fontLoc->embFontID, psName);
+ break;
+ case fontTrueType:
+ case fontTrueTypeOT:
+ psName = makePSFontName(font, font->getID());
+ setupEmbeddedTrueTypeFont(font, &fontLoc->embFontID, psName);
+ break;
+ case fontCIDType0C:
+ psName = makePSFontName(font, &fontLoc->embFontID);
+ setupEmbeddedCIDType0Font(font, &fontLoc->embFontID, psName);
+ break;
+ case fontCIDType2:
+ case fontCIDType2OT:
+ psName = makePSFontName(font, font->getID());
+ //~ should check to see if font actually uses vertical mode
+ setupEmbeddedCIDTrueTypeFont(font, &fontLoc->embFontID, psName, gTrue);
+ break;
+ case fontCIDType0COT:
+ psName = makePSFontName(font, &fontLoc->embFontID);
+ setupEmbeddedOpenTypeCFFFont(font, &fontLoc->embFontID, psName);
+ break;
+ default:
+ break;
+ }
+ break;
+ case gfxFontLocExternal:
+ //~ add cases for external 16-bit fonts
+ switch (fontLoc->fontType) {
+ case fontType1:
+ if (font->getEmbeddedFontName()) {
+ // this assumes that the PS font name matches the PDF font name
+ psName = font->getEmbeddedFontName()->copy();
+ } else {
+ //~ this won't work -- the PS font name won't match
+ psName = makePSFontName(font, font->getID());
+ }
+ setupExternalType1Font(fontLoc->path, psName);
+ break;
+ case fontTrueType:
+ case fontTrueTypeOT:
+ psName = makePSFontName(font, font->getID());
+ setupExternalTrueTypeFont(font, fontLoc->path, psName);
+ break;
+ case fontCIDType2:
+ case fontCIDType2OT:
+ psName = makePSFontName(font, font->getID());
+ //~ should check to see if font actually uses vertical mode
+ setupExternalCIDTrueTypeFont(font, fontLoc->path, psName, gTrue);
+ break;
+ default:
+ break;
+ }
+ break;
+ case gfxFontLocResident:
+ psName = fontLoc->path->copy();
+ break;
+ }
+ }
+
+ if (!psName) {
+ if (font->isCIDFont()) {
+ error(errSyntaxError, -1,
+ "Couldn't find a font to substitute for '{0:s}' ('{1:s}' character collection)",
+ font->getName() ? font->getName()->getCString()
+ : "(unnamed)",
+ ((GfxCIDFont *)font)->getCollection()
+ ? ((GfxCIDFont *)font)->getCollection()->getCString()
+ : "(unknown)");
+ if (font16EncLen >= font16EncSize) {
+ font16EncSize += 16;
+ font16Enc = (PSFont16Enc *)greallocn(font16Enc,
+ font16EncSize,
+ sizeof(PSFont16Enc));
+ }
+ font16Enc[font16EncLen].fontID = *font->getID();
+ font16Enc[font16EncLen].enc = NULL;
+ ++font16EncLen;
+ } else {
+ error(errSyntaxError, -1,
+ "Couldn't find a font to substitute for '{0:s}'",
+ font->getName() ? font->getName()->getCString()
+ : "(unnamed)");
+ }
+ delete fontLoc;
+ return;
+ }
+
+ // scale substituted 8-bit fonts
+ if (fontLoc->locType == gfxFontLocResident &&
+ fontLoc->substIdx >= 0) {
+ subst = gTrue;
+ for (code = 0; code < 256; ++code) {
+ if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
+ charName[0] == 'm' && charName[1] == '\0') {
+ break;
+ }
+ }
+ if (code < 256) {
+ w1 = ((Gfx8BitFont *)font)->getWidth(code);
+ } else {
+ w1 = 0;
+ }
+ w2 = psBase14SubstFonts[fontLoc->substIdx].mWidth;
+ xs = w1 / w2;
+ if (xs < 0.1) {
+ xs = 1;
+ }
+ }
+
+ // handle encodings for substituted CID fonts
+ if (fontLoc->locType == gfxFontLocResident &&
+ fontLoc->fontType >= fontCIDType0) {
+ subst = gTrue;
+ if (font16EncLen >= font16EncSize) {
+ font16EncSize += 16;
+ font16Enc = (PSFont16Enc *)greallocn(font16Enc,
+ font16EncSize,
+ sizeof(PSFont16Enc));
+ }
+ font16Enc[font16EncLen].fontID = *font->getID();
+ if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) {
+ font16Enc[font16EncLen].enc = fontLoc->encoding->copy();
+ uMap->decRefCnt();
+ } else {
+ error(errSyntaxError, -1,
+ "Couldn't find Unicode map for 16-bit font encoding '{0:t}'",
+ fontLoc->encoding);
+ font16Enc[font16EncLen].enc = NULL;
+ }
+ ++font16EncLen;
+ }
+
+ delete fontLoc;
+ }
+
+ // generate PostScript code to set up the font
+ if (font->isCIDFont()) {
+ if (level == psLevel3 || level == psLevel3Sep) {
+ writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16L3\n",
+ font->getID()->num, font->getID()->gen, psName,
+ font->getWMode());
+ } else {
+ writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16\n",
+ font->getID()->num, font->getID()->gen, psName,
+ font->getWMode());
+ }
+ } else {
+ writePSFmt("/F{0:d}_{1:d} /{2:t} {3:.6g} {4:.6g}\n",
+ font->getID()->num, font->getID()->gen, psName, xs, ys);
+ for (i = 0; i < 256; i += 8) {
+ writePS((char *)((i == 0) ? "[ " : " "));
+ for (j = 0; j < 8; ++j) {
+ if (font->getType() == fontTrueType &&
+ !subst &&
+ !((Gfx8BitFont *)font)->getHasEncoding()) {
+ sprintf(buf, "c%02x", i+j);
+ charName = buf;
+ } else {
+ charName = ((Gfx8BitFont *)font)->getCharName(i+j);
+ }
+ writePS("/");
+ writePSName(charName ? charName : (char *)".notdef");
+ // the empty name is legal in PDF and PostScript, but PostScript
+ // uses a double-slash (//...) for "immediately evaluated names",
+ // so we need to add a space character here
+ if (charName && !charName[0]) {
+ writePS(" ");
+ }
+ }
+ writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
+ }
+ writePS("pdfMakeFont\n");
+ }
+
+ delete psName;
+}
+
+void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
+ static const char hexChar[17] = "0123456789abcdef";
+ Object refObj, strObj, obj1, obj2, obj3;
+ Dict *dict;
+ long length1, length2, length3;
+ int c;
+ int start[4];
+ GBool binMode;
+ GBool writePadding = gTrue;
+ int i;
+
+ // check if font is already embedded
+ if (fontNames->lookupInt(psName)) {
+ return;
+ }
+ fontNames->add(psName->copy(), 1);
+
+ // get the font stream and info
+ refObj.initRef(id->num, id->gen);
+ refObj.fetch(xref, &strObj);
+ refObj.free();
+ if (!strObj.isStream()) {
+ error(errSyntaxError, -1, "Embedded font file object is not a stream");
+ goto err1;
+ }
+ if (!(dict = strObj.streamGetDict())) {
+ error(errSyntaxError, -1,
+ "Embedded font stream is missing its dictionary");
+ goto err1;
+ }
+ dict->lookup("Length1", &obj1);
+ dict->lookup("Length2", &obj2);
+ dict->lookup("Length3", &obj3);
+ if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
+ error(errSyntaxError, -1,
+ "Missing length fields in embedded font stream dictionary");
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ goto err1;
+ }
+ length1 = obj1.getInt();
+ length2 = obj2.getInt();
+ length3 = obj3.getInt();
+ obj1.free();
+ obj2.free();
+ obj3.free();
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ strObj.streamReset();
+ if (strObj.streamGetChar() == 0x80 &&
+ strObj.streamGetChar() == 1) {
+ // PFB format
+ length1 = strObj.streamGetChar() |
+ (strObj.streamGetChar() << 8) |
+ (strObj.streamGetChar() << 16) |
+ (strObj.streamGetChar() << 24);
+ } else {
+ strObj.streamReset();
+ }
+ // copy ASCII portion of font
+ for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
+ writePSChar(c);
+ }
+
+ // figure out if encrypted portion is binary or ASCII
+ binMode = gFalse;
+ for (i = 0; i < 4; ++i) {
+ start[i] = strObj.streamGetChar();
+ if (start[i] == EOF) {
+ error(errSyntaxError, -1,
+ "Unexpected end of file in embedded font stream");
+ goto err1;
+ }
+ if (!((start[i] >= '0' && start[i] <= '9') ||
+ (start[i] >= 'A' && start[i] <= 'F') ||
+ (start[i] >= 'a' && start[i] <= 'f')))
+ binMode = gTrue;
+ }
+
+ if (length2 == 0)
+ {
+ // length2 == 0 is an error
+ // trying to solve it by just piping all
+ // the stream data
+ error(errSyntaxWarning, -1, "Font has length2 as 0, trying to overcome the problem reading the stream until the end");
+ length2 = INT_MAX;
+ writePadding = gFalse;
+ }
+
+
+ // convert binary data to ASCII
+ if (binMode) {
+ if (start[0] == 0x80 &&
+ start[1] == 2) {
+ length2 = start[2] |
+ (start[3] << 8) |
+ (strObj.streamGetChar() << 16) |
+ (strObj.streamGetChar() << 24);
+ i = 0;
+ } else {
+ for (i = 0; i < 4; ++i) {
+ writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
+ writePSChar(hexChar[start[i] & 0x0f]);
+ }
+ }
+#if 0 // this causes trouble for various PostScript printers
+ // if Length2 is incorrect (too small), font data gets chopped, so
+ // we take a few extra characters from the trailer just in case
+ length2 += length3 >= 8 ? 8 : length3;
+#endif
+ while (i < length2) {
+ if ((c = strObj.streamGetChar()) == EOF) {
+ break;
+ }
+ writePSChar(hexChar[(c >> 4) & 0x0f]);
+ writePSChar(hexChar[c & 0x0f]);
+ if (++i % 32 == 0) {
+ writePSChar('\n');
+ }
+ }
+ if (i % 32 > 0) {
+ writePSChar('\n');
+ }
+
+ // already in ASCII format -- just copy it
+ } else {
+ for (i = 0; i < 4; ++i) {
+ writePSChar(start[i]);
+ }
+ for (i = 4; i < length2; ++i) {
+ if ((c = strObj.streamGetChar()) == EOF) {
+ break;
+ }
+ writePSChar(c);
+ }
+ }
+
+ if (writePadding)
+ {
+ if (length3 > 0) {
+ // write fixed-content portion
+ c = strObj.streamGetChar();
+ if (c == 0x80) {
+ c = strObj.streamGetChar();
+ if (c == 1) {
+ length3 = strObj.streamGetChar() |
+ (strObj.streamGetChar() << 8) |
+ (strObj.streamGetChar() << 16) |
+ (strObj.streamGetChar() << 24);
+
+ i = 0;
+ while (i < length3) {
+ if ((c = strObj.streamGetChar()) == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++i;
+ }
+ }
+ } else {
+ if (c != EOF) {
+ writePSChar(c);
+
+ while ((c = strObj.streamGetChar()) != EOF) {
+ writePSChar(c);
+ }
+ }
+ }
+ } else {
+ // write padding and "cleartomark"
+ for (i = 0; i < 8; ++i) {
+ writePS("00000000000000000000000000000000"
+ "00000000000000000000000000000000\n");
+ }
+ writePS("cleartomark\n");
+ }
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+
+ err1:
+ if (strObj.isStream())
+ strObj.streamClose();
+ strObj.free();
+}
+
+void PSOutputDev::setupExternalType1Font(GooString *fileName, GooString *psName) {
+ static const char hexChar[17] = "0123456789abcdef";
+ FILE *fontFile;
+ int c;
+
+ if (fontNames->lookupInt(psName)) {
+ return;
+ }
+ fontNames->add(psName->copy(), 1);
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // copy the font file
+ if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
+ error(errIO, -1, "Couldn't open external font file");
+ return;
+ }
+
+ c = fgetc(fontFile);
+ if (c == 0x80) {
+ // PFB file
+ ungetc(c, fontFile);
+ while (!feof(fontFile)) {
+ fgetc(fontFile); // skip start of segment byte (0x80)
+ int segType = fgetc(fontFile);
+ long segLen = fgetc(fontFile) |
+ (fgetc(fontFile) << 8) |
+ (fgetc(fontFile) << 16) |
+ (fgetc(fontFile) << 24);
+ if (feof(fontFile))
+ break;
+
+ if (segType == 1) {
+ // ASCII segment
+ for (long i = 0; i < segLen; i++) {
+ c = fgetc(fontFile);
+ if (c == EOF)
+ break;
+ writePSChar(c);
+ }
+ } else if (segType == 2) {
+ // binary segment
+ for (long i = 0; i < segLen; i++) {
+ c = fgetc(fontFile);
+ if (c == EOF)
+ break;
+ writePSChar(hexChar[(c >> 4) & 0x0f]);
+ writePSChar(hexChar[c & 0x0f]);
+ if (i % 36 == 35)
+ writePSChar('\n');
+ }
+ } else {
+ // end of file
+ break;
+ }
+ }
+ } else if (c != EOF) {
+ writePSChar(c);
+ while ((c = fgetc(fontFile)) != EOF)
+ writePSChar(c);
+ }
+ fclose(fontFile);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
+ GooString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiType1C *ffT1C;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < t1FontNameLen; ++i) {
+ if (t1FontNames[i].fontFileID.num == id->num &&
+ t1FontNames[i].fontFileID.gen == id->gen) {
+ psName->clear();
+ psName->insert(0, t1FontNames[i].psName);
+ return;
+ }
+ }
+ if (t1FontNameLen == t1FontNameSize) {
+ t1FontNameSize *= 2;
+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
+ sizeof(PST1FontName));
+ }
+ t1FontNames[t1FontNameLen].fontFileID = *id;
+ t1FontNames[t1FontNameLen].psName = psName->copy();
+ ++t1FontNameLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 1 font
+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+ ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
+ outputFunc, outputStream);
+ delete ffT1C;
+ }
+ gfree(fontBuf);
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id,
+ GooString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < t1FontNameLen; ++i) {
+ if (t1FontNames[i].fontFileID.num == id->num &&
+ t1FontNames[i].fontFileID.gen == id->gen) {
+ psName->clear();
+ psName->insert(0, t1FontNames[i].psName);
+ return;
+ }
+ }
+ if (t1FontNameLen == t1FontNameSize) {
+ t1FontNameSize *= 2;
+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
+ sizeof(PST1FontName));
+ }
+ t1FontNames[t1FontNameLen].fontFileID = *id;
+ t1FontNames[t1FontNameLen].psName = psName->copy();
+ ++t1FontNameLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 1 font
+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ if (ffTT->isOpenTypeCFF()) {
+ ffTT->convertToType1(psName->getCString(), NULL, gTrue,
+ outputFunc, outputStream);
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
+ GooString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ int *codeToGID;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+ ffTT->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getHasEncoding()
+ ? ((Gfx8BitFont *)font)->getEncoding()
+ : (char **)NULL,
+ codeToGID, outputFunc, outputStream);
+ if (codeToGID) {
+ if (font8InfoLen >= font8InfoSize) {
+ font8InfoSize += 16;
+ font8Info = (PSFont8Info *)greallocn(font8Info,
+ font8InfoSize,
+ sizeof(PSFont8Info));
+ }
+ font8Info[font8InfoLen].fontID = *font->getID();
+ font8Info[font8InfoLen].codeToGID = codeToGID;
+ ++font8InfoLen;
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GooString *fileName,
+ GooString *psName) {
+ FoFiTrueType *ffTT;
+ int *codeToGID;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) {
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+ ffTT->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getHasEncoding()
+ ? ((Gfx8BitFont *)font)->getEncoding()
+ : (char **)NULL,
+ codeToGID, outputFunc, outputStream);
+ if (codeToGID) {
+ if (font8InfoLen >= font8InfoSize) {
+ font8InfoSize += 16;
+ font8Info = (PSFont8Info *)greallocn(font8Info,
+ font8InfoSize,
+ sizeof(PSFont8Info));
+ }
+ font8Info[font8InfoLen].fontID = *font->getID();
+ font8Info[font8InfoLen].codeToGID = codeToGID;
+ ++font8InfoLen;
+ }
+ delete ffTT;
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font,
+ GooString *fileName,
+ GooString *psName,
+ GBool needVerticalMetrics) {
+ FoFiTrueType *ffTT;
+ int *codeToGID;
+ int codeToGIDLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ //~ this should use fontNum to load the correct font
+ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) {
+
+ // check for embedding permission
+ if (ffTT->getEmbeddingRights() >= 1) {
+ codeToGID = NULL;
+ codeToGIDLen = 0;
+ if (((GfxCIDFont *)font)->getCIDToGID()) {
+ codeToGIDLen = ((GfxCIDFont *)font)->getCIDToGIDLen();
+ if (codeToGIDLen) {
+ codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int));
+ memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(),
+ codeToGIDLen * sizeof(int));
+ }
+ } else {
+ codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &codeToGIDLen);
+ }
+ if (ffTT->isOpenTypeCFF()) {
+ ffTT->convertToCIDType0(psName->getCString(),
+ codeToGID, codeToGIDLen,
+ outputFunc, outputStream);
+ } else if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffTT->convertToCIDType2(psName->getCString(),
+ codeToGID, codeToGIDLen,
+ needVerticalMetrics,
+ outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffTT->convertToType0(psName->getCString(),
+ codeToGID, codeToGIDLen,
+ needVerticalMetrics,
+ outputFunc, outputStream);
+ }
+ gfree(codeToGID);
+ } else {
+ error(errSyntaxError, -1,
+ "TrueType font '{0:s}' does not allow embedding",
+ font->getName() ? font->getName()->getCString() : "(unnamed)");
+
+ }
+ delete ffTT;
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
+ GooString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiType1C *ffT1C;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < t1FontNameLen; ++i) {
+ if (t1FontNames[i].fontFileID.num == id->num &&
+ t1FontNames[i].fontFileID.gen == id->gen) {
+ psName->clear();
+ psName->insert(0, t1FontNames[i].psName);
+ return;
+ }
+ }
+ if (t1FontNameLen == t1FontNameSize) {
+ t1FontNameSize *= 2;
+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
+ sizeof(PST1FontName));
+ }
+ t1FontNames[t1FontNameLen].fontFileID = *id;
+ t1FontNames[t1FontNameLen].psName = psName->copy();
+ ++t1FontNameLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffT1C->convertToCIDType0(psName->getCString(), NULL, 0,
+ outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffT1C->convertToType0(psName->getCString(), NULL, 0,
+ outputFunc, outputStream);
+ }
+ delete ffT1C;
+ }
+ gfree(fontBuf);
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
+ GooString *psName,
+ GBool needVerticalMetrics) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffTT->convertToCIDType2(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
+ needVerticalMetrics,
+ outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffTT->convertToType0(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
+ needVerticalMetrics,
+ outputFunc, outputStream);
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id,
+ GooString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < t1FontNameLen; ++i) {
+ if (t1FontNames[i].fontFileID.num == id->num &&
+ t1FontNames[i].fontFileID.gen == id->gen) {
+ psName->clear();
+ psName->insert(0, t1FontNames[i].psName);
+ return;
+ }
+ }
+ if (t1FontNameLen == t1FontNameSize) {
+ t1FontNameSize *= 2;
+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
+ sizeof(PST1FontName));
+ }
+ t1FontNames[t1FontNameLen].fontFileID = *id;
+ t1FontNames[t1FontNameLen].psName = psName->copy();
+ ++t1FontNameLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ if (ffTT->isOpenTypeCFF()) {
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffTT->convertToCIDType0(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
+ outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffTT->convertToType0(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
+ outputFunc, outputStream);
+ }
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName,
+ Dict *parentResDict) {
+ Dict *resDict;
+ Dict *charProcs;
+ Object charProc;
+ Gfx *gfx;
+ PDFRectangle box;
+ double *m;
+ GooString *buf;
+ int i;
+
+ // set up resources used by font
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+ inType3Char = gTrue;
+ setupResources(resDict);
+ inType3Char = gFalse;
+ } else {
+ resDict = parentResDict;
+ }
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // font dictionary
+ writePS("8 dict begin\n");
+ writePS("/FontType 3 def\n");
+ m = font->getFontMatrix();
+ writePSFmt("/FontMatrix [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+ m = font->getFontBBox();
+ writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
+ m[0], m[1], m[2], m[3]);
+ writePS("/Encoding 256 array def\n");
+ writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
+ writePS("/BuildGlyph {\n");
+ writePS(" exch /CharProcs get exch\n");
+ writePS(" 2 copy known not { pop /.notdef } if\n");
+ writePS(" get exec\n");
+ writePS("} bind def\n");
+ writePS("/BuildChar {\n");
+ writePS(" 1 index /Encoding get exch get\n");
+ writePS(" 1 index /BuildGlyph get exec\n");
+ writePS("} bind def\n");
+ if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
+ writePSFmt("/CharProcs {0:d} dict def\n", charProcs->getLength());
+ writePS("CharProcs begin\n");
+ box.x1 = m[0];
+ box.y1 = m[1];
+ box.x2 = m[2];
+ box.y2 = m[3];
+ gfx = new Gfx(doc, this, resDict, &box, NULL);
+ inType3Char = gTrue;
+ for (i = 0; i < charProcs->getLength(); ++i) {
+ t3FillColorOnly = gFalse;
+ t3Cacheable = gFalse;
+ t3NeedsRestore = gFalse;
+ writePS("/");
+ writePSName(charProcs->getKey(i));
+ writePS(" {\n");
+ gfx->display(charProcs->getVal(i, &charProc));
+ charProc.free();
+ if (t3String) {
+ if (t3Cacheable) {
+ buf = GooString::format("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} setcachedevice\n",
+ t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
+ } else {
+ buf = GooString::format("{0:.6g} {1:.6g} setcharwidth\n", t3WX, t3WY);
+ }
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, t3String->getCString(),
+ t3String->getLength());
+ delete t3String;
+ t3String = NULL;
+ }
+ if (t3NeedsRestore) {
+ (*outputFunc)(outputStream, "Q\n", 2);
+ }
+ writePS("} def\n");
+ }
+ inType3Char = gFalse;
+ delete gfx;
+ writePS("end\n");
+ }
+ writePS("currentdict end\n");
+ writePSFmt("/{0:t} exch definefont pop\n", psName);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+// Make a unique PS font name, based on the names given in the PDF
+// font object, and an object ID (font file object for
+GooString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) {
+ GooString *psName, *s;
+
+ if ((s = font->getEmbeddedFontName())) {
+ psName = filterPSName(s);
+ if (!fontNames->lookupInt(psName)) {
+ fontNames->add(psName->copy(), 1);
+ return psName;
+ }
+ delete psName;
+ }
+ if ((s = font->getName())) {
+ psName = filterPSName(s);
+ if (!fontNames->lookupInt(psName)) {
+ fontNames->add(psName->copy(), 1);
+ return psName;
+ }
+ delete psName;
+ }
+ psName = GooString::format("FF{0:d}_{1:d}", id->num, id->gen);
+ if ((s = font->getEmbeddedFontName())) {
+ s = filterPSName(s);
+ psName->append('_')->append(s);
+ delete s;
+ } else if ((s = font->getName())) {
+ s = filterPSName(s);
+ psName->append('_')->append(s);
+ delete s;
+ }
+ fontNames->add(psName->copy(), 1);
+ return psName;
+}
+
+void PSOutputDev::setupImages(Dict *resDict) {
+ Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef;
+ Ref imgID;
+ int i, j;
+
+ if (!(mode == psModeForm || inType3Char || preloadImagesForms)) {
+ return;
+ }
+
+ //----- recursively scan XObjects
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+ xObjDict.dictGetValNF(i, &xObjRef);
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+ if (subtypeObj.isName("Image")) {
+ if (xObjRef.isRef()) {
+ imgID = xObjRef.getRef();
+ for (j = 0; j < imgIDLen; ++j) {
+ if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) {
+ break;
+ }
+ }
+ if (j == imgIDLen) {
+ if (imgIDLen >= imgIDSize) {
+ if (imgIDSize == 0) {
+ imgIDSize = 64;
+ } else {
+ imgIDSize *= 2;
+ }
+ imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
+ }
+ imgIDs[imgIDLen++] = imgID;
+ setupImage(imgID, xObj.getStream(), gFalse);
+ if (level >= psLevel3 &&
+ xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) {
+ setupImage(imgID, maskObj.getStream(), gTrue);
+ }
+ maskObj.free();
+ }
+ } else {
+ error(errSyntaxError, -1,
+ "Image in resource dict is not an indirect reference");
+ }
+ }
+ subtypeObj.free();
+ }
+ xObj.free();
+ xObjRef.free();
+ }
+ }
+ xObjDict.free();
+}
+
+void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
+ GBool useRLE, useCompressed, doUseASCIIHex;
+ GooString *s;
+ int c;
+ int size, line, col, i;
+ int outerSize, outer;
+
+ // filters
+ //~ this does not correctly handle the DeviceN color space
+ //~ -- need to use DeviceNRecoder
+ if (level < psLevel2) {
+ useRLE = gFalse;
+ useCompressed = gFalse;
+ doUseASCIIHex = gTrue;
+ } else {
+ if (uncompressPreloadedImages) {
+ useRLE = gFalse;
+ useCompressed = gFalse;
+ } else {
+ s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
+ if (s) {
+ useRLE = gFalse;
+ useCompressed = gTrue;
+ delete s;
+ } else {
+ useRLE = gTrue;
+ useCompressed = gFalse;
+ }
+ }
+ doUseASCIIHex = useASCIIHex;
+ }
+ if (useCompressed) {
+ str = str->getUndecodedStream();
+ }
+ if (useRLE) {
+ str = new RunLengthEncoder(str);
+ }
+ if (doUseASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+
+ // compute image data size
+ str->reset();
+ col = size = 0;
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (doUseASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ ++col;
+ } else {
+ ++col;
+ for (i = 1; i <= (doUseASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (doUseASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ ++col;
+ }
+ if (c == (doUseASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ }
+ if (col > 225) {
+ ++size;
+ col = 0;
+ }
+ } while (c != (doUseASCIIHex ? '>' : '~') && c != EOF);
+ // add one entry for the final line of data; add another entry
+ // because the RunLengthDecode filter may read past the end
+ ++size;
+ if (useRLE) {
+ ++size;
+ }
+ outerSize = size/65535 + 1;
+
+ writePSFmt("{0:d} array dup /{1:s}Data_{2:d}_{3:d} exch def\n",
+ outerSize, mask ? "Mask" : "Im", id.num, id.gen);
+ str->close();
+
+ // write the data into the array
+ str->reset();
+ for (outer = 0;outer < outerSize;outer++) {
+ int innerSize = size > 65535 ? 65535 : size;
+
+ // put the inner array into the outer array
+ writePSFmt("{0:d} array 1 index {1:d} 2 index put\n",
+ innerSize, outer);
+ line = col = 0;
+ writePS((char *)(doUseASCIIHex ? "dup 0 <" : "dup 0 <~"));
+ for (;;) {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (doUseASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ writePSChar(c);
+ ++col;
+ } else {
+ writePSChar(c);
+ ++col;
+ for (i = 1; i <= (doUseASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (doUseASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ }
+ }
+ if (c == (doUseASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ // each line is: "dup nnnnn <~...data...~> put<eol>"
+ // so max data length = 255 - 20 = 235
+ // chunks are 1 or 4 bytes each, so we have to stop at 232
+ // but make it 225 just to be safe
+ if (col > 225) {
+ writePS((char *)(doUseASCIIHex ? "> put\n" : "~> put\n"));
+ ++line;
+ if (line >= innerSize) break;
+ writePSFmt((char *)(doUseASCIIHex ? "dup {0:d} <" : "dup {0:d} <~"), line);
+ col = 0;
+ }
+ }
+ if (c == (doUseASCIIHex ? '>' : '~') || c == EOF) {
+ writePS((char *)(doUseASCIIHex ? "> put\n" : "~> put\n"));
+ if (useRLE) {
+ ++line;
+ writePSFmt("{0:d} <> put\n", line);
+ } else {
+ writePS("pop\n");
+ }
+ break;
+ }
+ writePS("pop\n");
+ size -= innerSize;
+ }
+ writePS("pop\n");
+ str->close();
+
+ delete str;
+}
+
+void PSOutputDev::setupForms(Dict *resDict) {
+ Object xObjDict, xObj, xObjRef, subtypeObj;
+ int i;
+
+ if (!preloadImagesForms) {
+ return;
+ }
+
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+ xObjDict.dictGetValNF(i, &xObjRef);
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+ if (subtypeObj.isName("Form")) {
+ if (xObjRef.isRef()) {
+ setupForm(xObjRef.getRef(), &xObj);
+ } else {
+ error(errSyntaxError, -1,
+ "Form in resource dict is not an indirect reference");
+ }
+ }
+ subtypeObj.free();
+ }
+ xObj.free();
+ xObjRef.free();
+ }
+ }
+ xObjDict.free();
+}
+
+void PSOutputDev::setupForm(Ref id, Object *strObj) {
+ Dict *dict, *resDict;
+ Object matrixObj, bboxObj, resObj, obj1;
+ double m[6], bbox[4];
+ PDFRectangle box;
+ Gfx *gfx;
+ int i;
+
+ // check if form is already defined
+ for (i = 0; i < formIDLen; ++i) {
+ if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) {
+ return;
+ }
+ }
+
+ // add entry to formIDs list
+ if (formIDLen >= formIDSize) {
+ if (formIDSize == 0) {
+ formIDSize = 64;
+ } else {
+ formIDSize *= 2;
+ }
+ formIDs = (Ref *)greallocn(formIDs, formIDSize, sizeof(Ref));
+ }
+ formIDs[formIDLen++] = id;
+
+ dict = strObj->streamGetDict();
+
+ // get bounding box
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ bboxObj.free();
+ error(errSyntaxError, -1, "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ bboxObj.arrayGet(i, &obj1);
+ bbox[i] = obj1.getNum();
+ obj1.free();
+ }
+ bboxObj.free();
+
+ // get matrix
+ dict->lookup("Matrix", &matrixObj);
+ if (matrixObj.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ matrixObj.arrayGet(i, &obj1);
+ m[i] = obj1.getNum();
+ obj1.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ matrixObj.free();
+
+ // get resources
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen);
+ writePS("q\n");
+ writePSFmt("[{0:.6gs} {1:.6gs} {2:.6gs} {3:.6gs} {4:.6gs} {5:.6gs}] cm\n",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+
+ box.x1 = bbox[0];
+ box.y1 = bbox[1];
+ box.x2 = bbox[2];
+ box.y2 = bbox[3];
+ gfx = new Gfx(doc, this, resDict, &box, &box);
+ gfx->display(strObj);
+ delete gfx;
+
+ writePS("Q\n");
+ writePS("} def\n");
+
+ resObj.free();
+}
+
+GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
+ int rotateA, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY,
+ int sliceW, int sliceH,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
+ void *annotDisplayDecideCbkData) {
+ PreScanOutputDev *scan;
+ GBool rasterize;
+#if HAVE_SPLASH
+ SplashOutputDev *splashOut;
+ SplashColor paperColor;
+ PDFRectangle box;
+ GfxState *state;
+ SplashBitmap *bitmap;
+ Stream *str0, *str;
+ Object obj;
+ Guchar *p;
+ Guchar col[4];
+ double hDPI2, vDPI2;
+ double m0, m1, m2, m3, m4, m5;
+ int nStripes, stripeH, stripeY;
+ int c, w, h, x, y, comp, i;
+ int numComps, initialNumComps;
+#endif
+ char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
+ Guchar digit;
+ GBool isGray;
+
+ if (!postInitDone) {
+ postInit();
+ }
+ if (forceRasterize) {
+ rasterize = gTrue;
+ } else {
+ scan = new PreScanOutputDev(doc);
+ page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ printing, abortCheckCbk, abortCheckCbkData,
+ annotDisplayDecideCbk, annotDisplayDecideCbkData);
+ rasterize = scan->usesTransparency() || scan->usesPatternImageMask();
+ delete scan;
+ }
+ if (!rasterize) {
+ return gTrue;
+ }
+
+#if HAVE_SPLASH
+ // start the PS page
+ page->makeBox(rasterResolution, rasterResolution, rotateA, useMediaBox, gFalse,
+ sliceX, sliceY, sliceW, sliceH, &box, &crop);
+ rotateA += page->getRotate();
+ if (rotateA >= 360) {
+ rotateA -= 360;
+ } else if (rotateA < 0) {
+ rotateA += 360;
+ }
+ state = new GfxState(rasterResolution, rasterResolution, &box, rotateA, gFalse);
+ startPage(page->getNum(), state, xref);
+ delete state;
+
+ // set up the SplashOutputDev
+ if (rasterMono || level == psLevel1) {
+ numComps = 1;
+ paperColor[0] = 0xff;
+ splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
+ paperColor, gFalse);
+#if SPLASH_CMYK
+ } else if (level == psLevel1Sep || level == psLevel2Sep ||
+ level == psLevel3Sep || globalParams->getOverprintPreview()) {
+ numComps = 4;
+ paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
+ splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
+ paperColor, gFalse);
+#endif
+ } else {
+ numComps = 3;
+ paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
+ splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
+ paperColor, gFalse);
+ }
+ splashOut->setFontAntialias(rasterAntialias);
+ splashOut->setVectorAntialias(rasterAntialias);
+ splashOut->startDoc(doc);
+
+ // break the page into stripes
+ hDPI2 = xScale * rasterResolution;
+ vDPI2 = yScale * rasterResolution;
+ if (sliceW < 0 || sliceH < 0) {
+ if (useMediaBox) {
+ box = *page->getMediaBox();
+ } else {
+ box = *page->getCropBox();
+ }
+ sliceX = sliceY = 0;
+ sliceW = (int)((box.x2 - box.x1) * hDPI2 / 72.0);
+ sliceH = (int)((box.y2 - box.y1) * vDPI2 / 72.0);
+ }
+ nStripes = (int)ceil((double)(sliceW * sliceH) /
+ (double)rasterizationSliceSize);
+ stripeH = (sliceH + nStripes - 1) / nStripes;
+
+ // render the stripes
+ initialNumComps = numComps;
+ for (stripeY = sliceY; stripeY < sliceH; stripeY += stripeH) {
+
+ // rasterize a stripe
+ page->makeBox(hDPI2, vDPI2, 0, useMediaBox, gFalse,
+ sliceX, stripeY, sliceW, stripeH, &box, &crop);
+ m0 = box.x2 - box.x1;
+ m1 = 0;
+ m2 = 0;
+ m3 = box.y2 - box.y1;
+ m4 = box.x1;
+ m5 = box.y1;
+ page->displaySlice(splashOut, hDPI2, vDPI2,
+ (360 - page->getRotate()) % 360, useMediaBox, crop,
+ sliceX, stripeY, sliceW, stripeH,
+ printing, abortCheckCbk, abortCheckCbkData,
+ annotDisplayDecideCbk, annotDisplayDecideCbkData);
+
+ // draw the rasterized image
+ bitmap = splashOut->getBitmap();
+ numComps = initialNumComps;
+ w = bitmap->getWidth();
+ h = bitmap->getHeight();
+ writePS("gsave\n");
+ writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
+ m0, m1, m2, m3, m4, m5);
+ switch (level) {
+ case psLevel1:
+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1{5:s}\n",
+ w, h, w, -h, h,
+ useBinary ? "Bin" : "");
+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
+ i = 0;
+ if (useBinary) {
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ hexBuf[i++] = *p++;
+ if (i >= 64) {
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ } else {
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ digit = *p / 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ digit = *p++ % 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ if (i >= 64) {
+ hexBuf[i++] = '\n';
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ }
+ if (i != 0) {
+ if (!useBinary) {
+ hexBuf[i++] = '\n';
+ }
+ writePSBuf(hexBuf, i);
+ }
+ break;
+ case psLevel1Sep:
+ p = bitmap->getDataPtr();
+ // Check for an all gray image
+ if (getOptimizeColorSpace()) {
+ isGray = gTrue;
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ if (p[4*x] != p[4*x + 1] || p[4*x] != p[4*x + 2]) {
+ isGray = gFalse;
+ y = h;
+ break;
+ }
+ }
+ p += bitmap->getRowSize();
+ }
+ } else {
+ isGray = gFalse;
+ }
+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1{5:s}{6:s}\n",
+ w, h, w, -h, h,
+ isGray ? "" : "Sep",
+ useBinary ? "Bin" : "");
+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
+ i = 0;
+ col[0] = col[1] = col[2] = col[3] = 0;
+ if (isGray) {
+ int g;
+ if ((psProcessBlack & processColors) == 0) {
+ // Check if the image uses black
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ if (p[4*x] > 0 || p[4*x + 3] > 0) {
+ col[3] = 1;
+ y = h;
+ break;
+ }
+ }
+ p -= bitmap->getRowSize();
+ }
+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
+ }
+ for (y = 0; y < h; ++y) {
+ if (useBinary) {
+ // Binary gray image
+ for (x = 0; x < w; ++x) {
+ g = p[4*x] + p[4*x + 3];
+ g = 255 - g;
+ if (g < 0) g = 0;
+ hexBuf[i++] = (Guchar) g;
+ if (i >= 64) {
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ } else {
+ // Hex gray image
+ for (x = 0; x < w; ++x) {
+ g = p[4*x] + p[4*x + 3];
+ g = 255 - g;
+ if (g < 0) g = 0;
+ digit = g / 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ digit = g % 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ if (i >= 64) {
+ hexBuf[i++] = '\n';
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ p -= bitmap->getRowSize();
+ }
+ } else if (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0) {
+ // Color image, need to check color flags for each dot
+ for (y = 0; y < h; ++y) {
+ for (comp = 0; comp < 4; ++comp) {
+ if (useBinary) {
+ // Binary color image
+ for (x = 0; x < w; ++x) {
+ col[comp] |= p[4*x + comp];
+ hexBuf[i++] = p[4*x + comp];
+ if (i >= 64) {
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ } else {
+ // Gray color image
+ for (x = 0; x < w; ++x) {
+ col[comp] |= p[4*x + comp];
+ digit = p[4*x + comp] / 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ digit = p[4*x + comp] % 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ if (i >= 64) {
+ hexBuf[i++] = '\n';
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ }
+ p -= bitmap->getRowSize();
+ }
+ } else {
+ // Color image, do not need to check color flags
+ for (y = 0; y < h; ++y) {
+ for (comp = 0; comp < 4; ++comp) {
+ if (useBinary) {
+ // Binary color image
+ for (x = 0; x < w; ++x) {
+ hexBuf[i++] = p[4*x + comp];
+ if (i >= 64) {
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ } else {
+ // Hex color image
+ for (x = 0; x < w; ++x) {
+ digit = p[4*x + comp] / 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ digit = p[4*x + comp] % 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ if (i >= 64) {
+ hexBuf[i++] = '\n';
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ }
+ p -= bitmap->getRowSize();
+ }
+ }
+ if (i != 0) {
+ if (!useBinary) {
+ hexBuf[i++] = '\n';
+ }
+ writePSBuf(hexBuf, i);
+ }
+ if (col[0]) {
+ processColors |= psProcessCyan;
+ }
+ if (col[1]) {
+ processColors |= psProcessMagenta;
+ }
+ if (col[2]) {
+ processColors |= psProcessYellow;
+ }
+ if (col[3]) {
+ processColors |= psProcessBlack;
+ }
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ case psLevel3:
+ case psLevel3Sep:
+ obj.initNull();
+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
+ str0 = new MemStream((char *)p, 0, w * h * numComps, &obj);
+ // Check for a color image that uses only gray
+ if (!getOptimizeColorSpace()) {
+ isGray = gFalse;
+ } else if (numComps == 4) {
+ int compCyan;
+ isGray = gTrue;
+ while ((compCyan = str0->getChar()) != EOF) {
+ if (str0->getChar() != compCyan ||
+ str0->getChar() != compCyan) {
+ isGray = gFalse;
+ break;
+ }
+ str0->getChar();
+ }
+ } else if (numComps == 3) {
+ int compRed;
+ isGray = gTrue;
+ while ((compRed = str0->getChar()) != EOF) {
+ if (str0->getChar() != compRed ||
+ str0->getChar() != compRed) {
+ isGray = gFalse;
+ break;
+ }
+ }
+ } else {
+ isGray = gFalse;
+ }
+ str0->reset();
+ if (isGray && numComps == 4) {
+ str = new RunLengthEncoder(new CMYKGrayEncoder(str0));
+ numComps = 1;
+ } else if (isGray && numComps == 3) {
+ str = new RunLengthEncoder(new RGBGrayEncoder(str0));
+ numComps = 1;
+ } else {
+ str = new RunLengthEncoder(str0);
+ }
+ if (numComps == 1) {
+ writePS("/DeviceGray setcolorspace\n");
+ } else if (numComps == 3) {
+ writePS("/DeviceRGB setcolorspace\n");
+ } else {
+ writePS("/DeviceCMYK setcolorspace\n");
+ }
+ writePS("<<\n /ImageType 1\n");
+ writePSFmt(" /Width {0:d}\n", bitmap->getWidth());
+ writePSFmt(" /Height {0:d}\n", bitmap->getHeight());
+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
+ writePS(" /BitsPerComponent 8\n");
+ if (numComps == 1) {
+ writePS(" /Decode [1 0]\n");
+ } else if (numComps == 3) {
+ writePS(" /Decode [0 1 0 1 0 1]\n");
+ } else {
+ writePS(" /Decode [0 1 0 1 0 1 0 1]\n");
+ }
+ writePS(" /DataSource currentfile\n");
+ if (useBinary) {
+ /* nothing to do */;
+ } else if (useASCIIHex) {
+ writePS(" /ASCIIHexDecode filter\n");
+ } else {
+ writePS(" /ASCII85Decode filter\n");
+ }
+ writePS(" /RunLengthDecode filter\n");
+ writePS(">>\n");
+ if (useBinary) {
+ /* nothing to do */;
+ } else if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+ str->reset();
+ if (useBinary) {
+ // Count the bytes to write a document comment
+ int len = 0;
+ while (str->getChar() != EOF) {
+ len++;
+ }
+ str->reset();
+ writePSFmt("%%BeginData: {0:d} Binary Bytes\n", len+6+1);
+ }
+ writePS("image\n");
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
+ delete str;
+ delete str0;
+ writePSChar('\n');
+ if (useBinary) {
+ writePS("%%EndData\n");
+ }
+ processColors |= (numComps == 1) ? psProcessBlack : psProcessCMYK;
+ break;
+ }
+ writePS("grestore\n");
+ }
+
+ delete splashOut;
+
+ // finish the PS page
+ endPage();
+
+ return gFalse;
+
+#else // HAVE_SPLASH
+
+ error(errSyntaxWarning, -1,
+ "PDF page uses transparency and PSOutputDev was built without"
+ " the Splash rasterizer - output may not be correct");
+ return gTrue;
+#endif // HAVE_SPLASH
+}
+
+void PSOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) {
+ Page *page;
+ int x1, y1, x2, y2, width, height, t;
+ int imgWidth, imgHeight, imgWidth2, imgHeight2;
+ GBool landscape;
+ GooString *s;
+ PSOutPaperSize *paperSize;
+
+ if (!postInitDone) {
+ postInit();
+ }
+ xref = xrefA;
+ if (mode == psModePS) {
+ GooString pageLabel;
+ const GBool gotLabel = doc->getCatalog()->indexToLabel(pageNum -1, &pageLabel);
+ if (gotLabel) {
+ // See bug13338 for why we try to avoid parentheses...
+ GBool needParens;
+ GooString *filteredString = filterPSLabel(&pageLabel, &needParens);
+ if (needParens) {
+ writePSFmt("%%Page: ({0:t}) {1:d}\n", filteredString, seqPage);
+ } else {
+ writePSFmt("%%Page: {0:t} {1:d}\n", filteredString, seqPage);
+ }
+ delete filteredString;
+ } else {
+ writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
+ }
+ if (paperMatch) {
+ page = doc->getCatalog()->getPage(pageNum);
+ imgLLX = imgLLY = 0;
+ if (noCrop) {
+ imgURX = (int)ceil(page->getMediaWidth());
+ imgURY = (int)ceil(page->getMediaHeight());
+ } else {
+ imgURX = (int)ceil(page->getCropWidth());
+ imgURY = (int)ceil(page->getCropHeight());
+ }
+ if (state->getRotate() == 90 || state->getRotate() == 270) {
+ t = imgURX;
+ imgURX = imgURY;
+ imgURY = t;
+ }
+ }
+ }
+
+ // underlays
+ if (underlayCbk) {
+ (*underlayCbk)(this, underlayCbkData);
+ }
+ if (overlayCbk) {
+ saveState(NULL);
+ }
+
+ xScale = yScale = 1;
+ switch (mode) {
+
+ case psModePS:
+ // rotate, translate, and scale page
+ imgWidth = imgURX - imgLLX;
+ imgHeight = imgURY - imgLLY;
+ x1 = (int)floor(state->getX1());
+ y1 = (int)floor(state->getY1());
+ x2 = (int)ceil(state->getX2());
+ y2 = (int)ceil(state->getY2());
+ width = x2 - x1;
+ height = y2 - y1;
+ tx = ty = 0;
+ // rotation and portrait/landscape mode
+ if (paperMatch) {
+ rotate = (360 - state->getRotate()) % 360;
+ landscape = gFalse;
+ } else if (rotate0 >= 0) {
+ rotate = (360 - rotate0) % 360;
+ landscape = gFalse;
+ } else {
+ rotate = (360 - state->getRotate()) % 360;
+ if (rotate == 0 || rotate == 180) {
+ if ((width < height && imgWidth > imgHeight && height > imgHeight) ||
+ (width > height && imgWidth < imgHeight && width > imgWidth)) {
+ rotate += 90;
+ landscape = gTrue;
+ } else {
+ landscape = gFalse;
+ }
+ } else { // rotate == 90 || rotate == 270
+ if ((height < width && imgWidth > imgHeight && width > imgHeight) ||
+ (height > width && imgWidth < imgHeight && height > imgWidth)) {
+ rotate = 270 - rotate;
+ landscape = gTrue;
+ } else {
+ landscape = gFalse;
+ }
+ }
+ }
+ if (paperMatch) {
+ paperSize = (PSOutPaperSize *)paperSizes->get(pagePaperSize[pageNum]);
+ writePSFmt("%%PageMedia: {0:t}\n", paperSize->name);
+ }
+ if (rotate == 0 || rotate == 180) {
+ writePSFmt("%%PageBoundingBox: 0 0 {0:d} {1:d}\n", width, height);
+ } else {
+ writePSFmt("%%PageBoundingBox: 0 0 {0:d} {1:d}\n", height, width);
+ }
+ writePSFmt("%%PageOrientation: {0:s}\n",
+ landscape ? "Landscape" : "Portrait");
+ writePS("%%BeginPageSetup\n");
+ if (paperMatch) {
+ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY);
+ }
+ writePS("pdfStartPage\n");
+ if (rotate == 0) {
+ imgWidth2 = imgWidth;
+ imgHeight2 = imgHeight;
+ } else if (rotate == 90) {
+ writePS("90 rotate\n");
+ ty = -imgWidth;
+ imgWidth2 = imgHeight;
+ imgHeight2 = imgWidth;
+ } else if (rotate == 180) {
+ writePS("180 rotate\n");
+ imgWidth2 = imgWidth;
+ imgHeight2 = imgHeight;
+ tx = -imgWidth;
+ ty = -imgHeight;
+ } else { // rotate == 270
+ writePS("270 rotate\n");
+ tx = -imgHeight;
+ imgWidth2 = imgHeight;
+ imgHeight2 = imgWidth;
+ }
+ // shrink or expand
+ if (xScale0 > 0 && yScale0 > 0) {
+ xScale = xScale0;
+ yScale = yScale0;
+ } else if ((globalParams->getPSShrinkLarger() &&
+ (width > imgWidth2 || height > imgHeight2)) ||
+ (globalParams->getPSExpandSmaller() &&
+ (width < imgWidth2 && height < imgHeight2))) {
+ xScale = (double)imgWidth2 / (double)width;
+ yScale = (double)imgHeight2 / (double)height;
+ if (yScale < xScale) {
+ xScale = yScale;
+ } else {
+ yScale = xScale;
+ }
+ }
+ // deal with odd bounding boxes or clipping
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ tx -= xScale * clipLLX0;
+ ty -= yScale * clipLLY0;
+ } else {
+ tx -= xScale * x1;
+ ty -= yScale * y1;
+ }
+ // center
+ if (tx0 >= 0 && ty0 >= 0) {
+ tx += (rotate == 0 || rotate == 180) ? tx0 : ty0;
+ ty += (rotate == 0 || rotate == 180) ? ty0 : -tx0;
+ } else if (globalParams->getPSCenter()) {
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2;
+ ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2;
+ } else {
+ tx += (imgWidth2 - xScale * width) / 2;
+ ty += (imgHeight2 - yScale * height) / 2;
+ }
+ }
+ tx += (rotate == 0 || rotate == 180) ? imgLLX : imgLLY;
+ ty += (rotate == 0 || rotate == 180) ? imgLLY : -imgLLX;
+ if (tx != 0 || ty != 0) {
+ writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
+ }
+ if (xScale != 1 || yScale != 1) {
+ writePSFmt("{0:.6f} {1:.6f} scale\n", xScale, yScale);
+ }
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n",
+ clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
+ } else {
+ writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
+ }
+
+ ++seqPage;
+ break;
+
+ case psModeEPS:
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ rotate = (360 - state->getRotate()) % 360;
+ if (rotate == 0) {
+ } else if (rotate == 90) {
+ writePS("90 rotate\n");
+ tx = -epsX1;
+ ty = -epsY2;
+ } else if (rotate == 180) {
+ writePS("180 rotate\n");
+ tx = -(epsX1 + epsX2);
+ ty = -(epsY1 + epsY2);
+ } else { // rotate == 270
+ writePS("270 rotate\n");
+ tx = -epsX2;
+ ty = -epsY1;
+ }
+ if (tx != 0 || ty != 0) {
+ writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
+ }
+ break;
+
+ case psModeForm:
+ writePS("/PaintProc {\n");
+ writePS("begin xpdf begin\n");
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ rotate = 0;
+ break;
+ }
+
+ if (customCodeCbk) {
+ if ((s = (*customCodeCbk)(this, psOutCustomPageSetup, pageNum,
+ customCodeCbkData))) {
+ writePS(s->getCString());
+ delete s;
+ }
+ }
+
+ writePS("%%EndPageSetup\n");
+}
+
+void PSOutputDev::endPage() {
+ if (overlayCbk) {
+ restoreState(NULL);
+ (*overlayCbk)(this, overlayCbkData);
+ }
+
+
+ if (mode == psModeForm) {
+ writePS("pdfEndPage\n");
+ writePS("end end\n");
+ writePS("} def\n");
+ writePS("end end\n");
+ } else {
+ if (!manualCtrl) {
+ writePS("showpage\n");
+ }
+ writePS("%%PageTrailer\n");
+ writePageTrailer();
+ }
+}
+
+void PSOutputDev::saveState(GfxState *state) {
+ writePS("q\n");
+ ++numSaves;
+}
+
+void PSOutputDev::restoreState(GfxState *state) {
+ writePS("Q\n");
+ --numSaves;
+}
+
+void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32) {
+ writePSFmt("[{0:.6gs} {1:.6gs} {2:.6gs} {3:.6gs} {4:.6gs} {5:.6gs}] cm\n",
+ m11, m12, m21, m22, m31, m32);
+}
+
+void PSOutputDev::updateLineDash(GfxState *state) {
+ double *dash;
+ double start;
+ int length, i;
+
+ state->getLineDash(&dash, &length, &start);
+ writePS("[");
+ for (i = 0; i < length; ++i) {
+ writePSFmt("{0:.6g}{1:w}",
+ dash[i] < 0 ? 0 : dash[i],
+ (i == length-1) ? 0 : 1);
+ }
+ writePSFmt("] {0:.6g} d\n", start);
+}
+
+void PSOutputDev::updateFlatness(GfxState *state) {
+ writePSFmt("{0:d} i\n", state->getFlatness());
+}
+
+void PSOutputDev::updateLineJoin(GfxState *state) {
+ writePSFmt("{0:d} j\n", state->getLineJoin());
+}
+
+void PSOutputDev::updateLineCap(GfxState *state) {
+ writePSFmt("{0:d} J\n", state->getLineCap());
+}
+
+void PSOutputDev::updateMiterLimit(GfxState *state) {
+ writePSFmt("{0:.6g} M\n", state->getMiterLimit());
+}
+
+void PSOutputDev::updateLineWidth(GfxState *state) {
+ writePSFmt("{0:.6g} w\n", state->getLineWidth());
+}
+
+void PSOutputDev::updateFillColorSpace(GfxState *state) {
+ if (inUncoloredPattern) {
+ return;
+ }
+ switch (level) {
+ case psLevel1:
+ case psLevel1Sep:
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getFillColorSpace()->getMode() != csPattern) {
+ dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse, gFalse);
+ writePS(" cs\n");
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ break;
+ }
+}
+
+void PSOutputDev::updateStrokeColorSpace(GfxState *state) {
+ if (inUncoloredPattern) {
+ return;
+ }
+ switch (level) {
+ case psLevel1:
+ case psLevel1Sep:
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getStrokeColorSpace()->getMode() != csPattern) {
+ dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse, gFalse);
+ writePS(" CS\n");
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ break;
+ }
+}
+
+void PSOutputDev::updateFillColor(GfxState *state) {
+ GfxColor color;
+ GfxColor *colorPtr;
+ GfxGray gray;
+ GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
+ double c, m, y, k;
+ int i;
+
+ if (inUncoloredPattern) {
+ return;
+ }
+ switch (level) {
+ case psLevel1:
+ state->getFillGray(&gray);
+ writePSFmt("{0:.4g} g\n", colToDbl(gray));
+ break;
+ case psLevel1Sep:
+ state->getFillCMYK(&cmyk);
+ c = colToDbl(cmyk.c);
+ m = colToDbl(cmyk.m);
+ y = colToDbl(cmyk.y);
+ k = colToDbl(cmyk.k);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
+ addProcessColor(c, m, y, k);
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getFillColorSpace()->getMode() != csPattern) {
+ colorPtr = state->getFillColor();
+ writePS("[");
+ for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
+ }
+ writePS("] sc\n");
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ if (state->getFillColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
+ color.c[0] = gfxColorComp1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) ck\n",
+ colToDbl(state->getFillColor()->c[0]),
+ colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName());
+ addCustomColor(sepCS);
+ } else {
+ state->getFillCMYK(&cmyk);
+ c = colToDbl(cmyk.c);
+ m = colToDbl(cmyk.m);
+ y = colToDbl(cmyk.y);
+ k = colToDbl(cmyk.k);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
+ addProcessColor(c, m, y, k);
+ }
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::updateStrokeColor(GfxState *state) {
+ GfxColor color;
+ GfxColor *colorPtr;
+ GfxGray gray;
+ GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
+ double c, m, y, k;
+ int i;
+
+ if (inUncoloredPattern) {
+ return;
+ }
+ switch (level) {
+ case psLevel1:
+ state->getStrokeGray(&gray);
+ writePSFmt("{0:.4g} G\n", colToDbl(gray));
+ break;
+ case psLevel1Sep:
+ state->getStrokeCMYK(&cmyk);
+ c = colToDbl(cmyk.c);
+ m = colToDbl(cmyk.m);
+ y = colToDbl(cmyk.y);
+ k = colToDbl(cmyk.k);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
+ addProcessColor(c, m, y, k);
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getStrokeColorSpace()->getMode() != csPattern) {
+ colorPtr = state->getStrokeColor();
+ writePS("[");
+ for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
+ }
+ writePS("] SC\n");
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ if (state->getStrokeColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
+ color.c[0] = gfxColorComp1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) CK\n",
+ colToDbl(state->getStrokeColor()->c[0]),
+ colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName());
+ addCustomColor(sepCS);
+ } else {
+ state->getStrokeCMYK(&cmyk);
+ c = colToDbl(cmyk.c);
+ m = colToDbl(cmyk.m);
+ y = colToDbl(cmyk.y);
+ k = colToDbl(cmyk.k);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
+ addProcessColor(c, m, y, k);
+ }
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
+ if (c > 0) {
+ processColors |= psProcessCyan;
+ }
+ if (m > 0) {
+ processColors |= psProcessMagenta;
+ }
+ if (y > 0) {
+ processColors |= psProcessYellow;
+ }
+ if (k > 0) {
+ processColors |= psProcessBlack;
+ }
+}
+
+void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
+ PSOutCustomColor *cc;
+ GfxColor color;
+ GfxCMYK cmyk;
+
+ if (!sepCS->getName()->cmp("Black")) {
+ processColors |= psProcessBlack;
+ return;
+ }
+ if (!sepCS->getName()->cmp("Cyan")) {
+ processColors |= psProcessCyan;
+ return;
+ }
+ if (!sepCS->getName()->cmp("Yellow")) {
+ processColors |= psProcessYellow;
+ return;
+ }
+ if (!sepCS->getName()->cmp("Magenta")) {
+ processColors |= psProcessMagenta;
+ return;
+ }
+ if (!sepCS->getName()->cmp("All"))
+ return;
+ if (!sepCS->getName()->cmp("None"))
+ return;
+ for (cc = customColors; cc; cc = cc->next) {
+ if (!cc->name->cmp(sepCS->getName())) {
+ return;
+ }
+ }
+ color.c[0] = gfxColorComp1;
+ sepCS->getCMYK(&color, &cmyk);
+ cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName()->copy());
+ cc->next = customColors;
+ customColors = cc;
+}
+
+void PSOutputDev::updateFillOverprint(GfxState *state) {
+ if (level >= psLevel2) {
+ writePSFmt("{0:s} op\n", state->getFillOverprint() ? "true" : "false");
+ }
+}
+
+void PSOutputDev::updateStrokeOverprint(GfxState *state) {
+ if (level >= psLevel2) {
+ writePSFmt("{0:s} OP\n", state->getStrokeOverprint() ? "true" : "false");
+ }
+}
+
+void PSOutputDev::updateOverprintMode(GfxState *state) {
+ if (level >= psLevel3) {
+ writePSFmt("{0:s} opm\n", state->getOverprintMode() ? "true" : "false");
+ }
+}
+
+void PSOutputDev::updateTransfer(GfxState *state) {
+ Function **funcs;
+ int i;
+
+ funcs = state->getTransfer();
+ if (funcs[0] && funcs[1] && funcs[2] && funcs[3]) {
+ if (level >= psLevel2) {
+ for (i = 0; i < 4; ++i) {
+ cvtFunction(funcs[i]);
+ }
+ writePS("setcolortransfer\n");
+ } else {
+ cvtFunction(funcs[3]);
+ writePS("settransfer\n");
+ }
+ } else if (funcs[0]) {
+ cvtFunction(funcs[0]);
+ writePS("settransfer\n");
+ } else {
+ writePS("{} settransfer\n");
+ }
+}
+
+void PSOutputDev::updateFont(GfxState *state) {
+ if (state->getFont()) {
+ writePSFmt("/F{0:d}_{1:d} {2:.6g} Tf\n",
+ state->getFont()->getID()->num, state->getFont()->getID()->gen,
+ fabs(state->getFontSize()) < 0.0001 ? 0.0001
+ : state->getFontSize());
+ }
+}
+
+void PSOutputDev::updateTextMat(GfxState *state) {
+ double *mat;
+
+ mat = state->getTextMat();
+ if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) {
+ // avoid a singular (or close-to-singular) matrix
+ writePSFmt("[0.00001 0 0 0.00001 {0:.6g} {1:.6g}] Tm\n", mat[4], mat[5]);
+ } else {
+ writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] Tm\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ }
+}
+
+void PSOutputDev::updateCharSpace(GfxState *state) {
+ writePSFmt("{0:.6g} Tc\n", state->getCharSpace());
+}
+
+void PSOutputDev::updateRender(GfxState *state) {
+ int rm;
+
+ rm = state->getRender();
+ writePSFmt("{0:d} Tr\n", rm);
+ rm &= 3;
+ if (rm != 0 && rm != 3) {
+ t3Cacheable = gFalse;
+ }
+}
+
+void PSOutputDev::updateRise(GfxState *state) {
+ writePSFmt("{0:.6g} Ts\n", state->getRise());
+}
+
+void PSOutputDev::updateWordSpace(GfxState *state) {
+ writePSFmt("{0:.6g} Tw\n", state->getWordSpace());
+}
+
+void PSOutputDev::updateHorizScaling(GfxState *state) {
+ double h;
+
+ h = state->getHorizScaling();
+ if (fabs(h) < 0.01) {
+ h = 0.01;
+ }
+ writePSFmt("{0:.6g} Tz\n", h);
+}
+
+void PSOutputDev::updateTextPos(GfxState *state) {
+ writePSFmt("{0:.6g} {1:.6g} Td\n", state->getLineX(), state->getLineY());
+}
+
+void PSOutputDev::updateTextShift(GfxState *state, double shift) {
+ if (state->getFont()->getWMode()) {
+ writePSFmt("{0:.6g} TJmV\n", shift);
+ } else {
+ writePSFmt("{0:.6g} TJm\n", shift);
+ }
+}
+
+void PSOutputDev::saveTextPos(GfxState *state) {
+ writePS("currentpoint\n");
+}
+
+void PSOutputDev::restoreTextPos(GfxState *state) {
+ writePS("m\n");
+}
+
+void PSOutputDev::stroke(GfxState *state) {
+ doPath(state->getPath());
+ if (inType3Char && t3FillColorOnly) {
+ // if we're construct a cacheable Type 3 glyph, we need to do
+ // everything in the fill color
+ writePS("Sf\n");
+ } else {
+ writePS("S\n");
+ }
+}
+
+void PSOutputDev::fill(GfxState *state) {
+ doPath(state->getPath());
+ writePS("f\n");
+}
+
+void PSOutputDev::eoFill(GfxState *state) {
+ doPath(state->getPath());
+ writePS("f*\n");
+}
+
+GBool PSOutputDev::tilingPatternFillL1(GfxState *state, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep) {
+ PDFRectangle box;
+ Gfx *gfx;
+
+ // define a Type 3 font
+ writePS("8 dict begin\n");
+ writePS("/FontType 3 def\n");
+ writePS("/FontMatrix [1 0 0 1 0 0] def\n");
+ writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ writePS("/Encoding 256 array def\n");
+ writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
+ writePS(" Encoding 120 /x put\n");
+ writePS("/BuildGlyph {\n");
+ writePS(" exch /CharProcs get exch\n");
+ writePS(" 2 copy known not { pop /.notdef } if\n");
+ writePS(" get exec\n");
+ writePS("} bind def\n");
+ writePS("/BuildChar {\n");
+ writePS(" 1 index /Encoding get exch get\n");
+ writePS(" 1 index /BuildGlyph get exec\n");
+ writePS("} bind def\n");
+ writePS("/CharProcs 1 dict def\n");
+ writePS("CharProcs begin\n");
+ box.x1 = bbox[0];
+ box.y1 = bbox[1];
+ box.x2 = bbox[2];
+ box.y2 = bbox[3];
+ gfx = new Gfx(doc, this, resDict, &box, NULL);
+ writePS("/x {\n");
+ if (paintType == 2) {
+ writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n",
+ xStep, bbox[0], bbox[1], bbox[2], bbox[3]);
+ t3FillColorOnly = gTrue;
+ } else
+ {
+ if (x1 - 1 <= x0) {
+ writePS("1 0 setcharwidth\n");
+ } else {
+ writePSFmt("{0:.6g} 0 setcharwidth\n", xStep);
+ }
+ t3FillColorOnly = gFalse;
+ }
+ inType3Char = gTrue;
+ if (paintType == 2) {
+ inUncoloredPattern = gTrue;
+ // ensure any PS procedures that contain sCol or fCol do not change the color
+ writePS("/pdfLastFill true def\n");
+ writePS("/pdfLastStroke true def\n");
+ }
+ ++numTilingPatterns;
+ gfx->display(str);
+ --numTilingPatterns;
+ if (paintType == 2) {
+ inUncoloredPattern = gFalse;
+ // ensure the next PS procedures that uses sCol or fCol will update the color
+ writePS("/pdfLastFill false def\n");
+ writePS("/pdfLastStroke false def\n");
+ }
+ inType3Char = gFalse;
+ writePS("} def\n");
+ delete gfx;
+ writePS("end\n");
+ writePS("currentdict end\n");
+ writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns);
+
+ // draw the tiles
+ writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns);
+ writePS("fCol\n");
+ writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
+ y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1);
+ writePS("grestore\n");
+
+ return gTrue;
+}
+
+GBool PSOutputDev::tilingPatternFillL2(GfxState *state, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep) {
+ PDFRectangle box;
+ Gfx *gfx;
+
+ if (paintType == 2) {
+ // setpattern with PaintType 2 needs the paint color
+ writePS("currentcolor\n");
+ }
+ writePS("<<\n /PatternType 1\n");
+ writePSFmt(" /PaintType {0:d}\n", paintType);
+ writePSFmt(" /TilingType {0:d}\n", tilingType);
+ writePSFmt(" /BBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}]\n", bbox[0], bbox[1], bbox[2], bbox[3]);
+ writePSFmt(" /XStep {0:.6g}\n", xStep);
+ writePSFmt(" /YStep {0:.6g}\n", yStep);
+ writePS(" /PaintProc { \n");
+ box.x1 = bbox[0];
+ box.y1 = bbox[1];
+ box.x2 = bbox[2];
+ box.y2 = bbox[3];
+ gfx = new Gfx(doc, this, resDict, &box, NULL);
+ inType3Char = gTrue;
+ if (paintType == 2) {
+ inUncoloredPattern = gTrue;
+ // ensure any PS procedures that contain sCol or fCol do not change the color
+ writePS("/pdfLastFill true def\n");
+ writePS("/pdfLastStroke true def\n");
+ }
+ gfx->display(str);
+ if (paintType == 2) {
+ inUncoloredPattern = gFalse;
+ // ensure the next PS procedures that uses sCol or fCol will update the color
+ writePS("/pdfLastFill false def\n");
+ writePS("/pdfLastStroke false def\n");
+ }
+ inType3Char = gFalse;
+ delete gfx;
+ writePS(" }\n");
+ writePS(">>\n");
+ writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}]\n", mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ writePS("makepattern setpattern\n");
+ writePS("clippath fill\n"); // Gfx sets up a clip before calling out->tilingPatternFill()
+
+ return gTrue;
+}
+
+GBool PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep) {
+ if (x1 - x0 == 1 && y1 - y0 == 1) {
+ // Don't need to use patterns if only one instance of the pattern is used
+ PDFRectangle box;
+ Gfx *gfx;
+ double x, y, tx, ty;
+
+ x = x0 * xStep;
+ y = y0 * yStep;
+ tx = x * mat[0] + y * mat[2] + mat[4];
+ ty = x * mat[1] + y * mat[3] + mat[5];
+ box.x1 = bbox[0];
+ box.y1 = bbox[1];
+ box.x2 = bbox[2];
+ box.y2 = bbox[3];
+ gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gfxA->getXRef());
+ writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] cm\n", mat[0], mat[1], mat[2], mat[3], tx, ty);
+ inType3Char = gTrue;
+ gfx->display(str);
+ inType3Char = gFalse;
+ delete gfx;
+ return gTrue;
+ }
+
+ if (level == psLevel1 || level == psLevel1Sep) {
+ return tilingPatternFillL1(state, cat, str, pmat, paintType, tilingType, resDict,
+ mat, bbox, x0, y0, x1, y1, xStep, yStep);
+ } else {
+ return tilingPatternFillL2(state, cat, str, pmat, paintType, tilingType, resDict,
+ mat, bbox, x0, y0, x1, y1, xStep, yStep);
+ }
+}
+
+GBool PSOutputDev::functionShadedFill(GfxState *state,
+ GfxFunctionShading *shading) {
+ double x0, y0, x1, y1;
+ double *mat;
+ int i;
+
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
+ return gFalse;
+ }
+ processColors |= psProcessCMYK;
+ }
+
+ shading->getDomain(&x0, &y0, &x1, &y1);
+ mat = shading->getMatrix();
+ writePSFmt("/mat [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
+ if (shading->getNFuncs() == 1) {
+ writePS("/func ");
+ cvtFunction(shading->getFunc(0));
+ writePS("def\n");
+ } else {
+ writePS("/func {\n");
+ for (i = 0; i < shading->getNFuncs(); ++i) {
+ if (i < shading->getNFuncs() - 1) {
+ writePS("2 copy\n");
+ }
+ cvtFunction(shading->getFunc(i));
+ writePS("exec\n");
+ if (i < shading->getNFuncs() - 1) {
+ writePS("3 1 roll\n");
+ }
+ }
+ writePS("} def\n");
+ }
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} 0 funcSH\n", x0, y0, x1, y1);
+
+ return gTrue;
+}
+
+GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, x1, y1, dx, dy, mul;
+ double tMin, tMax, t, t0, t1;
+ int i;
+
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
+ return gFalse;
+ }
+ processColors |= psProcessCMYK;
+ }
+
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ // compute min and max t values, based on the four corners of the
+ // clip region bbox
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ if (fabs(dx) < 0.01 && fabs(dy) < 0.01) {
+ return gTrue;
+ } else {
+ mul = 1 / (dx * dx + dy * dy);
+ tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
+ t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ if (tMin < 0 && !shading->getExtend0()) {
+ tMin = 0;
+ }
+ if (tMax > 1 && !shading->getExtend1()) {
+ tMax = 1;
+ }
+ }
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // generate the PS code
+ writePSFmt("/t0 {0:.6g} def\n", t0);
+ writePSFmt("/t1 {0:.6g} def\n", t1);
+ writePSFmt("/dt {0:.6g} def\n", t1 - t0);
+ writePSFmt("/x0 {0:.6g} def\n", x0);
+ writePSFmt("/y0 {0:.6g} def\n", y0);
+ writePSFmt("/dx {0:.6g} def\n", x1 - x0);
+ writePSFmt("/x1 {0:.6g} def\n", x1);
+ writePSFmt("/y1 {0:.6g} def\n", y1);
+ writePSFmt("/dy {0:.6g} def\n", y1 - y0);
+ writePSFmt("/xMin {0:.6g} def\n", xMin);
+ writePSFmt("/yMin {0:.6g} def\n", yMin);
+ writePSFmt("/xMax {0:.6g} def\n", xMax);
+ writePSFmt("/yMax {0:.6g} def\n", yMax);
+ writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
+ if (shading->getNFuncs() == 1) {
+ writePS("/func ");
+ cvtFunction(shading->getFunc(0));
+ writePS("def\n");
+ } else {
+ writePS("/func {\n");
+ for (i = 0; i < shading->getNFuncs(); ++i) {
+ if (i < shading->getNFuncs() - 1) {
+ writePS("dup\n");
+ }
+ cvtFunction(shading->getFunc(i));
+ writePS("exec\n");
+ if (i < shading->getNFuncs() - 1) {
+ writePS("exch\n");
+ }
+ }
+ writePS("} def\n");
+ }
+ writePSFmt("{0:.6g} {1:.6g} 0 axialSH\n", tMin, tMax);
+
+ return gTrue;
+}
+
+GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, r0, x1, y1, r1, t0, t1;
+ double xa, ya, ra;
+ double sMin, sMax, h, ta;
+ double sLeft, sRight, sTop, sBottom, sZero, sDiag;
+ GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
+ GBool haveSMin, haveSMax;
+ double theta, alpha, a1, a2;
+ GBool enclosed;
+ int i;
+
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
+ return gFalse;
+ }
+ processColors |= psProcessCMYK;
+ }
+
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // Compute the point at which r(s) = 0; check for the enclosed
+ // circles case; and compute the angles for the tangent lines.
+ // Compute the point at which r(s) = 0; check for the enclosed
+ // circles case; and compute the angles for the tangent lines.
+ h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
+ if (h == 0) {
+ enclosed = gTrue;
+ theta = 0; // make gcc happy
+ } else if (r1 - r0 == 0) {
+ enclosed = gFalse;
+ theta = 0;
+ } else if (fabs(r1 - r0) >= h) {
+ enclosed = gTrue;
+ theta = 0; // make gcc happy
+ } else {
+ enclosed = gFalse;
+ theta = asin((r1 - r0) / h);
+ }
+ if (enclosed) {
+ a1 = 0;
+ a2 = 360;
+ } else {
+ alpha = atan2(y1 - y0, x1 - x0);
+ a1 = (180 / M_PI) * (alpha + theta) + 90;
+ a2 = (180 / M_PI) * (alpha - theta) - 90;
+ while (a2 < a1) {
+ a2 += 360;
+ }
+ }
+
+ // compute the (possibly extended) s range
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ if (enclosed) {
+ sMin = 0;
+ sMax = 1;
+ } else {
+ // solve x(sLeft) + r(sLeft) = xMin
+ if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) {
+ sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+ } else {
+ sLeft = 0; // make gcc happy
+ }
+ // solve x(sRight) - r(sRight) = xMax
+ if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) {
+ sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+ } else {
+ sRight = 0; // make gcc happy
+ }
+ // solve y(sBottom) + r(sBottom) = yMin
+ if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) {
+ sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+ } else {
+ sBottom = 0; // make gcc happy
+ }
+ // solve y(sTop) - r(sTop) = yMax
+ if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) {
+ sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+ } else {
+ sTop = 0; // make gcc happy
+ }
+ // solve r(sZero) = 0
+ if ((haveSZero = fabs(r1 - r0) > 0.000001)) {
+ sZero = -r0 / (r1 - r0);
+ } else {
+ sZero = 0; // make gcc happy
+ }
+ // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2)
+ if (haveSZero) {
+ sDiag = (sqrt((xMax - xMin) * (xMax - xMin) +
+ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
+ } else {
+ sDiag = 0; // make gcc happy
+ }
+ // compute sMin
+ if (shading->getExtend0()) {
+ sMin = 0;
+ haveSMin = gFalse;
+ if (x0 < x1 && haveSLeft && sLeft < 0) {
+ sMin = sLeft;
+ haveSMin = gTrue;
+ } else if (x0 > x1 && haveSRight && sRight < 0) {
+ sMin = sRight;
+ haveSMin = gTrue;
+ }
+ if (y0 < y1 && haveSBottom && sBottom < 0) {
+ if (!haveSMin || sBottom > sMin) {
+ sMin = sBottom;
+ haveSMin = gTrue;
+ }
+ } else if (y0 > y1 && haveSTop && sTop < 0) {
+ if (!haveSMin || sTop > sMin) {
+ sMin = sTop;
+ haveSMin = gTrue;
+ }
+ }
+ if (haveSZero && sZero < 0) {
+ if (!haveSMin || sZero > sMin) {
+ sMin = sZero;
+ }
+ }
+ } else {
+ sMin = 0;
+ }
+ // compute sMax
+ if (shading->getExtend1()) {
+ sMax = 1;
+ haveSMax = gFalse;
+ if (x1 < x0 && haveSLeft && sLeft > 1) {
+ sMax = sLeft;
+ haveSMax = gTrue;
+ } else if (x1 > x0 && haveSRight && sRight > 1) {
+ sMax = sRight;
+ haveSMax = gTrue;
+ }
+ if (y1 < y0 && haveSBottom && sBottom > 1) {
+ if (!haveSMax || sBottom < sMax) {
+ sMax = sBottom;
+ haveSMax = gTrue;
+ }
+ } else if (y1 > y0 && haveSTop && sTop > 1) {
+ if (!haveSMax || sTop < sMax) {
+ sMax = sTop;
+ haveSMax = gTrue;
+ }
+ }
+ if (haveSZero && sDiag > 1) {
+ if (!haveSMax || sDiag < sMax) {
+ sMax = sDiag;
+ }
+ }
+ } else {
+ sMax = 1;
+ }
+ }
+
+ // generate the PS code
+ writePSFmt("/x0 {0:.6g} def\n", x0);
+ writePSFmt("/x1 {0:.6g} def\n", x1);
+ writePSFmt("/dx {0:.6g} def\n", x1 - x0);
+ writePSFmt("/y0 {0:.6g} def\n", y0);
+ writePSFmt("/y1 {0:.6g} def\n", y1);
+ writePSFmt("/dy {0:.6g} def\n", y1 - y0);
+ writePSFmt("/r0 {0:.6g} def\n", r0);
+ writePSFmt("/r1 {0:.6g} def\n", r1);
+ writePSFmt("/dr {0:.6g} def\n", r1 - r0);
+ writePSFmt("/t0 {0:.6g} def\n", t0);
+ writePSFmt("/t1 {0:.6g} def\n", t1);
+ writePSFmt("/dt {0:.6g} def\n", t1 - t0);
+ writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
+ writePSFmt("/encl {0:s} def\n", enclosed ? "true" : "false");
+ writePSFmt("/a1 {0:.6g} def\n", a1);
+ writePSFmt("/a2 {0:.6g} def\n", a2);
+ if (shading->getNFuncs() == 1) {
+ writePS("/func ");
+ cvtFunction(shading->getFunc(0));
+ writePS("def\n");
+ } else {
+ writePS("/func {\n");
+ for (i = 0; i < shading->getNFuncs(); ++i) {
+ if (i < shading->getNFuncs() - 1) {
+ writePS("dup\n");
+ }
+ cvtFunction(shading->getFunc(i));
+ writePS("exec\n");
+ if (i < shading->getNFuncs() - 1) {
+ writePS("exch\n");
+ }
+ }
+ writePS("} def\n");
+ }
+ writePSFmt("{0:.6g} {1:.6g} 0 radialSH\n", sMin, sMax);
+
+ // extend the 'enclosed' case
+ if (enclosed) {
+ // extend the smaller circle
+ if ((shading->getExtend0() && r0 <= r1) ||
+ (shading->getExtend1() && r1 < r0)) {
+ if (r0 <= r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ writePSFmt("{0:.6g} radialCol aload pop k\n", ta);
+ } else {
+ writePSFmt("{0:.6g} radialCol sc\n", ta);
+ }
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h f*\n", xa, ya, ra);
+ }
+
+ // extend the larger circle
+ if ((shading->getExtend0() && r0 > r1) ||
+ (shading->getExtend1() && r1 >= r0)) {
+ if (r0 > r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ writePSFmt("{0:.6g} radialCol aload pop k\n", ta);
+ } else {
+ writePSFmt("{0:.6g} radialCol sc\n", ta);
+ }
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h\n", xa, ya, ra);
+ writePSFmt("{0:.6g} {1:.6g} m {2:.6g} {3:.6g} l {4:.6g} {5:.6g} l {6:.6g} {7:.6g} l h f*\n",
+ xMin, yMin, xMin, yMax, xMax, yMax, xMax, yMin);
+ }
+ }
+
+ return gTrue;
+}
+
+void PSOutputDev::clip(GfxState *state) {
+ doPath(state->getPath());
+ writePS("W\n");
+}
+
+void PSOutputDev::eoClip(GfxState *state) {
+ doPath(state->getPath());
+ writePS("W*\n");
+}
+
+void PSOutputDev::clipToStrokePath(GfxState *state) {
+ doPath(state->getPath());
+ writePS("Ws\n");
+}
+
+void PSOutputDev::doPath(GfxPath *path) {
+ GfxSubpath *subpath;
+ double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
+ int n, m, i, j;
+
+ n = path->getNumSubpaths();
+
+ if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
+ subpath = path->getSubpath(0);
+ x0 = subpath->getX(0);
+ y0 = subpath->getY(0);
+ x4 = subpath->getX(4);
+ y4 = subpath->getY(4);
+ if (x4 == x0 && y4 == y0) {
+ x1 = subpath->getX(1);
+ y1 = subpath->getY(1);
+ x2 = subpath->getX(2);
+ y2 = subpath->getY(2);
+ x3 = subpath->getX(3);
+ y3 = subpath->getY(3);
+ if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
+ x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
+ fabs(x2 - x0), fabs(y1 - y0));
+ return;
+ } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
+ x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
+ fabs(x1 - x0), fabs(y2 - y0));
+ return;
+ }
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ subpath = path->getSubpath(i);
+ m = subpath->getNumPoints();
+ writePSFmt("{0:.6g} {1:.6g} m\n", subpath->getX(0), subpath->getY(0));
+ j = 1;
+ while (j < m) {
+ if (subpath->getCurve(j)) {
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} c\n",
+ subpath->getX(j), subpath->getY(j),
+ subpath->getX(j+1), subpath->getY(j+1),
+ subpath->getX(j+2), subpath->getY(j+2));
+ j += 3;
+ } else {
+ writePSFmt("{0:.6g} {1:.6g} l\n", subpath->getX(j), subpath->getY(j));
+ ++j;
+ }
+ }
+ if (subpath->isClosed()) {
+ writePS("h\n");
+ }
+ }
+}
+
+void PSOutputDev::drawString(GfxState *state, GooString *s) {
+ GfxFont *font;
+ int wMode;
+ int *codeToGID;
+ GooString *s2;
+ double dx, dy, originX, originY;
+ char *p;
+ UnicodeMap *uMap;
+ CharCode code;
+ Unicode *u;
+ char buf[8];
+ double *dxdy;
+ int dxdySize, len, nChars, uLen, n, m, i, j;
+
+ // for pdftohtml, output PS without text
+ if( displayText == gFalse )
+ return;
+
+ // check for invisible text -- this is used by Acrobat Capture
+ if (state->getRender() == 3) {
+ return;
+ }
+
+ // ignore empty strings
+ if (s->getLength() == 0) {
+ return;
+ }
+
+ // get the font
+ if (!(font = state->getFont())) {
+ return;
+ }
+ wMode = font->getWMode();
+
+ // check for a subtitute 16-bit font
+ uMap = NULL;
+ codeToGID = NULL;
+ if (font->isCIDFont()) {
+ for (i = 0; i < font16EncLen; ++i) {
+ if (font->getID()->num == font16Enc[i].fontID.num &&
+ font->getID()->gen == font16Enc[i].fontID.gen) {
+ if (!font16Enc[i].enc) {
+ // font substitution failed, so don't output any text
+ return;
+ }
+ uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
+ break;
+ }
+ }
+
+ // check for a code-to-GID map
+ } else {
+ for (i = 0; i < font8InfoLen; ++i) {
+ if (font->getID()->num == font8Info[i].fontID.num &&
+ font->getID()->gen == font8Info[i].fontID.gen) {
+ codeToGID = font8Info[i].codeToGID;
+ break;
+ }
+ }
+ }
+
+ // compute the positioning (dx, dy) for each char in the string
+ nChars = 0;
+ p = s->getCString();
+ len = s->getLength();
+ s2 = new GooString();
+ dxdySize = font->isCIDFont() ? 8 : s->getLength();
+ dxdy = (double *)gmallocn(2 * dxdySize, sizeof(double));
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ &u, &uLen,
+ &dx, &dy, &originX, &originY);
+ dx *= state->getFontSize();
+ dy *= state->getFontSize();
+ if (wMode) {
+ dy += state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dy += state->getWordSpace();
+ }
+ } else {
+ dx += state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dx += state->getWordSpace();
+ }
+ }
+ dx *= state->getHorizScaling();
+ if (font->isCIDFont()) {
+ if (uMap) {
+ if (nChars + uLen > dxdySize) {
+ do {
+ dxdySize *= 2;
+ } while (nChars + uLen > dxdySize);
+ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double));
+ }
+ for (i = 0; i < uLen; ++i) {
+ m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
+ for (j = 0; j < m; ++j) {
+ s2->append(buf[j]);
+ }
+ //~ this really needs to get the number of chars in the target
+ //~ encoding - which may be more than the number of Unicode
+ //~ chars
+ dxdy[2 * nChars] = dx;
+ dxdy[2 * nChars + 1] = dy;
+ ++nChars;
+ }
+ } else {
+ if (nChars + 1 > dxdySize) {
+ dxdySize *= 2;
+ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double));
+ }
+ s2->append((char)((code >> 8) & 0xff));
+ s2->append((char)(code & 0xff));
+ dxdy[2 * nChars] = dx;
+ dxdy[2 * nChars + 1] = dy;
+ ++nChars;
+ }
+ } else {
+ if (!codeToGID || codeToGID[code] >= 0) {
+ s2->append((char)code);
+ dxdy[2 * nChars] = dx;
+ dxdy[2 * nChars + 1] = dy;
+ ++nChars;
+ }
+ }
+ p += n;
+ len -= n;
+ }
+ if (uMap) {
+ uMap->decRefCnt();
+ }
+
+ if (nChars > 0) {
+ writePSString(s2);
+ writePS("\n[");
+ for (i = 0; i < 2 * nChars; ++i) {
+ if (i > 0) {
+ writePS("\n");
+ }
+ writePSFmt("{0:.6g}", dxdy[i]);
+ }
+ writePS("] Tj\n");
+ }
+ gfree(dxdy);
+ delete s2;
+
+ if (state->getRender() & 4) {
+ haveTextClip = gTrue;
+ }
+}
+
+void PSOutputDev::beginTextObject(GfxState *state) {
+}
+
+void PSOutputDev::endTextObject(GfxState *state) {
+ if (haveTextClip) {
+ writePS("Tclip\n");
+ haveTextClip = gFalse;
+ }
+}
+
+void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg) {
+ int len;
+
+ len = height * ((width + 7) / 8);
+ switch (level) {
+ case psLevel1:
+ case psLevel1Sep:
+ doImageL1(ref, NULL, invert, inlineImg, str, width, height, len,
+ NULL, NULL, 0, 0, gFalse);
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ doImageL2(ref, NULL, invert, inlineImg, str, width, height, len,
+ NULL, NULL, 0, 0, gFalse);
+ break;
+ case psLevel3:
+ case psLevel3Sep:
+ doImageL3(ref, NULL, invert, inlineImg, str, width, height, len,
+ NULL, NULL, 0, 0, gFalse);
+ break;
+ }
+}
+
+void PSOutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix) {
+ if (level != psLevel1 && level != psLevel1Sep) {
+ maskToClippingPath(str, width, height, invert);
+ }
+}
+
+void PSOutputDev::unsetSoftMaskFromImageMask(GfxState * state, double *baseMatrix) {
+ if (level != psLevel1 && level != psLevel1Sep) {
+ writePS("pdfImClipEnd\n");
+ }
+}
+
+void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg) {
+ int len;
+
+ len = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ switch (level) {
+ case psLevel1:
+ doImageL1(ref, colorMap, gFalse, inlineImg, str,
+ width, height, len, maskColors, NULL, 0, 0, gFalse);
+ break;
+ case psLevel1Sep:
+ //~ handle indexed, separation, ... color spaces
+ doImageL1Sep(ref, colorMap, gFalse, inlineImg, str,
+ width, height, len, maskColors, NULL, 0, 0, gFalse);
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ doImageL2(ref, colorMap, gFalse, inlineImg, str,
+ width, height, len, maskColors, NULL, 0, 0, gFalse);
+ break;
+ case psLevel3:
+ case psLevel3Sep:
+ doImageL3(ref, colorMap, gFalse, inlineImg, str,
+ width, height, len, maskColors, NULL, 0, 0, gFalse);
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GBool maskInvert, GBool maskInterpolate) {
+ int len;
+
+ len = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ switch (level) {
+ case psLevel1:
+ doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len,
+ NULL, maskStr, maskWidth, maskHeight, maskInvert);
+ break;
+ case psLevel1Sep:
+ //~ handle indexed, separation, ... color spaces
+ doImageL1Sep(ref, colorMap, gFalse, gFalse, str, width, height, len,
+ NULL, maskStr, maskWidth, maskHeight, maskInvert);
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len,
+ NULL, maskStr, maskWidth, maskHeight, maskInvert);
+ break;
+ case psLevel3:
+ case psLevel3Sep:
+ doImageL3(ref, colorMap, gFalse, gFalse, str, width, height, len,
+ NULL, maskStr, maskWidth, maskHeight, maskInvert);
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert) {
+ ImageStream *imgStr;
+ Guchar pixBuf[gfxColorMaxComps];
+ GfxGray gray;
+ int col, x, y, c, i;
+ char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
+ Guchar digit, grayValue;
+
+ // explicit masking
+ if (maskStr && !(maskColors && colorMap)) {
+ maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
+ }
+
+ if ((inType3Char || preloadImagesForms) && !colorMap) {
+ if (inlineImg) {
+ // create an array
+ str = new FixedLengthEncoder(str, len);
+ str = new ASCIIHexEncoder(str);
+ str->reset();
+ col = 0;
+ writePS("[<");
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == '>' || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ // each line is: "<...data...><eol>"
+ // so max data length = 255 - 4 = 251
+ // but make it 240 just to be safe
+ // chunks are 2 bytes each, so we need to stop on an even col number
+ if (col == 240) {
+ writePS(">\n<");
+ col = 0;
+ }
+ } while (c != '>' && c != EOF);
+ writePS(">]\n");
+ writePS("0\n");
+ str->close();
+ delete str;
+ } else {
+ // make sure the image is setup, it sometimes is not like on bug #17645
+ setupImage(ref->getRef(), str, gFalse);
+ // set up to use the array already created by setupImages()
+ writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
+ }
+ }
+
+ // image/imagemask command
+ if ((inType3Char || preloadImagesForms) && !colorMap) {
+ writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1a\n",
+ width, height, invert ? "true" : "false",
+ width, -height, height);
+ } else if (colorMap) {
+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1{5:s}\n",
+ width, height,
+ width, -height, height,
+ useBinary ? "Bin" : "");
+ } else {
+ writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1{6:s}\n",
+ width, height, invert ? "true" : "false",
+ width, -height, height,
+ useBinary ? "Bin" : "");
+ }
+
+ // image data
+ if (!((inType3Char || preloadImagesForms) && !colorMap)) {
+
+ if (colorMap) {
+
+ // set up to process the data stream
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+ // process the data stream
+ i = 0;
+ for (y = 0; y < height; ++y) {
+
+ // write the line
+ for (x = 0; x < width; ++x) {
+ imgStr->getPixel(pixBuf);
+ colorMap->getGray(pixBuf, &gray);
+ grayValue = colToByte(gray);
+ if (useBinary) {
+ hexBuf[i++] = grayValue;
+ } else {
+ digit = grayValue / 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ digit = grayValue % 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ }
+ if (i >= 64) {
+ if (!useBinary) {
+ hexBuf[i++] = '\n';
+ }
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ if (i != 0) {
+ if (!useBinary) {
+ hexBuf[i++] = '\n';
+ }
+ writePSBuf(hexBuf, i);
+ }
+ str->close();
+ delete imgStr;
+
+ // imagemask
+ } else {
+ str->reset();
+ i = 0;
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; x += 8) {
+ grayValue = str->getChar();
+ if (useBinary) {
+ hexBuf[i++] = grayValue;
+ } else {
+ digit = grayValue / 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ digit = grayValue % 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
+ }
+ if (i >= 64) {
+ if (!useBinary) {
+ hexBuf[i++] = '\n';
+ }
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ if (i != 0) {
+ if (!useBinary) {
+ hexBuf[i++] = '\n';
+ }
+ writePSBuf(hexBuf, i);
+ }
+ str->close();
+ }
+ }
+
+ if (maskStr && !(maskColors && colorMap)) {
+ writePS("pdfImClipEnd\n");
+ }
+}
+
+void PSOutputDev::doImageL1Sep(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert) {
+ ImageStream *imgStr;
+ Guchar *lineBuf;
+ Guchar pixBuf[gfxColorMaxComps];
+ GfxCMYK cmyk;
+ int x, y, i, comp;
+ GBool checkProcessColor;
+ char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
+ Guchar digit;
+
+ // explicit masking
+ if (maskStr && !(maskColors && colorMap)) {
+ maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
+ }
+
+ // width, height, matrix, bits per component
+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep{5:s}\n",
+ width, height,
+ width, -height, height,
+ useBinary ? "Bin" : "");
+
+ // allocate a line buffer
+ lineBuf = (Guchar *)gmallocn(width, 4);
+
+ // set up to process the data stream
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+ // process the data stream
+ checkProcessColor = gTrue;
+ i = 0;
+ for (y = 0; y < height; ++y) {
+
+ // read the line
+ if (checkProcessColor) {
+ checkProcessColor = (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0);
+ }
+ if (checkProcessColor) {
+ for (x = 0; x < width; ++x) {
+ imgStr->getPixel(pixBuf);
+ colorMap->getCMYK(pixBuf, &cmyk);
+ lineBuf[4*x+0] = colToByte(cmyk.c);
+ lineBuf[4*x+1] = colToByte(cmyk.m);
+ lineBuf[4*x+2] = colToByte(cmyk.y);
+ lineBuf[4*x+3] = colToByte(cmyk.k);
+ addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k));
+ }
+ } else {
+ for (x = 0; x < width; ++x) {
+ imgStr->getPixel(pixBuf);
+ colorMap->getCMYK(pixBuf, &cmyk);
+ lineBuf[4*x+0] = colToByte(cmyk.c);
+ lineBuf[4*x+1] = colToByte(cmyk.m);
+ lineBuf[4*x+2] = colToByte(cmyk.y);
+ lineBuf[4*x+3] = colToByte(cmyk.k);
+ }
+ }
+
+ // write one line of each color component
+ if (useBinary) {
+ for (comp = 0; comp < 4; ++comp) {
+ for (x = 0; x < width; ++x) {
+ hexBuf[i++] = lineBuf[4*x + comp];
+ if (i >= 64) {
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ } else {
+ for (comp = 0; comp < 4; ++comp) {
+ for (x = 0; x < width; ++x) {
+ digit = lineBuf[4*x + comp] / 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0');
+ digit = lineBuf[4*x + comp] % 16;
+ hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0');
+ if (i >= 64) {
+ hexBuf[i++] = '\n';
+ writePSBuf(hexBuf, i);
+ i = 0;
+ }
+ }
+ }
+ }
+ }
+
+ if (i != 0) {
+ if (!useBinary) {
+ hexBuf[i++] = '\n';
+ }
+ writePSBuf(hexBuf, i);
+ }
+
+ str->close();
+ delete imgStr;
+ gfree(lineBuf);
+
+ if (maskStr && !(maskColors && colorMap)) {
+ writePS("pdfImClipEnd\n");
+ }
+}
+
+void PSOutputDev::maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) {
+ ImageStream *imgStr;
+ Guchar *line;
+ PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
+ int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
+ GBool emitRect, addRect, extendRect;
+ int i, x0, x1, y, maskXor;
+
+ imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
+ imgStr->reset();
+ rects0Len = rects1Len = rectsOutLen = 0;
+ rectsSize = rectsOutSize = 64;
+ rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, sizeof(PSOutImgClipRect));
+ maskXor = maskInvert ? 1 : 0;
+ for (y = 0; y < maskHeight; ++y) {
+ if (!(line = imgStr->getLine())) {
+ break;
+ }
+ i = 0;
+ rects1Len = 0;
+ for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
+ for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
+ while (x0 < maskWidth || i < rects0Len) {
+ emitRect = addRect = extendRect = gFalse;
+ if (x0 >= maskWidth) {
+ emitRect = gTrue;
+ } else if (i >= rects0Len) {
+ addRect = gTrue;
+ } else if (rects0[i].x0 < x0) {
+ emitRect = gTrue;
+ } else if (x0 < rects0[i].x0) {
+ addRect = gTrue;
+ } else if (rects0[i].x1 == x1) {
+ extendRect = gTrue;
+ } else {
+ emitRect = addRect = gTrue;
+ }
+ if (emitRect) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
+ rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ ++i;
+ }
+ if (addRect || extendRect) {
+ if (rects1Len == rectsSize) {
+ rectsSize *= 2;
+ rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, sizeof(PSOutImgClipRect));
+ }
+ rects1[rects1Len].x0 = x0;
+ rects1[rects1Len].x1 = x1;
+ if (addRect) {
+ rects1[rects1Len].y0 = y;
+ }
+ if (extendRect) {
+ rects1[rects1Len].y0 = rects0[i].y0;
+ ++i;
+ }
+ ++rects1Len;
+ for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
+ for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
+ }
+ }
+ rectsTmp = rects0;
+ rects0 = rects1;
+ rects1 = rectsTmp;
+ i = rects0Len;
+ rects0Len = rects1Len;
+ rects1Len = i;
+ }
+ for (i = 0; i < rects0Len; ++i) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
+ rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ }
+ if (rectsOutLen < 65536/4) {
+ writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
+ for (i = 0; i < rectsOutLen; ++i) {
+ writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
+ rectsOut[i].x0, rectsOut[i].y0,
+ rectsOut[i].x1 - rectsOut[i].x0,
+ rectsOut[i].y1 - rectsOut[i].y0);
+ }
+ writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight);
+ } else {
+ // would be over the limit of array size.
+ // make each rectangle path and clip.
+ writePS("gsave newpath\n");
+ for (i = 0; i < rectsOutLen; ++i) {
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
+ ((double)rectsOut[i].x0)/maskWidth,
+ ((double)rectsOut[i].y0)/maskHeight,
+ ((double)(rectsOut[i].x1 - rectsOut[i].x0))/maskWidth,
+ ((double)(rectsOut[i].y1 - rectsOut[i].y0))/maskHeight);
+ }
+ writePS("clip\n");
+ }
+ gfree(rectsOut);
+ gfree(rects0);
+ gfree(rects1);
+ delete imgStr;
+ maskStr->close();
+}
+
+void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert) {
+ Stream *str2;
+ ImageStream *imgStr;
+ Guchar *line;
+ PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
+ int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
+ GBool emitRect, addRect, extendRect;
+ GooString *s;
+ int n, numComps;
+ GBool useRLE, useASCII, useCompressed;
+ GfxSeparationColorSpace *sepCS;
+ GfxColor color;
+ GfxCMYK cmyk;
+ int c;
+ int col, i, j, x0, x1, y;
+ char dataBuf[4096];
+
+ rectsOutLen = 0;
+
+ // color key masking
+ if (maskColors && colorMap && !inlineImg) {
+ // can't read the stream twice for inline images -- but masking
+ // isn't allowed with inline images anyway
+ numComps = colorMap->getNumPixelComps();
+ imgStr = new ImageStream(str, width, numComps, colorMap->getBits());
+ imgStr->reset();
+ rects0Len = rects1Len = 0;
+ rectsSize = rectsOutSize = 64;
+ rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ for (y = 0; y < height; ++y) {
+ if (!(line = imgStr->getLine())) {
+ break;
+ }
+ i = 0;
+ rects1Len = 0;
+ for (x0 = 0; x0 < width; ++x0) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x0*numComps+j] < maskColors[2*j] ||
+ line[x0*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j < numComps) {
+ break;
+ }
+ }
+ for (x1 = x0; x1 < width; ++x1) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x1*numComps+j] < maskColors[2*j] ||
+ line[x1*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ break;
+ }
+ }
+ while (x0 < width || i < rects0Len) {
+ emitRect = addRect = extendRect = gFalse;
+ if (x0 >= width) {
+ emitRect = gTrue;
+ } else if (i >= rects0Len) {
+ addRect = gTrue;
+ } else if (rects0[i].x0 < x0) {
+ emitRect = gTrue;
+ } else if (x0 < rects0[i].x0) {
+ addRect = gTrue;
+ } else if (rects0[i].x1 == x1) {
+ extendRect = gTrue;
+ } else {
+ emitRect = addRect = gTrue;
+ }
+ if (emitRect) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = height - y - 1;
+ rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ ++i;
+ }
+ if (addRect || extendRect) {
+ if (rects1Len == rectsSize) {
+ rectsSize *= 2;
+ rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
+ sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rects1[rects1Len].x0 = x0;
+ rects1[rects1Len].x1 = x1;
+ if (addRect) {
+ rects1[rects1Len].y0 = y;
+ }
+ if (extendRect) {
+ rects1[rects1Len].y0 = rects0[i].y0;
+ ++i;
+ }
+ ++rects1Len;
+ for (x0 = x1; x0 < width; ++x0) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x0*numComps+j] < maskColors[2*j] ||
+ line[x0*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j < numComps) {
+ break;
+ }
+ }
+ for (x1 = x0; x1 < width; ++x1) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x1*numComps+j] < maskColors[2*j] ||
+ line[x1*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ break;
+ }
+ }
+ }
+ }
+ rectsTmp = rects0;
+ rects0 = rects1;
+ rects1 = rectsTmp;
+ i = rects0Len;
+ rects0Len = rects1Len;
+ rects1Len = i;
+ }
+ for (i = 0; i < rects0Len; ++i) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = height - y - 1;
+ rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ }
+ if (rectsOutLen < 65536/4) {
+ writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
+ for (i = 0; i < rectsOutLen; ++i) {
+ writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
+ rectsOut[i].x0, rectsOut[i].y0,
+ rectsOut[i].x1 - rectsOut[i].x0,
+ rectsOut[i].y1 - rectsOut[i].y0);
+ }
+ writePSFmt("pop {0:d} {1:d} pdfImClip\n", width, height);
+ } else {
+ // would be over the limit of array size.
+ // make each rectangle path and clip.
+ writePS("gsave newpath\n");
+ for (i = 0; i < rectsOutLen; ++i) {
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
+ ((double)rectsOut[i].x0)/width,
+ ((double)rectsOut[i].y0)/height,
+ ((double)(rectsOut[i].x1 - rectsOut[i].x0))/width,
+ ((double)(rectsOut[i].y1 - rectsOut[i].y0))/height);
+ }
+ writePS("clip\n");
+ }
+ gfree(rectsOut);
+ gfree(rects0);
+ gfree(rects1);
+ delete imgStr;
+ str->close();
+
+ // explicit masking
+ } else if (maskStr) {
+ maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
+ }
+
+ // color space
+ if (colorMap) {
+ dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
+ writePS(" setcolorspace\n");
+ }
+
+ // set up the image data
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+ if (inlineImg) {
+ // create an array
+ str2 = new FixedLengthEncoder(str, len);
+ str2 = new RunLengthEncoder(str2);
+ if (useASCIIHex) {
+ str2 = new ASCIIHexEncoder(str2);
+ } else {
+ str2 = new ASCII85Encoder(str2);
+ }
+ str2->reset();
+ col = 0;
+ writePS((char *)(useASCIIHex ? "[<" : "[<~"));
+ do {
+ do {
+ c = str2->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ writePSChar(c);
+ ++col;
+ } else {
+ writePSChar(c);
+ ++col;
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str2->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ }
+ }
+ // each line is: "<~...data...~><eol>"
+ // so max data length = 255 - 6 = 249
+ // chunks are 1 or 5 bytes each, so we have to stop at 245
+ // but make it 240 just to be safe
+ if (col > 240) {
+ writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
+ col = 0;
+ }
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
+ writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
+ // add an extra entry because the RunLengthDecode filter may
+ // read past the end
+ writePS("<>]\n");
+ writePS("0\n");
+ str2->close();
+ delete str2;
+ } else {
+ // make sure the image is setup, it sometimes is not like on bug #17645
+ setupImage(ref->getRef(), str, gFalse);
+ // set up to use the array already created by setupImages()
+ writePSFmt("ImData_{0:d}_{1:d} 0 0\n",ref->getRefNum(), ref->getRefGen());
+ }
+ }
+
+ // image dictionary
+ writePS("<<\n /ImageType 1\n");
+
+ // width, height, matrix, bits per component
+ writePSFmt(" /Width {0:d}\n", width);
+ writePSFmt(" /Height {0:d}\n", height);
+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
+ width, -height, height);
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ writePS(" /BitsPerComponent 8\n");
+ } else {
+ writePSFmt(" /BitsPerComponent {0:d}\n",
+ colorMap ? colorMap->getBits() : 1);
+ }
+
+ // decode
+ if (colorMap) {
+ writePS(" /Decode [");
+ if ((level == psLevel2Sep || level == psLevel3Sep) &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ // this matches up with the code in the pdfImSep operator
+ n = (1 << colorMap->getBits()) - 1;
+ writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
+ colorMap->getDecodeHigh(0) * n);
+ } else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
+ numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getAlt()->getNComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePS("0 1");
+ }
+ } else {
+ numComps = colorMap->getNumPixelComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePSFmt("{0:.4g} {1:.4g}",
+ colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
+ }
+ }
+ writePS("]\n");
+ } else {
+ writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
+ }
+
+ // data source
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+ if (inlineImg) {
+ writePS(" /DataSource { pdfImStr }\n");
+ } else {
+ writePS(" /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
+ " index get 1 index get exch 1 add exch }\n");
+ }
+ } else {
+ writePS(" /DataSource currentfile\n");
+ }
+
+ // filters
+ if ((mode == psModeForm || inType3Char || preloadImagesForms) &&
+ uncompressPreloadedImages) {
+ s = NULL;
+ useRLE = gFalse;
+ useCompressed = gFalse;
+ useASCII = gFalse;
+ } else {
+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+ " ");
+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+ inlineImg || !s) {
+ useRLE = gTrue;
+ useASCII = !(mode == psModeForm || inType3Char || preloadImagesForms);
+ useCompressed = gFalse;
+ } else {
+ useRLE = gFalse;
+ useASCII = str->isBinary() &&
+ !(mode == psModeForm || inType3Char || preloadImagesForms);
+ useCompressed = gTrue;
+ }
+ }
+ if (useASCII) {
+ writePSFmt(" /ASCII{0:s}Decode filter\n",
+ useASCIIHex ? "Hex" : "85");
+ }
+ if (useRLE) {
+ writePS(" /RunLengthDecode filter\n");
+ }
+ if (useCompressed) {
+ writePS(s->getCString());
+ }
+ if (s) {
+ delete s;
+ }
+
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+
+ // end of image dictionary
+ writePSFmt(">>\n{0:s}\n", colorMap ? "image" : "imagemask");
+
+ // get rid of the array and index
+ if (!inlineImg) writePS("pop ");
+ writePS("pop pop\n");
+
+ } else {
+
+ // cut off inline image streams at appropriate length
+ if (inlineImg) {
+ str = new FixedLengthEncoder(str, len);
+ } else if (useCompressed) {
+ str = str->getUndecodedStream();
+ }
+
+ // recode DeviceN data
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ str = new DeviceNRecoder(str, width, height, colorMap);
+ }
+
+ // add RunLengthEncode and ASCIIHex/85 encode filters
+ if (useRLE) {
+ str = new RunLengthEncoder(str);
+ }
+ if (useASCII) {
+ if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+ }
+
+ // end of image dictionary
+ writePS(">>\n");
+#if OPI_SUPPORT
+ if (opi13Nest) {
+ if (inlineImg) {
+ // this can't happen -- OPI dictionaries are in XObjects
+ error(errSyntaxError, -1, "OPI in inline image");
+ n = 0;
+ } else {
+ // need to read the stream to count characters -- the length
+ // is data-dependent (because of ASCII and RLE filters)
+ str->reset();
+ n = 0;
+ while ((c = str->getChar()) != EOF) {
+ ++n;
+ }
+ str->close();
+ }
+ // +6/7 for "pdfIm\n" / "pdfImM\n"
+ // +8 for newline + trailer
+ n += colorMap ? 14 : 15;
+ writePSFmt("%%BeginData: {0:d} Hex Bytes\n", n);
+ }
+#endif
+ if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
+ colorMap->getColorSpace()->getMode() == csSeparation && colorMap->getBits() == 8) {
+ color.c[0] = gfxColorComp1;
+ sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
+ colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName());
+ } else {
+ writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
+ }
+
+ // copy the stream data
+ str->reset();
+ i = 0;
+ while ((c = str->getChar()) != EOF) {
+ dataBuf[i++] = c;
+ if (i >= (int)sizeof(dataBuf)) {
+ writePSBuf(dataBuf, i);
+ i = 0;
+ }
+ }
+ if (i > 0) {
+ writePSBuf(dataBuf, i);
+ }
+ str->close();
+
+ // add newline and trailer to the end
+ writePSChar('\n');
+ writePS("%-EOD-\n");
+#if OPI_SUPPORT
+ if (opi13Nest) {
+ writePS("%%EndData\n");
+ }
+#endif
+
+ // delete encoders
+ if (useRLE || useASCII || inlineImg) {
+ delete str;
+ }
+ }
+
+ if ((maskColors && colorMap && !inlineImg) || maskStr) {
+ if (rectsOutLen < 65536/4) {
+ writePS("pdfImClipEnd\n");
+ } else {
+ writePS("grestore\n");
+ }
+ }
+}
+
+//~ this doesn't currently support OPI
+void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert) {
+ Stream *str2;
+ GooString *s;
+ int n, numComps;
+ GBool useRLE, useASCII, useCompressed;
+ GBool maskUseRLE, maskUseASCII, maskUseCompressed;
+ GooString *maskFilters;
+ GfxSeparationColorSpace *sepCS;
+ GfxColor color;
+ GfxCMYK cmyk;
+ int c;
+ int col, i;
+
+ useRLE = useASCII = useCompressed = gFalse; // make gcc happy
+ maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
+ maskFilters = NULL; // make gcc happy
+
+ // explicit masking
+ if (maskStr) {
+
+ // mask data source
+ if ((mode == psModeForm || inType3Char || preloadImagesForms) &&
+ uncompressPreloadedImages) {
+ s = NULL;
+ maskUseRLE = gFalse;
+ maskUseCompressed = gFalse;
+ maskUseASCII = gFalse;
+ } else {
+ s = maskStr->getPSFilter(3, " ");
+ if (!s) {
+ maskUseRLE = gTrue;
+ maskUseASCII = !(mode == psModeForm || inType3Char || preloadImagesForms);
+ maskUseCompressed = gFalse;
+ } else {
+ maskUseRLE = gFalse;
+ maskUseASCII = maskStr->isBinary() &&
+ !(mode == psModeForm || inType3Char || preloadImagesForms);
+ maskUseCompressed = gTrue;
+ }
+ }
+ maskFilters = new GooString();
+ if (maskUseASCII) {
+ maskFilters->appendf(" /ASCII{0:s}Decode filter\n",
+ useASCIIHex ? "Hex" : "85");
+ }
+ if (maskUseRLE) {
+ maskFilters->append(" /RunLengthDecode filter\n");
+ }
+ if (maskUseCompressed) {
+ maskFilters->append(s);
+ }
+ if (s) {
+ delete s;
+ }
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+ writePSFmt("MaskData_{0:d}_{1:d} pdfMaskInit\n",
+ ref->getRefNum(), ref->getRefGen());
+ } else {
+ writePS("currentfile\n");
+ writePS(maskFilters->getCString());
+ writePS("pdfMask\n");
+
+ // add RunLengthEncode and ASCIIHex/85 encode filters
+ if (maskUseCompressed) {
+ maskStr = maskStr->getUndecodedStream();
+ }
+ if (maskUseRLE) {
+ maskStr = new RunLengthEncoder(maskStr);
+ }
+ if (maskUseASCII) {
+ if (useASCIIHex) {
+ maskStr = new ASCIIHexEncoder(maskStr);
+ } else {
+ maskStr = new ASCII85Encoder(maskStr);
+ }
+ }
+
+ // copy the stream data
+ maskStr->reset();
+ while ((c = maskStr->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ maskStr->close();
+ writePSChar('\n');
+ writePS("%-EOD-\n");
+
+ // delete encoders
+ if (maskUseRLE || maskUseASCII) {
+ delete maskStr;
+ }
+ }
+ }
+
+ // color space
+ if (colorMap) {
+ dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
+ writePS(" setcolorspace\n");
+ }
+
+ // set up the image data
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+ if (inlineImg) {
+ // create an array
+ str2 = new FixedLengthEncoder(str, len);
+ str2 = new RunLengthEncoder(str2);
+ if (useASCIIHex) {
+ str2 = new ASCIIHexEncoder(str2);
+ } else {
+ str2 = new ASCII85Encoder(str2);
+ }
+ str2->reset();
+ col = 0;
+ writePS((char *)(useASCIIHex ? "[<" : "[<~"));
+ do {
+ do {
+ c = str2->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ writePSChar(c);
+ ++col;
+ } else {
+ writePSChar(c);
+ ++col;
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str2->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ }
+ }
+ // each line is: "<~...data...~><eol>"
+ // so max data length = 255 - 6 = 249
+ // chunks are 1 or 5 bytes each, so we have to stop at 245
+ // but make it 240 just to be safe
+ if (col > 240) {
+ writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
+ col = 0;
+ }
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
+ writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
+ // add an extra entry because the RunLengthDecode filter may
+ // read past the end
+ writePS("<>]\n");
+ writePS("0\n");
+ str2->close();
+ delete str2;
+ } else {
+ // make sure the image is setup, it sometimes is not like on bug #17645
+ setupImage(ref->getRef(), str, gFalse);
+ // set up to use the array already created by setupImages()
+ writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
+ }
+ }
+
+ // explicit masking
+ if (maskStr) {
+ writePS("<<\n /ImageType 3\n");
+ writePS(" /InterleaveType 3\n");
+ writePS(" /DataDict\n");
+ }
+
+ // image (data) dictionary
+ writePSFmt("<<\n /ImageType {0:d}\n", (maskColors && colorMap) ? 4 : 1);
+
+ // color key masking
+ if (maskColors && colorMap) {
+ writePS(" /MaskColor [\n");
+ numComps = colorMap->getNumPixelComps();
+ for (i = 0; i < 2 * numComps; i += 2) {
+ writePSFmt(" {0:d} {1:d}\n", maskColors[i], maskColors[i+1]);
+ }
+ writePS(" ]\n");
+ }
+
+ // width, height, matrix, bits per component
+ writePSFmt(" /Width {0:d}\n", width);
+ writePSFmt(" /Height {0:d}\n", height);
+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
+ width, -height, height);
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ writePS(" /BitsPerComponent 8\n");
+ } else {
+ writePSFmt(" /BitsPerComponent {0:d}\n",
+ colorMap ? colorMap->getBits() : 1);
+ }
+
+ // decode
+ if (colorMap) {
+ writePS(" /Decode [");
+ if ((level == psLevel2Sep || level == psLevel3Sep) &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ // this matches up with the code in the pdfImSep operator
+ n = (1 << colorMap->getBits()) - 1;
+ writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
+ colorMap->getDecodeHigh(0) * n);
+ } else {
+ numComps = colorMap->getNumPixelComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(i),
+ colorMap->getDecodeHigh(i));
+ }
+ }
+ writePS("]\n");
+ } else {
+ writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
+ }
+
+ // data source
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+ if (inlineImg) {
+ writePS(" /DataSource { pdfImStr }\n");
+ } else {
+ writePS(" /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
+ " index get 1 index get exch 1 add exch }\n");
+ }
+ } else {
+ writePS(" /DataSource currentfile\n");
+ }
+
+ // filters
+ if ((mode == psModeForm || inType3Char || preloadImagesForms) &&
+ uncompressPreloadedImages) {
+ s = NULL;
+ useRLE = gFalse;
+ useCompressed = gFalse;
+ useASCII = gFalse;
+ } else {
+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+ " ");
+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+ inlineImg || !s) {
+ useRLE = gTrue;
+ useASCII = !(mode == psModeForm || inType3Char || preloadImagesForms);
+ useCompressed = gFalse;
+ } else {
+ useRLE = gFalse;
+ useASCII = str->isBinary() &&
+ !(mode == psModeForm || inType3Char || preloadImagesForms);
+ useCompressed = gTrue;
+ }
+ }
+ if (useASCII) {
+ writePSFmt(" /ASCII{0:s}Decode filter\n",
+ useASCIIHex ? "Hex" : "85");
+ }
+ if (useRLE) {
+ writePS(" /RunLengthDecode filter\n");
+ }
+ if (useCompressed) {
+ writePS(s->getCString());
+ }
+ if (s) {
+ delete s;
+ }
+
+ // end of image (data) dictionary
+ writePS(">>\n");
+
+ // explicit masking
+ if (maskStr) {
+ writePS(" /MaskDict\n");
+ writePS("<<\n");
+ writePS(" /ImageType 1\n");
+ writePSFmt(" /Width {0:d}\n", maskWidth);
+ writePSFmt(" /Height {0:d}\n", maskHeight);
+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
+ maskWidth, -maskHeight, maskHeight);
+ writePS(" /BitsPerComponent 1\n");
+ writePSFmt(" /Decode [{0:d} {1:d}]\n",
+ maskInvert ? 1 : 0, maskInvert ? 0 : 1);
+
+ // mask data source
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+ writePS(" /DataSource {pdfMaskSrc}\n");
+ writePS(maskFilters->getCString());
+ } else {
+ writePS(" /DataSource maskStream\n");
+ }
+ delete maskFilters;
+
+ writePS(">>\n");
+ writePS(">>\n");
+ }
+
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+
+ // image command
+ writePSFmt("{0:s}\n", colorMap ? "image" : "imagemask");
+
+ } else {
+
+ if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
+ colorMap->getColorSpace()->getMode() == csSeparation && colorMap->getBits() == 8) {
+ color.c[0] = gfxColorComp1;
+ sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
+ colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName());
+ } else {
+ writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
+ }
+
+ }
+
+ // get rid of the array and index
+ if (mode == psModeForm || inType3Char || preloadImagesForms) {
+ if (!inlineImg) writePS("pop ");
+ writePS("pop pop\n");
+
+ // image data
+ } else {
+
+ // cut off inline image streams at appropriate length
+ if (inlineImg) {
+ str = new FixedLengthEncoder(str, len);
+ } else if (useCompressed) {
+ str = str->getUndecodedStream();
+ }
+
+ // add RunLengthEncode and ASCIIHex/85 encode filters
+ if (useRLE) {
+ str = new RunLengthEncoder(str);
+ }
+ if (useASCII) {
+ if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+ }
+
+ // copy the stream data
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
+
+ // add newline and trailer to the end
+ writePSChar('\n');
+ writePS("%-EOD-\n");
+
+ // delete encoders
+ if (useRLE || useASCII || inlineImg) {
+ delete str;
+ }
+ }
+
+ // close the mask stream
+ if (maskStr) {
+ if (!(mode == psModeForm || inType3Char || preloadImagesForms)) {
+ writePS("pdfMaskEnd\n");
+ }
+ }
+}
+
+void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ GfxCalGrayColorSpace *calGrayCS;
+ GfxCalRGBColorSpace *calRGBCS;
+ GfxLabColorSpace *labCS;
+ GfxIndexedColorSpace *indexedCS;
+ GfxSeparationColorSpace *separationCS;
+ GfxDeviceNColorSpace *deviceNCS;
+ GfxColorSpace *baseCS;
+ Guchar *lookup, *p;
+ double x[gfxColorMaxComps], y[gfxColorMaxComps];
+ double low[gfxColorMaxComps], range[gfxColorMaxComps];
+ GfxColor color;
+ GfxCMYK cmyk;
+ Function *func;
+ int n, numComps, numAltComps;
+ int byte;
+ int i, j, k;
+
+ switch (colorSpace->getMode()) {
+
+ case csDeviceGray:
+ writePS("/DeviceGray");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessBlack;
+ }
+ break;
+
+ case csCalGray:
+ calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
+ writePS("[/CIEBasedA <<\n");
+ writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", calGrayCS->getGamma());
+ writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+ calGrayCS->getWhiteZ());
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+ calGrayCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calGrayCS->getBlackX(), calGrayCS->getBlackY(),
+ calGrayCS->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessBlack;
+ }
+ break;
+
+ case csDeviceRGB:
+ writePS("/DeviceRGB");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+ break;
+
+ case csCalRGB:
+ calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
+ writePS("[/CIEBasedABC <<\n");
+ writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n",
+ calRGBCS->getGammaR(), calRGBCS->getGammaG(),
+ calRGBCS->getGammaB());
+ writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n",
+ calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
+ calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
+ calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
+ calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
+ calRGBCS->getMatrix()[8]);
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
+ calRGBCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calRGBCS->getBlackX(), calRGBCS->getBlackY(),
+ calRGBCS->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+ break;
+
+ case csDeviceCMYK:
+ writePS("/DeviceCMYK");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+ break;
+
+ case csLab:
+ labCS = (GfxLabColorSpace *)colorSpace;
+ writePS("[/CIEBasedABC <<\n");
+ if (map01) {
+ writePS(" /RangeABC [0 1 0 1 0 1]\n");
+ writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n",
+ (labCS->getAMax() - labCS->getAMin()) / 500.0,
+ labCS->getAMin() / 500.0,
+ (labCS->getBMax() - labCS->getBMin()) / 200.0,
+ labCS->getBMin() / 200.0);
+ } else {
+ writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n",
+ labCS->getAMin(), labCS->getAMax(),
+ labCS->getBMin(), labCS->getBMax());
+ writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
+ }
+ writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
+ writePS(" /DecodeLMN\n");
+ writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
+ labCS->getWhiteX());
+ writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
+ labCS->getWhiteY());
+ writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n",
+ labCS->getWhiteZ());
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+ break;
+
+ case csICCBased:
+ // there is no transform function to the alternate color space, so
+ // we can use it directly
+ dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
+ genXform, updateColors, gFalse);
+ break;
+
+ case csIndexed:
+ indexedCS = (GfxIndexedColorSpace *)colorSpace;
+ baseCS = indexedCS->getBase();
+ writePS("[/Indexed ");
+ dumpColorSpaceL2(baseCS, gFalse, gFalse, gTrue);
+ n = indexedCS->getIndexHigh();
+ numComps = baseCS->getNComps();
+ lookup = indexedCS->getLookup();
+ writePSFmt(" {0:d} <\n", n);
+ if (baseCS->getMode() == csDeviceN && level != psLevel3 && level != psLevel3Sep) {
+ func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
+ baseCS->getDefaultRanges(low, range, indexedCS->getIndexHigh());
+ if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) {
+ labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt();
+ } else {
+ labCS = NULL;
+ }
+ numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
+ p = lookup;
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ x[k] = low[k] + (*p++ / 255.0) * range[k];
+ }
+ func->transform(x, y);
+ if (labCS) {
+ y[0] /= 100.0;
+ y[1] = (y[1] - labCS->getAMin()) /
+ (labCS->getAMax() - labCS->getAMin());
+ y[2] = (y[2] - labCS->getBMin()) /
+ (labCS->getBMax() - labCS->getBMin());
+ }
+ for (k = 0; k < numAltComps; ++k) {
+ byte = (int)(y[k] * 255 + 0.5);
+ if (byte < 0) {
+ byte = 0;
+ } else if (byte > 255) {
+ byte = 255;
+ }
+ writePSFmt("{0:02x}", byte);
+ }
+ if (updateColors) {
+ color.c[0] = dblToCol(j);
+ indexedCS->getCMYK(&color, &cmyk);
+ addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k));
+ }
+ }
+ writePS("\n");
+ }
+ } else {
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ writePSFmt("{0:02x}", lookup[j * numComps + k]);
+ }
+ if (updateColors) {
+ color.c[0] = dblToCol(j);
+ indexedCS->getCMYK(&color, &cmyk);
+ addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k));
+ }
+ }
+ writePS("\n");
+ }
+ }
+ writePS(">]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ break;
+
+ case csSeparation:
+ separationCS = (GfxSeparationColorSpace *)colorSpace;
+ writePS("[/Separation ");
+ writePSString(separationCS->getName());
+ writePS(" ");
+ dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse, gFalse);
+ writePS("\n");
+ cvtFunction(separationCS->getFunc());
+ writePS("]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ addCustomColor(separationCS);
+ }
+ break;
+
+ case csDeviceN:
+ deviceNCS = (GfxDeviceNColorSpace *)colorSpace;
+ if (level == psLevel3 || level == psLevel3Sep) {
+ writePS("[/DeviceN\n");
+ writePS(" [ ");
+ for (i = 0; i < deviceNCS->getNComps(); i++) {
+ writePSString(deviceNCS->getColorantName(i));
+ writePS(" ");
+ }
+ writePS("]\n");
+ dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, gFalse);
+ writePS("\n");
+ cvtFunction(deviceNCS->getTintTransformFunc(), map01 && deviceNCS->getAlt()->getMode() == csLab);
+ writePS("]\n");
+ if (genXform) {
+ writePS(" {}");
+ }
+ } else {
+ // DeviceN color spaces are a Level 3 PostScript feature.
+ dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, map01);
+ if (genXform) {
+ writePS(" ");
+ cvtFunction(deviceNCS->getTintTransformFunc());
+ }
+ }
+ break;
+
+ case csPattern:
+ //~ unimplemented
+ break;
+ }
+}
+
+#if OPI_SUPPORT
+void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
+ Object dict;
+
+ if (generateOPI) {
+ opiDict->lookup("2.0", &dict);
+ if (dict.isDict()) {
+ opiBegin20(state, dict.getDict());
+ dict.free();
+ } else {
+ dict.free();
+ opiDict->lookup("1.3", &dict);
+ if (dict.isDict()) {
+ opiBegin13(state, dict.getDict());
+ }
+ dict.free();
+ }
+ }
+}
+
+void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
+ Object obj1, obj2, obj3, obj4;
+ double width, height, left, right, top, bottom;
+ int w, h;
+ int i;
+
+ writePS("%%BeginOPI: 2.0\n");
+ writePS("%%Distilled\n");
+
+ dict->lookup("F", &obj1);
+ if (getFileSpecName(&obj1, &obj2)) {
+ writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString());
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("MainImage", &obj1);
+ if (obj1.isString()) {
+ writePSFmt("%%MainImage: {0:t}\n", obj1.getString());
+ }
+ obj1.free();
+
+ //~ ignoring 'Tags' entry
+ //~ need to use writePSString() and deal with >255-char lines
+
+ dict->lookup("Size", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ width = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ height = obj2.getNum();
+ obj2.free();
+ writePSFmt("%%ImageDimensions: {0:.6g} {1:.6g}\n", width, height);
+ }
+ obj1.free();
+
+ dict->lookup("CropRect", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ obj1.arrayGet(0, &obj2);
+ left = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ top = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ right = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ bottom = obj2.getNum();
+ obj2.free();
+ writePSFmt("%%ImageCropRect: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
+ left, top, right, bottom);
+ }
+ obj1.free();
+
+ dict->lookup("Overprint", &obj1);
+ if (obj1.isBool()) {
+ writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ dict->lookup("Inks", &obj1);
+ if (obj1.isName()) {
+ writePSFmt("%%ImageInks: {0:s}\n", obj1.getName());
+ } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isName()) {
+ writePSFmt("%%ImageInks: {0:s} {1:d}",
+ obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
+ for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
+ obj1.arrayGet(i, &obj3);
+ obj1.arrayGet(i+1, &obj4);
+ if (obj3.isString() && obj4.isNum()) {
+ writePS(" ");
+ writePSString(obj3.getString());
+ writePSFmt(" {0:.6g}", obj4.getNum());
+ }
+ obj3.free();
+ obj4.free();
+ }
+ writePS("\n");
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ writePS("gsave\n");
+
+ writePS("%%BeginIncludedImage\n");
+
+ dict->lookup("IncludedImageDimensions", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ w = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ h = obj2.getInt();
+ obj2.free();
+ writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h);
+ }
+ obj1.free();
+
+ dict->lookup("IncludedImageQuality", &obj1);
+ if (obj1.isNum()) {
+ writePSFmt("%%IncludedImageQuality: {0:.6g}\n", obj1.getNum());
+ }
+ obj1.free();
+
+ ++opi20Nest;
+}
+
+void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
+ Object obj1, obj2;
+ int left, right, top, bottom, samples, bits, width, height;
+ double c, m, y, k;
+ double llx, lly, ulx, uly, urx, ury, lrx, lry;
+ double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
+ double horiz, vert;
+ int i, j;
+
+ writePS("save\n");
+ writePS("/opiMatrix2 matrix currentmatrix def\n");
+ writePS("opiMatrix setmatrix\n");
+
+ dict->lookup("F", &obj1);
+ if (getFileSpecName(&obj1, &obj2)) {
+ writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString());
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("CropRect", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ obj1.arrayGet(0, &obj2);
+ left = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ top = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ right = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ bottom = obj2.getInt();
+ obj2.free();
+ writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n",
+ left, top, right, bottom);
+ }
+ obj1.free();
+
+ dict->lookup("Color", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 5) {
+ obj1.arrayGet(0, &obj2);
+ c = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ m = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ y = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ k = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(4, &obj2);
+ if (obj2.isString()) {
+ writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ",
+ c, m, y, k);
+ writePSString(obj2.getString());
+ writePS("\n");
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("ColorType", &obj1);
+ if (obj1.isName()) {
+ writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName());
+ }
+ obj1.free();
+
+ //~ ignores 'Comments' entry
+ //~ need to handle multiple lines
+
+ dict->lookup("CropFixed", &obj1);
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ ulx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ uly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ lrx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ lry = obj2.getNum();
+ obj2.free();
+ writePSFmt("%ALDImageCropFixed: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
+ ulx, uly, lrx, lry);
+ }
+ obj1.free();
+
+ dict->lookup("GrayMap", &obj1);
+ if (obj1.isArray()) {
+ writePS("%ALDImageGrayMap:");
+ for (i = 0; i < obj1.arrayGetLength(); i += 16) {
+ if (i > 0) {
+ writePS("\n%%+");
+ }
+ for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
+ obj1.arrayGet(i+j, &obj2);
+ writePSFmt(" {0:d}", obj2.getInt());
+ obj2.free();
+ }
+ }
+ writePS("\n");
+ }
+ obj1.free();
+
+ dict->lookup("ID", &obj1);
+ if (obj1.isString()) {
+ writePSFmt("%ALDImageID: {0:t}\n", obj1.getString());
+ }
+ obj1.free();
+
+ dict->lookup("ImageType", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ samples = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ bits = obj2.getInt();
+ obj2.free();
+ writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits);
+ }
+ obj1.free();
+
+ dict->lookup("Overprint", &obj1);
+ if (obj1.isBool()) {
+ writePSFmt("%ALDImageOverprint: {0:s}\n",
+ obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ dict->lookup("Position", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 8) {
+ obj1.arrayGet(0, &obj2);
+ llx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ lly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ ulx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ uly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(4, &obj2);
+ urx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(5, &obj2);
+ ury = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(6, &obj2);
+ lrx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(7, &obj2);
+ lry = obj2.getNum();
+ obj2.free();
+ opiTransform(state, llx, lly, &tllx, &tlly);
+ opiTransform(state, ulx, uly, &tulx, &tuly);
+ opiTransform(state, urx, ury, &turx, &tury);
+ opiTransform(state, lrx, lry, &tlrx, &tlry);
+ writePSFmt("%ALDImagePosition: {0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} {6:.6g} {7:.6g}\n",
+ tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Resolution", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ horiz = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ vert = obj2.getNum();
+ obj2.free();
+ writePSFmt("%ALDImageResoution: {0:.6g} {1:.6g}\n", horiz, vert);
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Size", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ width = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ height = obj2.getInt();
+ obj2.free();
+ writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height);
+ }
+ obj1.free();
+
+ //~ ignoring 'Tags' entry
+ //~ need to use writePSString() and deal with >255-char lines
+
+ dict->lookup("Tint", &obj1);
+ if (obj1.isNum()) {
+ writePSFmt("%ALDImageTint: {0:.6g}\n", obj1.getNum());
+ }
+ obj1.free();
+
+ dict->lookup("Transparency", &obj1);
+ if (obj1.isBool()) {
+ writePSFmt("%ALDImageTransparency: {0:s}\n",
+ obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ writePS("%%BeginObject: image\n");
+ writePS("opiMatrix2 setmatrix\n");
+ ++opi13Nest;
+}
+
+// Convert PDF user space coordinates to PostScript default user space
+// coordinates. This has to account for both the PDF CTM and the
+// PSOutputDev page-fitting transform.
+void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
+ double *x1, double *y1) {
+ double t;
+
+ state->transform(x0, y0, x1, y1);
+ *x1 += tx;
+ *y1 += ty;
+ if (rotate == 90) {
+ t = *x1;
+ *x1 = -*y1;
+ *y1 = t;
+ } else if (rotate == 180) {
+ *x1 = -*x1;
+ *y1 = -*y1;
+ } else if (rotate == 270) {
+ t = *x1;
+ *x1 = *y1;
+ *y1 = -t;
+ }
+ *x1 *= xScale;
+ *y1 *= yScale;
+}
+
+void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
+ Object dict;
+
+ if (generateOPI) {
+ opiDict->lookup("2.0", &dict);
+ if (dict.isDict()) {
+ writePS("%%EndIncludedImage\n");
+ writePS("%%EndOPI\n");
+ writePS("grestore\n");
+ --opi20Nest;
+ dict.free();
+ } else {
+ dict.free();
+ opiDict->lookup("1.3", &dict);
+ if (dict.isDict()) {
+ writePS("%%EndObject\n");
+ writePS("restore\n");
+ --opi13Nest;
+ }
+ dict.free();
+ }
+ }
+}
+#endif // OPI_SUPPORT
+
+void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
+ writePSFmt("{0:.6g} {1:.6g} setcharwidth\n", wx, wy);
+ writePS("q\n");
+ t3NeedsRestore = gTrue;
+}
+
+void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury) {
+ t3WX = wx;
+ t3WY = wy;
+ t3LLX = llx;
+ t3LLY = lly;
+ t3URX = urx;
+ t3URY = ury;
+ t3String = new GooString();
+ writePS("q\n");
+ t3FillColorOnly = gTrue;
+ t3Cacheable = gTrue;
+ t3NeedsRestore = gTrue;
+}
+
+void PSOutputDev::drawForm(Ref id) {
+ writePSFmt("f_{0:d}_{1:d}\n", id.num, id.gen);
+}
+
+void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
+ Stream *str;
+ int c;
+
+ if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
+ str = level1Stream;
+ } else {
+ str = psStream;
+ }
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
+}
+
+//~ can nextFunc be reset to 0 -- maybe at the start of each page?
+//~ or maybe at the start of each color space / pattern?
+void PSOutputDev::cvtFunction(Function *func, GBool invertPSFunction) {
+ SampledFunction *func0;
+ ExponentialFunction *func2;
+ StitchingFunction *func3;
+ PostScriptFunction *func4;
+ int thisFunc, m, n, nSamples, i, j, k;
+
+ switch (func->getType()) {
+
+ case -1: // identity
+ writePS("{}\n");
+ break;
+
+ case 0: // sampled
+ func0 = (SampledFunction *)func;
+ thisFunc = nextFunc++;
+ m = func0->getInputSize();
+ n = func0->getOutputSize();
+ nSamples = n;
+ for (i = 0; i < m; ++i) {
+ nSamples *= func0->getSampleSize(i);
+ }
+ writePSFmt("/xpdfSamples{0:d} [\n", thisFunc);
+ for (i = 0; i < nSamples; ++i) {
+ writePSFmt("{0:.6g}\n", func0->getSamples()[i]);
+ }
+ writePS("] def\n");
+ writePSFmt("{{ {0:d} array {1:d} array {2:d} 2 roll\n", 2*m, m, m+2);
+ // [e01] [efrac] x0 x1 ... xm-1
+ for (i = m-1; i >= 0; --i) {
+ // [e01] [efrac] x0 x1 ... xi
+ writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add\n",
+ func0->getDomainMin(i),
+ (func0->getEncodeMax(i) - func0->getEncodeMin(i)) /
+ (func0->getDomainMax(i) - func0->getDomainMin(i)),
+ func0->getEncodeMin(i));
+ // [e01] [efrac] x0 x1 ... xi-1 xi'
+ writePSFmt("dup 0 lt {{ pop 0 }} {{ dup {0:d} gt {{ pop {1:d} }} if }} ifelse\n",
+ func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1);
+ // [e01] [efrac] x0 x1 ... xi-1 xi'
+ writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
+ // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
+ writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, i);
+ // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
+ writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, 2*i+1);
+ // [e01] [efrac] x0 x1 ... xi-1 floor(xi')
+ writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+2, 2*i);
+ // [e01] [efrac] x0 x1 ... xi-1
+ }
+ // [e01] [efrac]
+ for (i = 0; i < n; ++i) {
+ // [e01] [efrac] y(0) ... y(i-1)
+ for (j = 0; j < (1<<m); ++j) {
+ // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
+ writePSFmt("xpdfSamples{0:d}\n", thisFunc);
+ k = m - 1;
+ writePSFmt("{0:d} index {1:d} get\n", i+j+2, 2 * k + ((j >> k) & 1));
+ for (k = m - 2; k >= 0; --k) {
+ writePSFmt("{0:d} mul {1:d} index {2:d} get add\n",
+ func0->getSampleSize(k),
+ i + j + 3,
+ 2 * k + ((j >> k) & 1));
+ }
+ if (n > 1) {
+ writePSFmt("{0:d} mul {1:d} add ", n, i);
+ }
+ writePS("get\n");
+ }
+ // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
+ for (j = 0; j < m; ++j) {
+ // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
+ for (k = 0; k < (1 << (m - j)); k += 2) {
+ // [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
+ writePSFmt("{0:d} index {1:d} get dup\n",
+ i + k/2 + (1 << (m-j)) - k, j);
+ writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
+ writePSFmt("{0:d} 1 roll\n", k/2 + (1 << (m-j)) - k - 1);
+ }
+ // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
+ }
+ // [e01] [efrac] y(0) ... y(i-1) s
+ writePSFmt("{0:.6g} mul {1:.6g} add\n",
+ func0->getDecodeMax(i) - func0->getDecodeMin(i),
+ func0->getDecodeMin(i));
+ writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
+ func0->getRangeMin(i), func0->getRangeMin(i),
+ func0->getRangeMax(i), func0->getRangeMax(i));
+ // [e01] [efrac] y(0) ... y(i-1) y(i)
+ }
+ // [e01] [efrac] y(0) ... y(n-1)
+ writePSFmt("{0:d} {1:d} roll pop pop \n", n+2, n);
+ if (invertPSFunction) {
+ for (i = 0; i < n; ++i) {
+ writePSFmt("{0:d} -1 roll ", n);
+ writePSFmt("{0:.6g} sub {1:.6g} div ", func0->getRangeMin(i), func0->getRangeMax(i) - func0->getRangeMin(i));
+ }
+ }
+ writePS("}\n");
+ break;
+
+ case 2: // exponential
+ func2 = (ExponentialFunction *)func;
+ n = func2->getOutputSize();
+ writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
+ func2->getDomainMin(0), func2->getDomainMin(0),
+ func2->getDomainMax(0), func2->getDomainMax(0));
+ // x
+ for (i = 0; i < n; ++i) {
+ // x y(0) .. y(i-1)
+ writePSFmt("{0:d} index {1:.6g} exp {2:.6g} mul {3:.6g} add\n",
+ i, func2->getE(), func2->getC1()[i] - func2->getC0()[i],
+ func2->getC0()[i]);
+ if (func2->getHasRange()) {
+ writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
+ func2->getRangeMin(i), func2->getRangeMin(i),
+ func2->getRangeMax(i), func2->getRangeMax(i));
+ }
+ }
+ // x y(0) .. y(n-1)
+ writePSFmt("{0:d} {1:d} roll pop \n", n+1, n);
+ if (invertPSFunction && func2->getHasRange()) {
+ for (i = 0; i < n; ++i) {
+ writePSFmt("{0:d} -1 roll ", n);
+ writePSFmt("{0:.6g} sub {1:.6g} div ", func2->getRangeMin(i), func2->getRangeMax(i) - func2->getRangeMin(i));
+ }
+ }
+ writePS("}\n");
+ break;
+
+ case 3: // stitching
+ func3 = (StitchingFunction *)func;
+ thisFunc = nextFunc++;
+ for (i = 0; i < func3->getNumFuncs(); ++i) {
+ cvtFunction(func3->getFunc(i));
+ writePSFmt("/xpdfFunc{0:d}_{1:d} exch def\n", thisFunc, i);
+ }
+ writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
+ func3->getDomainMin(0), func3->getDomainMin(0),
+ func3->getDomainMax(0), func3->getDomainMax(0));
+ for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
+ writePSFmt("dup {0:.6g} lt {{ {1:.6g} sub {2:.6g} mul {3:.6g} add xpdfFunc{4:d}_{5:d} }} {{\n",
+ func3->getBounds()[i+1],
+ func3->getBounds()[i],
+ func3->getScale()[i],
+ func3->getEncode()[2*i],
+ thisFunc, i);
+ }
+ writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add xpdfFunc{3:d}_{4:d}\n",
+ func3->getBounds()[i],
+ func3->getScale()[i],
+ func3->getEncode()[2*i],
+ thisFunc, i);
+ for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
+ writePS("} ifelse\n");
+ }
+ if (invertPSFunction && func3->getHasRange()) {
+ n = func3->getOutputSize();
+ for (i = 0; i < n; ++i) {
+ writePSFmt("{0:d} -1 roll ", n);
+ writePSFmt("{0:.6g} sub {1:.6g} div ", func3->getRangeMin(i), func3->getRangeMax(i) - func3->getRangeMin(i));
+ }
+ }
+ writePS("}\n");
+ break;
+
+ case 4: // PostScript
+ func4 = (PostScriptFunction *)func;
+ if (invertPSFunction) {
+ GooString *codeString = new GooString(func4->getCodeString());
+ for (i = codeString->getLength() -1; i > 0; i--) {
+ if (codeString->getChar(i) == '}') {
+ codeString->del(i);
+ break;
+ }
+ }
+ writePS(codeString->getCString());
+ writePS("\n");
+ delete codeString;
+ n = func4->getOutputSize();
+ for (i = 0; i < n; ++i) {
+ writePSFmt("{0:d} -1 roll ", n);
+ writePSFmt("{0:.6g} sub {1:.6g} div ", func4->getRangeMin(i), func4->getRangeMax(i) - func4->getRangeMin(i));
+ }
+ writePS("}\n");
+ } else {
+ writePS(func4->getCodeString()->getCString());
+ writePS("\n");
+ }
+ break;
+ }
+}
+
+void PSOutputDev::writePSChar(char c) {
+ if (t3String) {
+ t3String->append(c);
+ } else {
+ (*outputFunc)(outputStream, &c, 1);
+ }
+}
+
+void PSOutputDev::writePS(const char *s) {
+ if (t3String) {
+ t3String->append(s);
+ } else {
+ (*outputFunc)(outputStream, s, strlen(s));
+ }
+}
+
+void PSOutputDev::writePSBuf(const char *s, int len) {
+ if (t3String) {
+ for (int i = 0; i < len; i++) {
+ t3String->append(s[i]);
+ }
+ } else {
+ (*outputFunc)(outputStream, s, len);
+ }
+}
+
+void PSOutputDev::writePSFmt(const char *fmt, ...) {
+ va_list args;
+ GooString *buf;
+
+ va_start(args, fmt);
+ if (t3String) {
+ t3String->appendfv((char *)fmt, args);
+ } else {
+ buf = GooString::formatv((char *)fmt, args);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ va_end(args);
+}
+
+void PSOutputDev::writePSString(GooString *s) {
+ Guchar *p;
+ int n, line;
+ char buf[8];
+
+ writePSChar('(');
+ line = 1;
+ for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
+ if (line >= 64) {
+ writePSChar('\\');
+ writePSChar('\n');
+ line = 0;
+ }
+ if (*p == '(' || *p == ')' || *p == '\\') {
+ writePSChar('\\');
+ writePSChar((char)*p);
+ line += 2;
+ } else if (*p < 0x20 || *p >= 0x80) {
+ sprintf(buf, "\\%03o", *p);
+ writePS(buf);
+ line += 4;
+ } else {
+ writePSChar((char)*p);
+ ++line;
+ }
+ }
+ writePSChar(')');
+}
+
+void PSOutputDev::writePSName(const char *s) {
+ const char *p;
+ char c;
+
+ p = s;
+ while ((c = *p++)) {
+ if (c <= (char)0x20 || c >= (char)0x7f ||
+ c == '(' || c == ')' || c == '<' || c == '>' ||
+ c == '[' || c == ']' || c == '{' || c == '}' ||
+ c == '/' || c == '%' || c == '\\') {
+ writePSFmt("#{0:02x}", c & 0xff);
+ } else {
+ writePSChar(c);
+ }
+ }
+}
+
+GooString *PSOutputDev::filterPSName(GooString *name) {
+ GooString *name2;
+ char buf[8];
+ int i;
+ char c;
+
+ name2 = new GooString();
+
+ // ghostscript chokes on names that begin with out-of-limits
+ // numbers, e.g., 1e4foo is handled correctly (as a name), but
+ // 1e999foo generates a limitcheck error
+ c = name->getChar(0);
+ if (c >= '0' && c <= '9') {
+ name2->append('f');
+ }
+
+ for (i = 0; i < name->getLength(); ++i) {
+ c = name->getChar(i);
+ if (c <= (char)0x20 || c >= (char)0x7f ||
+ c == '(' || c == ')' || c == '<' || c == '>' ||
+ c == '[' || c == ']' || c == '{' || c == '}' ||
+ c == '/' || c == '%') {
+ sprintf(buf, "#%02x", c & 0xff);
+ name2->append(buf);
+ } else {
+ name2->append(c);
+ }
+ }
+ return name2;
+}
+
+// Convert GooString to GooString, with appropriate escaping
+// of things that can't appear in a label
+// This is heavily based on the writePSTextLine() method
+GooString* PSOutputDev::filterPSLabel(GooString *label, GBool *needParens) {
+ int i, step;
+ GBool isNumeric;
+
+ // - DSC comments must be printable ASCII; control chars and
+ // backslashes have to be escaped (we do cheap UCS2-to-ASCII
+ // conversion by simply ignoring the high byte)
+ // - parentheses are escaped. this isn't strictly necessary for matched
+ // parentheses, but shouldn't be a problem
+ // - lines are limited to 255 chars (we limit to 200 here to allow
+ // for the keyword, which was emitted by the caller)
+
+ GooString *label2 = new GooString();
+ int labelLength = label->getLength();
+
+ if (labelLength == 0) {
+ isNumeric = false;
+ } else {
+ // this gets changed later if we find a non-numeric character
+ isNumeric = true;
+ }
+
+ if ( (labelLength >= 2) &&
+ ( (label->getChar(0) & 0xff) == 0xfe) &&
+ ( (label->getChar(1) & 0xff) == 0xff) ) {
+ // UCS2 mode
+ i = 3;
+ step = 2;
+ if ( (label->getChar(labelLength-1) == 0) ) {
+ // prune the trailing null (0x000 for UCS2)
+ labelLength -= 2;
+ }
+ } else {
+ i = 0;
+ step = 1;
+ }
+ for (int j = 0; i < labelLength && j < 200; i += step) {
+ char c = label->getChar(i);
+ if ( (c < '0') || (c > '9') ) {
+ isNumeric = false;
+ }
+ if (c == '\\') {
+ label2->append("\\\\");
+ j += 2;
+ } else if (c == ')') {
+ label2->append("\\)");
+ } else if (c == '(') {
+ label2->append("\\(");
+ } else if (c < 0x20 || c > 0x7e) {
+ label2->append(GooString::format("\\{0:03o}", c));
+ j += 4;
+ } else {
+ label2->append(c);
+ ++j;
+ }
+ }
+ if (needParens) {
+ *needParens = !(isNumeric);
+ }
+ return label2;
+}
+
+// Write a DSC-compliant <textline>.
+void PSOutputDev::writePSTextLine(GooString *s) {
+ int i, j, step;
+ int c;
+
+ // - DSC comments must be printable ASCII; control chars and
+ // backslashes have to be escaped (we do cheap Unicode-to-ASCII
+ // conversion by simply ignoring the high byte)
+ // - lines are limited to 255 chars (we limit to 200 here to allow
+ // for the keyword, which was emitted by the caller)
+ // - lines that start with a left paren are treated as <text>
+ // instead of <textline>, so we escape a leading paren
+ if (s->getLength() >= 2 &&
+ (s->getChar(0) & 0xff) == 0xfe &&
+ (s->getChar(1) & 0xff) == 0xff) {
+ i = 3;
+ step = 2;
+ } else {
+ i = 0;
+ step = 1;
+ }
+ for (j = 0; i < s->getLength() && j < 200; i += step) {
+ c = s->getChar(i) & 0xff;
+ if (c == '\\') {
+ writePS("\\\\");
+ j += 2;
+ } else if (c < 0x20 || c > 0x7e || (j == 0 && c == '(')) {
+ writePSFmt("\\{0:03o}", c);
+ j += 4;
+ } else {
+ writePSChar(c);
+ ++j;
+ }
+ }
+ writePS("\n");
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PSOutputDev.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PSOutputDev.h
new file mode 100644
index 00000000000..7318cafdf2a
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PSOutputDev.h
@@ -0,0 +1,546 @@
+//========================================================================
+//
+// PSOutputDev.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006-2008, 2012, 2013, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007 Brad Hards <bradh@kde.org>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2009 Till Kamppeter <till.kamppeter@gmail.com>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009, 2011, 2015 William Bader <williambader@hotmail.com>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2011, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef PSOUTPUTDEV_H
+#define PSOUTPUTDEV_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include <stddef.h>
+#include "Object.h"
+#include "GfxState.h"
+#include "GlobalParams.h"
+#include "OutputDev.h"
+#include <set>
+#include <map>
+#include <vector>
+
+class GHooash;
+class PDFDoc;
+class XRef;
+class Function;
+class GfxPath;
+class GfxFont;
+class GfxColorSpace;
+class GfxSeparationColorSpace;
+class PDFRectangle;
+struct PST1FontName;
+struct PSFont8Info;
+struct PSFont16Enc;
+class PSOutCustomColor;
+class PSOutputDev;
+
+//------------------------------------------------------------------------
+// PSOutputDev
+//------------------------------------------------------------------------
+
+enum PSOutMode {
+ psModePS,
+ psModeEPS,
+ psModeForm
+};
+
+enum PSFileType {
+ psFile, // write to file
+ psPipe, // write to pipe
+ psStdout, // write to stdout
+ psGeneric // write to a generic stream
+};
+
+enum PSOutCustomCodeLocation {
+ psOutCustomDocSetup,
+ psOutCustomPageSetup
+};
+
+typedef void (*PSOutputFunc)(void *stream, const char *data, int len);
+
+typedef GooString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut,
+ PSOutCustomCodeLocation loc, int n,
+ void *data);
+
+class PSOutputDev: public OutputDev {
+public:
+
+ // Open a PostScript output file, and write the prolog.
+ // pages has to be sorted in increasing order
+ PSOutputDev(const char *fileName, PDFDoc *docA,
+ char *psTitleA,
+ const std::vector<int> &pages, PSOutMode modeA,
+ int paperWidthA = -1, int paperHeightA = -1,
+ GBool noCrop = gFalse,
+ GBool duplexA = gTrue,
+ int imgLLXA = 0, int imgLLYA = 0,
+ int imgURXA = 0, int imgURYA = 0,
+ GBool forceRasterizeA = gFalse,
+ GBool manualCtrlA = gFalse,
+ PSOutCustomCodeCbk customCodeCbkA = NULL,
+ void *customCodeCbkDataA = NULL);
+
+ // Open a PSOutputDev that will write to a generic stream.
+ // pages has to be sorted in increasing order
+ PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
+ char *psTitleA,
+ PDFDoc *docA,
+ const std::vector<int> &pages, PSOutMode modeA,
+ int paperWidthA = -1, int paperHeightA = -1,
+ GBool noCrop = gFalse,
+ GBool duplexA = gTrue,
+ int imgLLXA = 0, int imgLLYA = 0,
+ int imgURXA = 0, int imgURYA = 0,
+ GBool forceRasterizeA = gFalse,
+ GBool manualCtrlA = gFalse,
+ PSOutCustomCodeCbk customCodeCbkA = NULL,
+ void *customCodeCbkDataA = NULL);
+
+ // Destructor -- writes the trailer and closes the file.
+ virtual ~PSOutputDev();
+
+ // Check if file was successfully created.
+ virtual GBool isOk() { return ok; }
+
+ //---- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gFalse; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gFalse; }
+
+ // Does this device use tilingPatternFill()? If this returns false,
+ // tiling pattern fills will be reduced to a series of other drawing
+ // operations.
+ virtual GBool useTilingPatternFill() { return gTrue; }
+
+ // Does this device use functionShadedFill(), axialShadedFill(), and
+ // radialShadedFill()? If this returns false, these shaded fills
+ // will be reduced to a series of other drawing operations.
+ virtual GBool useShadedFills(int type)
+ { return type < 4 && level >= psLevel2; }
+
+ // Does this device use drawForm()? If this returns false,
+ // form-type XObjects will be interpreted (i.e., unrolled).
+ virtual GBool useDrawForm() { return preloadImagesForms; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gFalse; }
+
+ virtual GBool needClipToCropBox() { return mode == psModeEPS; }
+
+ //----- header/trailer (used only if manualCtrl is true)
+
+ // Write the document-level header.
+ void writeHeader(const std::vector<int> &pages,
+ PDFRectangle *mediaBox, PDFRectangle *cropBox,
+ int pageRotate, char *pstitle);
+
+ // Write the Xpdf procset.
+ void writeXpdfProcset();
+
+ // Write the trailer for the current page.
+ void writePageTrailer();
+
+ // Write the document trailer.
+ void writeTrailer();
+
+ //----- initialization and control
+
+ // Check to see if a page slice should be displayed. If this
+ // returns false, the page display is aborted. Typically, an
+ // OutputDev will use some alternate means to display the page
+ // before returning false.
+ virtual GBool checkPageSlice(Page *page, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+ void *annotDisplayDecideCbkData = NULL);
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state, XRef *xref);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state);
+ virtual void restoreState(GfxState *state);
+
+ //----- update graphics state
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32);
+ virtual void updateLineDash(GfxState *state);
+ virtual void updateFlatness(GfxState *state);
+ virtual void updateLineJoin(GfxState *state);
+ virtual void updateLineCap(GfxState *state);
+ virtual void updateMiterLimit(GfxState *state);
+ virtual void updateLineWidth(GfxState *state);
+ virtual void updateFillColorSpace(GfxState *state);
+ virtual void updateStrokeColorSpace(GfxState *state);
+ virtual void updateFillColor(GfxState *state);
+ virtual void updateStrokeColor(GfxState *state);
+ virtual void updateFillOverprint(GfxState *state);
+ virtual void updateStrokeOverprint(GfxState *state);
+ virtual void updateOverprintMode(GfxState *state);
+ virtual void updateTransfer(GfxState *state);
+
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+ virtual void updateTextMat(GfxState *state);
+ virtual void updateCharSpace(GfxState *state);
+ virtual void updateRender(GfxState *state);
+ virtual void updateRise(GfxState *state);
+ virtual void updateWordSpace(GfxState *state);
+ virtual void updateHorizScaling(GfxState *state);
+ virtual void updateTextPos(GfxState *state);
+ virtual void updateTextShift(GfxState *state, double shift);
+ virtual void saveTextPos(GfxState *state);
+ virtual void restoreTextPos(GfxState *state);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep);
+ virtual GBool functionShadedFill(GfxState *state,
+ GfxFunctionShading *shading);
+ virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/);
+ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/);
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+ virtual void eoClip(GfxState *state);
+ virtual void clipToStrokePath(GfxState *state);
+
+ //----- text drawing
+ virtual void drawString(GfxState *state, GooString *s);
+ virtual void beginTextObject(GfxState *state);
+ virtual void endTextObject(GfxState *state);
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg);
+ virtual void setSoftMaskFromImageMask(GfxState *state,
+ Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix);
+ virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ GBool maskInvert, GBool maskInterpolate);
+
+#if OPI_SUPPORT
+ //----- OPI functions
+ virtual void opiBegin(GfxState *state, Dict *opiDict);
+ virtual void opiEnd(GfxState *state, Dict *opiDict);
+#endif
+
+ //----- Type 3 font operators
+ virtual void type3D0(GfxState *state, double wx, double wy);
+ virtual void type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury);
+
+ //----- form XObjects
+ virtual void drawForm(Ref ref);
+
+ //----- PostScript XObjects
+ virtual void psXObject(Stream *psStream, Stream *level1Stream);
+
+ //----- miscellaneous
+ void setOffset(double x, double y)
+ { tx0 = x; ty0 = y; }
+ void setScale(double x, double y)
+ { xScale0 = x; yScale0 = y; }
+ void setRotate(int rotateA)
+ { rotate0 = rotateA; }
+ void setClip(double llx, double lly, double urx, double ury)
+ { clipLLX0 = llx; clipLLY0 = lly; clipURX0 = urx; clipURY0 = ury; }
+ void setUnderlayCbk(void (*cbk)(PSOutputDev *psOut, void *data),
+ void *data)
+ { underlayCbk = cbk; underlayCbkData = data; }
+ void setOverlayCbk(void (*cbk)(PSOutputDev *psOut, void *data),
+ void *data)
+ { overlayCbk = cbk; overlayCbkData = data; }
+ void setDisplayText(GBool display) { displayText = display; }
+
+ void setRasterAntialias(GBool a) { rasterAntialias = a; }
+ void setRasterResolution(double r) { rasterResolution = r; }
+ void setRasterMono(GBool b) { rasterMono = b; }
+ void setUncompressPreloadedImages(GBool b) { uncompressPreloadedImages = b; }
+
+ GBool getEmbedType1() const { return embedType1; }
+ GBool getEmbedTrueType() const { return embedTrueType; }
+ GBool getEmbedCIDPostScript() const { return embedCIDPostScript; }
+ GBool getEmbedCIDTrueType() const { return embedCIDTrueType; }
+ GBool getFontPassthrough() const { return fontPassthrough; }
+ GBool getOptimizeColorSpace() const { return optimizeColorSpace; }
+ void setEmbedType1(GBool b) { embedType1 = b; }
+ void setEmbedTrueType(GBool b) { embedTrueType = b; }
+ void setEmbedCIDPostScript(GBool b) { embedCIDPostScript = b; }
+ void setEmbedCIDTrueType(GBool b) { embedCIDTrueType = b; }
+ void setFontPassthrough(GBool b) { fontPassthrough = b; }
+ void setOptimizeColorSpace(GBool b) { optimizeColorSpace = b; }
+ void setPreloadImagesForms(GBool b) { preloadImagesForms = b; }
+ void setGenerateOPI(GBool b) { generateOPI = b; }
+ void setUseASCIIHex(GBool b) { useASCIIHex = b; }
+ void setUseBinary(GBool b) { useBinary = b; }
+
+private:
+
+ void init(PSOutputFunc outputFuncA, void *outputStreamA,
+ PSFileType fileTypeA, char *psTitleA, PDFDoc *doc,
+ const std::vector<int> &pages, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA, int paperWidthA, int paperHeightA,
+ GBool noCropA, GBool duplexA);
+ void postInit();
+ void setupResources(Dict *resDict);
+ void setupFonts(Dict *resDict);
+ void setupFont(GfxFont *font, Dict *parentResDict);
+ void setupEmbeddedType1Font(Ref *id, GooString *psName);
+ void setupExternalType1Font(GooString *fileName, GooString *psName);
+ void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GooString *psName);
+ void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GooString *psName);
+ void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GooString *psName);
+ void setupExternalTrueTypeFont(GfxFont *font, GooString *fileName,
+ GooString *psName);
+ void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GooString *psName);
+ void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GooString *psName,
+ GBool needVerticalMetrics);
+ void setupExternalCIDTrueTypeFont(GfxFont *font,
+ GooString *fileName,
+ GooString *psName,
+ GBool needVerticalMetrics);
+ void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GooString *psName);
+ void setupType3Font(GfxFont *font, GooString *psName, Dict *parentResDict);
+ GooString *makePSFontName(GfxFont *font, Ref *id);
+ void setupImages(Dict *resDict);
+ void setupImage(Ref id, Stream *str, GBool mask);
+ void setupForms(Dict *resDict);
+ void setupForm(Ref id, Object *strObj);
+ void addProcessColor(double c, double m, double y, double k);
+ void addCustomColor(GfxSeparationColorSpace *sepCS);
+ void doPath(GfxPath *path);
+ void maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert);
+ void doImageL1(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert);
+ void doImageL1Sep(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert);
+ void doImageL2(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert);
+ void doImageL3(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert);
+ void dumpColorSpaceL2(GfxColorSpace *colorSpace,
+ GBool genXform, GBool updateColors,
+ GBool map01);
+ GBool tilingPatternFillL1(GfxState *state, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep);
+ GBool tilingPatternFillL2(GfxState *state, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep);
+
+#if OPI_SUPPORT
+ void opiBegin20(GfxState *state, Dict *dict);
+ void opiBegin13(GfxState *state, Dict *dict);
+ void opiTransform(GfxState *state, double x0, double y0,
+ double *x1, double *y1);
+#endif
+ void cvtFunction(Function *func, GBool invertPSFunction = gFalse);
+ GooString *filterPSName(GooString *name);
+
+ // Write the document-level setup.
+ void writeDocSetup(PDFDoc *doc, Catalog *catalog, const std::vector<int> &pages, GBool duplexA);
+
+ void writePSChar(char c);
+ void writePS(const char *s);
+ void writePSBuf(const char *s, int len);
+ void writePSFmt(const char *fmt, ...);
+ void writePSString(GooString *s);
+ void writePSName(const char *s);
+ GooString *filterPSLabel(GooString *label, GBool *needParens=0);
+ void writePSTextLine(GooString *s);
+
+ PSLevel level; // PostScript level (1, 2, separation)
+ PSOutMode mode; // PostScript mode (PS, EPS, form)
+ int paperWidth; // width of paper, in pts
+ int paperHeight; // height of paper, in pts
+ GBool paperMatch; // true if paper size is set to match each page
+ int prevWidth; // width of previous page
+ // (only psModePSOrigPageSizes output mode)
+ int prevHeight; // height of previous page
+ // (only psModePSOrigPageSizes output mode)
+ int imgLLX, imgLLY, // imageable area, in pts
+ imgURX, imgURY;
+ GBool noCrop;
+ GBool duplex;
+ std::vector<int> pages;
+ char *psTitle;
+ GBool postInitDone; // true if postInit() was called
+
+ PSOutputFunc outputFunc;
+ void *outputStream;
+ PSFileType fileType; // file / pipe / stdout
+ GBool manualCtrl;
+ int seqPage; // current sequential page number
+ void (*underlayCbk)(PSOutputDev *psOut, void *data);
+ void *underlayCbkData;
+ void (*overlayCbk)(PSOutputDev *psOut, void *data);
+ void *overlayCbkData;
+ GooString *(*customCodeCbk)(PSOutputDev *psOut,
+ PSOutCustomCodeLocation loc, int n,
+ void *data);
+ void *customCodeCbkData;
+
+ PDFDoc *doc;
+ XRef *xref; // the xref table for this PDF file
+
+ Ref *fontIDs; // list of object IDs of all used fonts
+ int fontIDLen; // number of entries in fontIDs array
+ int fontIDSize; // size of fontIDs array
+ std::set<int> resourceIDs; // list of object IDs of objects containing Resources we've already set up
+ GooHash *fontNames; // all used font names
+ PST1FontName *t1FontNames; // font names for Type 1/1C fonts
+ int t1FontNameLen; // number of entries in t1FontNames array
+ int t1FontNameSize; // size of t1FontNames array
+ PSFont8Info *font8Info; // info for 8-bit fonts
+ int font8InfoLen; // number of entries in font8Info array
+ int font8InfoSize; // size of font8Info array
+ PSFont16Enc *font16Enc; // encodings for substitute 16-bit fonts
+ int font16EncLen; // number of entries in font16Enc array
+ int font16EncSize; // size of font16Enc array
+ Ref *imgIDs; // list of image IDs for in-memory images
+ int imgIDLen; // number of entries in imgIDs array
+ int imgIDSize; // size of imgIDs array
+ Ref *formIDs; // list of IDs for predefined forms
+ int formIDLen; // number of entries in formIDs array
+ int formIDSize; // size of formIDs array
+ int numSaves; // current number of gsaves
+ int numTilingPatterns; // current number of nested tiling patterns
+ int nextFunc; // next unique number to use for a function
+
+ GooList *paperSizes; // list of used paper sizes, if paperMatch
+ // is true [PSOutPaperSize]
+ std::map<int,int> pagePaperSize; // page num to paperSize entry mapping
+ double tx0, ty0; // global translation
+ double xScale0, yScale0; // global scaling
+ int rotate0; // rotation angle (0, 90, 180, 270)
+ double clipLLX0, clipLLY0,
+ clipURX0, clipURY0;
+ double tx, ty; // global translation for current page
+ double xScale, yScale; // global scaling for current page
+ int rotate; // rotation angle for current page
+ double epsX1, epsY1, // EPS bounding box (unrotated)
+ epsX2, epsY2;
+
+ GooString *embFontList; // resource comments for embedded fonts
+
+ int processColors; // used process colors
+ PSOutCustomColor // used custom colors
+ *customColors;
+
+ GBool haveTextClip; // set if text has been drawn with a
+ // clipping render mode
+
+ GBool inType3Char; // inside a Type 3 CharProc
+ GBool inUncoloredPattern; // inside a uncolored pattern (PaintType = 2)
+ GooString *t3String; // Type 3 content string
+ double t3WX, t3WY, // Type 3 character parameters
+ t3LLX, t3LLY, t3URX, t3URY;
+ GBool t3FillColorOnly; // operators should only use the fill color
+ GBool t3Cacheable; // cleared if char is not cacheable
+ GBool t3NeedsRestore; // set if a 'q' operator was issued
+ GBool forceRasterize; // forces the page to be rasterized into a image before printing
+ GBool displayText; // displayText
+ GBool rasterAntialias; // antialias on rasterize
+ GBool uncompressPreloadedImages;
+ double rasterResolution; // PostScript rasterization resolution (dpi)
+ GBool rasterMono; // true to do PostScript rasterization
+ // in monochrome (gray); false to do it
+ // in color (RGB/CMYK)
+ GBool embedType1; // embed Type 1 fonts?
+ GBool embedTrueType; // embed TrueType fonts?
+ GBool embedCIDPostScript; // embed CID PostScript fonts?
+ GBool embedCIDTrueType; // embed CID TrueType fonts?
+ GBool fontPassthrough; // pass all fonts through as-is?
+ GBool optimizeColorSpace; // false to keep gray RGB images in their original color space
+ // true to optimize gray images to DeviceGray color space
+ GBool preloadImagesForms; // preload PostScript images and forms into
+ // memory
+ GBool generateOPI; // generate PostScript OPI comments?
+ GBool useASCIIHex; // use ASCIIHex instead of ASCII85?
+ GBool useBinary; // use binary instead of hex
+
+#if OPI_SUPPORT
+ int opi13Nest; // nesting level of OPI 1.3 objects
+ int opi20Nest; // nesting level of OPI 2.0 objects
+#endif
+
+ GBool ok; // set up ok?
+
+ friend class WinPDFPrinter;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PSTokenizer.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PSTokenizer.cc
new file mode 100644
index 00000000000..05127f0d03c
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PSTokenizer.cc
@@ -0,0 +1,159 @@
+//========================================================================
+//
+// PSTokenizer.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
+// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "PSTokenizer.h"
+
+//------------------------------------------------------------------------
+
+// A '1' in this array means the character is white space. A '1' or
+// '2' means the character ends a name or command.
+static const char specialChars[256] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
+ 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
+};
+
+//------------------------------------------------------------------------
+
+PSTokenizer::PSTokenizer(int (*getCharFuncA)(void *), void *dataA) {
+ getCharFunc = getCharFuncA;
+ data = dataA;
+ charBuf = -1;
+}
+
+PSTokenizer::~PSTokenizer() {
+}
+
+GBool PSTokenizer::getToken(char *buf, int size, int *length) {
+ GBool comment, backslash;
+ int c;
+ int i;
+
+ // skip leading whitespace and comments
+ comment = gFalse;
+ while (1) {
+ if ((c = getChar()) == EOF) {
+ buf[0] = '\0';
+ *length = 0;
+ return gFalse;
+ }
+ if (comment) {
+ if (c == '\x0a' || c == '\x0d') {
+ comment = gFalse;
+ }
+ } else if (c == '%') {
+ comment = gTrue;
+ } else if (specialChars[c] != 1) {
+ break;
+ }
+ }
+
+ // Reserve room for terminating '\0'
+ size--;
+
+ // read a token
+ i = 0;
+ buf[i++] = c;
+ if (c == '(') {
+ backslash = gFalse;
+ while ((c = lookChar()) != EOF) {
+ consumeChar();
+ if (i < size) {
+ buf[i++] = c;
+ }
+ if (c == '\\') {
+ backslash = gTrue;
+ } else if (!backslash && c == ')') {
+ break;
+ } else {
+ backslash = gFalse;
+ }
+ }
+ } else if (c == '<') {
+ while ((c = lookChar()) != EOF) {
+ consumeChar();
+ if (i < size && specialChars[c] != 1) {
+ buf[i++] = c;
+ }
+ if (c == '>') {
+ break;
+ }
+ }
+ } else if (c != '[' && c != ']') {
+ while ((c = lookChar()) != EOF && !specialChars[c]) {
+ consumeChar();
+ if (i < size) {
+ buf[i++] = c;
+ }
+ }
+ }
+ // Zero terminate token string
+ buf[i] = '\0';
+ // Return length of token
+ *length = i;
+
+ return gTrue;
+}
+
+int PSTokenizer::lookChar() {
+ if (charBuf < 0) {
+ charBuf = (*getCharFunc)(data);
+ }
+ return charBuf;
+}
+
+void PSTokenizer::consumeChar() {
+ charBuf = -1;
+}
+
+int PSTokenizer::getChar() {
+ int c = charBuf;
+
+ if (c < 0) {
+ c = (*getCharFunc)(data);
+ } else {
+ charBuf = -1;
+ }
+ return c;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PSTokenizer.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PSTokenizer.h
new file mode 100644
index 00000000000..fc2f053d3f2
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PSTokenizer.h
@@ -0,0 +1,54 @@
+//========================================================================
+//
+// PSTokenizer.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef PSTOKENIZER_H
+#define PSTOKENIZER_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+
+//------------------------------------------------------------------------
+
+class PSTokenizer {
+public:
+
+ PSTokenizer(int (*getCharFuncA)(void *), void *dataA);
+ ~PSTokenizer();
+
+ // Get the next PostScript token. Returns false at end-of-stream.
+ GBool getToken(char *buf, int size, int *length);
+
+private:
+
+ int lookChar();
+ void consumeChar();
+ int getChar();
+
+ int (*getCharFunc)(void *);
+ void *data;
+ int charBuf;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Page.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Page.cc
new file mode 100644
index 00000000000..a4af3405b92
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Page.cc
@@ -0,0 +1,860 @@
+//========================================================================
+//
+// Page.cc
+//
+// Copyright 1996-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2005-2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006-2008 Pino Toscano <pino@kde.org>
+// Copyright (C) 2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
+// Copyright (C) 2006-2011, 2015 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2008 Iñigo Martínez <inigomartinez@gmail.com>
+// Copyright (C) 2008 Brad Hards <bradh@kde.org>
+// Copyright (C) 2008 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013, 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Jason Crain <jason@aquaticape.us>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2015 Philipp Reinkemeier <philipp.reinkemeier@offis.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <limits.h>
+#include "GlobalParams.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "PDFDoc.h"
+#include "XRef.h"
+#include "Link.h"
+#include "OutputDev.h"
+#include "Gfx.h"
+#include "GfxState.h"
+#include "Annot.h"
+#include "TextOutputDev.h"
+#include "Form.h"
+#include "Error.h"
+#include "Page.h"
+#include "Catalog.h"
+#include "Form.h"
+
+#if MULTITHREADED
+# define pageLocker() MutexLocker locker(&mutex)
+#else
+# define pageLocker()
+#endif
+//------------------------------------------------------------------------
+// PDFRectangle
+//------------------------------------------------------------------------
+
+void PDFRectangle::clipTo(PDFRectangle *rect) {
+ if (x1 < rect->x1) {
+ x1 = rect->x1;
+ } else if (x1 > rect->x2) {
+ x1 = rect->x2;
+ }
+ if (x2 < rect->x1) {
+ x2 = rect->x1;
+ } else if (x2 > rect->x2) {
+ x2 = rect->x2;
+ }
+ if (y1 < rect->y1) {
+ y1 = rect->y1;
+ } else if (y1 > rect->y2) {
+ y1 = rect->y2;
+ }
+ if (y2 < rect->y1) {
+ y2 = rect->y1;
+ } else if (y2 > rect->y2) {
+ y2 = rect->y2;
+ }
+}
+
+//------------------------------------------------------------------------
+// PageAttrs
+//------------------------------------------------------------------------
+
+PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
+ Object obj1;
+ PDFRectangle mBox;
+ const GBool isPage = dict->is("Page");
+
+ // get old/default values
+ if (attrs) {
+ mediaBox = attrs->mediaBox;
+ cropBox = attrs->cropBox;
+ haveCropBox = attrs->haveCropBox;
+ rotate = attrs->rotate;
+ attrs->resources.copy(&resources);
+ } else {
+ // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
+ // but some (non-compliant) PDF files don't specify a MediaBox
+ mediaBox.x1 = 0;
+ mediaBox.y1 = 0;
+ mediaBox.x2 = 612;
+ mediaBox.y2 = 792;
+ cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
+ haveCropBox = gFalse;
+ rotate = 0;
+ resources.initNull();
+ }
+
+ // media box
+ if (readBox(dict, "MediaBox", &mBox)) {
+ mediaBox = mBox;
+ }
+
+ // crop box
+ if (readBox(dict, "CropBox", &cropBox)) {
+ haveCropBox = gTrue;
+ }
+ if (!haveCropBox) {
+ cropBox = mediaBox;
+ }
+
+ if (isPage) {
+ // cropBox can not be bigger than mediaBox
+ if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1)
+ {
+ cropBox.x1 = mediaBox.x1;
+ cropBox.x2 = mediaBox.x2;
+ }
+ if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1)
+ {
+ cropBox.y1 = mediaBox.y1;
+ cropBox.y2 = mediaBox.y2;
+ }
+ }
+
+ // other boxes
+ bleedBox = cropBox;
+ readBox(dict, "BleedBox", &bleedBox);
+ trimBox = cropBox;
+ readBox(dict, "TrimBox", &trimBox);
+ artBox = cropBox;
+ readBox(dict, "ArtBox", &artBox);
+
+ // rotate
+ dict->lookup("Rotate", &obj1);
+ if (obj1.isInt()) {
+ rotate = obj1.getInt();
+ }
+ obj1.free();
+ while (rotate < 0) {
+ rotate += 360;
+ }
+ while (rotate >= 360) {
+ rotate -= 360;
+ }
+
+ // misc attributes
+ dict->lookup("LastModified", &lastModified);
+ dict->lookup("BoxColorInfo", &boxColorInfo);
+ dict->lookup("Group", &group);
+ dict->lookup("Metadata", &metadata);
+ dict->lookup("PieceInfo", &pieceInfo);
+ dict->lookup("SeparationInfo", &separationInfo);
+
+ // resource dictionary
+ dict->lookup("Resources", &obj1);
+ if (obj1.isDict()) {
+ resources.free();
+ obj1.copy(&resources);
+ }
+ obj1.free();
+}
+
+PageAttrs::~PageAttrs() {
+ lastModified.free();
+ boxColorInfo.free();
+ group.free();
+ metadata.free();
+ pieceInfo.free();
+ separationInfo.free();
+ resources.free();
+}
+
+void PageAttrs::clipBoxes() {
+ cropBox.clipTo(&mediaBox);
+ bleedBox.clipTo(&mediaBox);
+ trimBox.clipTo(&mediaBox);
+ artBox.clipTo(&mediaBox);
+}
+
+GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) {
+ PDFRectangle tmp;
+ double t;
+ Object obj1, obj2;
+ GBool ok;
+
+ dict->lookup(key, &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ ok = gTrue;
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isNum()) {
+ tmp.x1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ if (obj2.isNum()) {
+ tmp.y1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ if (obj2.isNum()) {
+ tmp.x2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ if (obj2.isNum()) {
+ tmp.y2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ if (tmp.x1 == 0 && tmp.x2 == 0 && tmp.y1 == 0 && tmp.y2 == 0)
+ ok = gFalse;
+ if (ok) {
+ if (tmp.x1 > tmp.x2) {
+ t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t;
+ }
+ if (tmp.y1 > tmp.y2) {
+ t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t;
+ }
+ *box = tmp;
+ }
+ } else {
+ ok = gFalse;
+ }
+ obj1.free();
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// Page
+//------------------------------------------------------------------------
+
+Page::Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form) {
+ Object tmp;
+
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+ ok = gTrue;
+ doc = docA;
+ xref = doc->getXRef();
+ num = numA;
+ duration = -1;
+ annots = NULL;
+
+ pageObj.initDict(pageDict);
+ pageRef = pageRefA;
+
+ // get attributes
+ attrs = attrsA;
+ attrs->clipBoxes();
+
+ // transtion
+ pageDict->lookupNF("Trans", &trans);
+ if (!(trans.isRef() || trans.isDict() || trans.isNull())) {
+ error(errSyntaxError, -1, "Page transition object (page {0:d}) is wrong type ({1:s})",
+ num, trans.getTypeName());
+ trans.free();
+ }
+
+ // duration
+ pageDict->lookupNF("Dur", &tmp);
+ if (!(tmp.isNum() || tmp.isNull())) {
+ error(errSyntaxError, -1, "Page duration object (page {0:d}) is wrong type ({1:s})",
+ num, tmp.getTypeName());
+ } else if (tmp.isNum()) {
+ duration = tmp.getNum();
+ }
+ tmp.free();
+
+ // annotations
+ pageDict->lookupNF("Annots", &annotsObj);
+ if (!(annotsObj.isRef() || annotsObj.isArray() || annotsObj.isNull())) {
+ error(errSyntaxError, -1, "Page annotations object (page {0:d}) is wrong type ({1:s})",
+ num, annotsObj.getTypeName());
+ annotsObj.free();
+ goto err2;
+ }
+
+ // contents
+ pageDict->lookupNF("Contents", &contents);
+ if (!(contents.isRef() || contents.isArray() ||
+ contents.isNull())) {
+ error(errSyntaxError, -1, "Page contents object (page {0:d}) is wrong type ({1:s})",
+ num, contents.getTypeName());
+ contents.free();
+ goto err1;
+ }
+
+ // thumb
+ pageDict->lookupNF("Thumb", &thumb);
+ if (!(thumb.isStream() || thumb.isNull() || thumb.isRef())) {
+ error(errSyntaxError, -1, "Page thumb object (page {0:d}) is wrong type ({1:s})",
+ num, thumb.getTypeName());
+ thumb.initNull();
+ }
+
+ // actions
+ pageDict->lookupNF("AA", &actions);
+ if (!(actions.isDict() || actions.isNull())) {
+ error(errSyntaxError, -1, "Page additional action object (page {0:d}) is wrong type ({1:s})",
+ num, actions.getTypeName());
+ actions.initNull();
+ }
+
+ return;
+
+ trans.initNull();
+ err2:
+ annotsObj.initNull();
+ err1:
+ contents.initNull();
+ ok = gFalse;
+}
+
+Page::~Page() {
+ delete attrs;
+ delete annots;
+ pageObj.free();
+ annotsObj.free();
+ contents.free();
+ trans.free();
+ thumb.free();
+ actions.free();
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+Dict *Page::getResourceDict() {
+ return attrs->getResourceDict();
+}
+
+Dict *Page::getResourceDictCopy(XRef *xrefA) {
+ pageLocker();
+ Dict *dict = attrs->getResourceDict();
+ return dict ? dict->copy(xrefA) : NULL;
+}
+
+void Page::replaceXRef(XRef *xrefA) {
+ Object obj1;
+ Dict *pageDict = pageObj.getDict()->copy(xrefA);
+ xref = xrefA;
+ trans.free();
+ pageDict->lookupNF("Trans", &trans);
+ annotsObj.free();
+ pageDict->lookupNF("Annots", &annotsObj);
+ contents.free();
+ pageDict->lookupNF("Contents", &contents);
+ if (contents.isArray()) {
+ contents.free();
+ pageDict->lookupNF("Contents", &obj1)->getArray()->copy(xrefA, &contents);
+ obj1.free();
+ }
+ thumb.free();
+ pageDict->lookupNF("Thumb", &thumb);
+ actions.free();
+ pageDict->lookupNF("AA", &actions);
+ pageDict->lookup("Resources", &obj1);
+ if (obj1.isDict()) {
+ attrs->replaceResource(obj1);
+ }
+ obj1.free();
+ delete pageDict;
+}
+
+Annots *Page::getAnnots(XRef *xrefA) {
+ if (!annots) {
+ Object obj;
+ annots = new Annots(doc, num, getAnnots(&obj, (xrefA == NULL) ? xref : xrefA));
+ obj.free();
+ }
+
+ return annots;
+}
+
+void Page::addAnnot(Annot *annot) {
+ Object obj1;
+ Object tmp;
+ Ref annotRef = annot->getRef ();
+
+ // Make sure we have annots before adding the new one
+ // even if it's an empty list so that we can safely
+ // call annots->appendAnnot(annot)
+ pageLocker();
+ getAnnots();
+
+ if (annotsObj.isNull()) {
+ Ref annotsRef;
+ // page doesn't have annots array,
+ // we have to create it
+
+ obj1.initArray(xref);
+ obj1.arrayAdd(tmp.initRef (annotRef.num, annotRef.gen));
+ tmp.free();
+
+ annotsRef = xref->addIndirectObject (&obj1);
+ annotsObj.initRef(annotsRef.num, annotsRef.gen);
+ pageObj.dictSet ("Annots", &annotsObj);
+ xref->setModifiedObject (&pageObj, pageRef);
+ } else {
+ getAnnots(&obj1);
+ if (obj1.isArray()) {
+ obj1.arrayAdd (tmp.initRef (annotRef.num, annotRef.gen));
+ if (annotsObj.isRef())
+ xref->setModifiedObject (&obj1, annotsObj.getRef());
+ else
+ xref->setModifiedObject (&pageObj, pageRef);
+ }
+ obj1.free();
+ }
+
+ // Popup annots are already handled by markup annots,
+ // so add to the list only Popup annots without a
+ // markup annotation associated.
+ if (annot->getType() != Annot::typePopup ||
+ static_cast<AnnotPopup*>(annot)->getParentNF()->isNull()) {
+ annots->appendAnnot(annot);
+ }
+ annot->setPage(num, gTrue);
+
+ AnnotMarkup *annotMarkup = dynamic_cast<AnnotMarkup*>(annot);
+ if (annotMarkup) {
+ AnnotPopup *annotPopup = annotMarkup->getPopup();
+ if (annotPopup)
+ addAnnot(annotPopup);
+ }
+}
+
+void Page::removeAnnot(Annot *annot) {
+ Ref annotRef = annot->getRef();
+ Object annArray;
+
+ pageLocker();
+ getAnnots(&annArray);
+ if (annArray.isArray()) {
+ int idx = -1;
+ // Get annotation position
+ for (int i = 0; idx == -1 && i < annArray.arrayGetLength(); ++i) {
+ Object tmp;
+ if (annArray.arrayGetNF(i, &tmp)->isRef()) {
+ Ref currAnnot = tmp.getRef();
+ if (currAnnot.num == annotRef.num && currAnnot.gen == annotRef.gen) {
+ idx = i;
+ }
+ }
+ tmp.free();
+ }
+
+ if (idx == -1) {
+ error(errInternal, -1, "Annotation doesn't belong to this page");
+ annArray.free();
+ return;
+ }
+ annots->removeAnnot(annot); // Gracefully fails on popup windows
+ annArray.arrayRemove(idx);
+ xref->removeIndirectObject(annotRef);
+
+ if (annotsObj.isRef()) {
+ xref->setModifiedObject (&annArray, annotsObj.getRef());
+ } else {
+ xref->setModifiedObject (&pageObj, pageRef);
+ }
+ }
+ annArray.free();
+ annot->removeReferencedObjects(); // Note: Might recurse in removeAnnot again
+ annot->setPage(0, gFalse);
+}
+
+Links *Page::getLinks() {
+ return new Links(getAnnots());
+}
+
+FormPageWidgets *Page::getFormWidgets() {
+ return new FormPageWidgets(getAnnots(), num, doc->getCatalog()->getForm());
+}
+
+void Page::display(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
+ void *annotDisplayDecideCbkData,
+ GBool copyXRef) {
+ displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing,
+ abortCheckCbk, abortCheckCbkData,
+ annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
+}
+
+Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData, XRef *xrefA) {
+ PDFRectangle *mediaBox, *cropBox;
+ PDFRectangle box;
+ Gfx *gfx;
+
+ rotate += getRotate();
+ if (rotate >= 360) {
+ rotate -= 360;
+ } else if (rotate < 0) {
+ rotate += 360;
+ }
+
+ makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(),
+ sliceX, sliceY, sliceW, sliceH, &box, &crop);
+ cropBox = getCropBox();
+ mediaBox = getMediaBox();
+
+ if (globalParams->getPrintCommands()) {
+ printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
+ mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2);
+ printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
+ cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
+ printf("***** Rotate = %d\n", attrs->getRotate());
+ }
+
+ if (!crop) {
+ crop = (box == *cropBox) && out->needClipToCropBox();
+ }
+ gfx = new Gfx(doc, out, num, attrs->getResourceDict(),
+ hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
+ rotate, abortCheckCbk, abortCheckCbkData, xrefA);
+
+ return gfx;
+}
+
+void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
+ void *annotDisplayDecideCbkData,
+ GBool copyXRef) {
+ Gfx *gfx;
+ Object obj;
+ Annots *annotList;
+ int i;
+
+ if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ printing,
+ abortCheckCbk, abortCheckCbkData,
+ annotDisplayDecideCbk, annotDisplayDecideCbkData)) {
+ return;
+ }
+ pageLocker();
+ XRef *localXRef = (copyXRef) ? xref->copy() : xref;
+ if (copyXRef) {
+ replaceXRef(localXRef);
+ }
+
+ gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ printing,
+ abortCheckCbk, abortCheckCbkData, localXRef);
+
+ contents.fetch(localXRef, &obj);
+ if (!obj.isNull()) {
+ gfx->saveState();
+ gfx->display(&obj);
+ gfx->restoreState();
+ } else {
+ // empty pages need to call dump to do any setup required by the
+ // OutputDev
+ out->dump();
+ }
+ obj.free();
+
+ // draw annotations
+ annotList = getAnnots();
+
+ if (annotList->getNumAnnots() > 0) {
+ if (globalParams->getPrintCommands()) {
+ printf("***** Annotations\n");
+ }
+ for (i = 0; i < annotList->getNumAnnots(); ++i) {
+ Annot *annot = annotList->getAnnot(i);
+ if ((annotDisplayDecideCbk &&
+ (*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) ||
+ !annotDisplayDecideCbk) {
+ annotList->getAnnot(i)->draw(gfx, printing);
+ }
+ }
+ out->dump();
+ }
+
+ delete gfx;
+ if (copyXRef) {
+ replaceXRef(doc->getXRef());
+ delete localXRef;
+ }
+}
+
+void Page::display(Gfx *gfx) {
+ Object obj;
+
+ contents.fetch(xref, &obj);
+ if (!obj.isNull()) {
+ gfx->saveState();
+ gfx->display(&obj);
+ gfx->restoreState();
+ }
+ obj.free();
+}
+
+GBool Page::loadThumb(unsigned char **data_out,
+ int *width_out, int *height_out,
+ int *rowstride_out)
+{
+ unsigned int pixbufdatasize;
+ int width, height, bits;
+ Object obj1, fetched_thumb;
+ Dict *dict;
+ GfxColorSpace *colorSpace;
+ GBool success = gFalse;
+ Stream *str;
+ GfxImageColorMap *colorMap;
+
+ /* Get stream dict */
+ pageLocker();
+ thumb.fetch(xref, &fetched_thumb);
+ if (!fetched_thumb.isStream()) {
+ fetched_thumb.free();
+ return gFalse;
+ }
+
+ dict = fetched_thumb.streamGetDict();
+ str = fetched_thumb.getStream();
+
+ if (!dict->lookupInt("Width", "W", &width))
+ goto fail1;
+ if (!dict->lookupInt("Height", "H", &height))
+ goto fail1;
+ if (!dict->lookupInt("BitsPerComponent", "BPC", &bits))
+ goto fail1;
+
+ /* Check for invalid dimensions and integer overflow. */
+ if (width <= 0 || height <= 0)
+ goto fail1;
+ if (width > INT_MAX / 3 / height)
+ goto fail1;
+ pixbufdatasize = width * height * 3;
+
+ /* Get color space */
+ dict->lookup ("ColorSpace", &obj1);
+ if (obj1.isNull ()) {
+ obj1.free ();
+ dict->lookup ("CS", &obj1);
+ }
+ colorSpace = GfxColorSpace::parse(NULL, &obj1, NULL, NULL);
+ obj1.free();
+ if (!colorSpace) {
+ fprintf (stderr, "Error: Cannot parse color space\n");
+ goto fail1;
+ }
+
+ dict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("D", &obj1);
+ }
+ colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
+ obj1.free();
+ if (!colorMap->isOk()) {
+ fprintf (stderr, "Error: invalid colormap\n");
+ delete colorMap;
+ goto fail1;
+ }
+
+ if (data_out) {
+ unsigned char *pixbufdata = (unsigned char *) gmalloc(pixbufdatasize);
+ unsigned char *p = pixbufdata;
+ ImageStream *imgstr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgstr->reset();
+ for (int row = 0; row < height; ++row) {
+ for (int col = 0; col < width; ++col) {
+ Guchar pix[gfxColorMaxComps];
+ GfxRGB rgb;
+
+ imgstr->getPixel(pix);
+ colorMap->getRGB(pix, &rgb);
+
+ *p++ = colToByte(rgb.r);
+ *p++ = colToByte(rgb.g);
+ *p++ = colToByte(rgb.b);
+ }
+ }
+ *data_out = pixbufdata;
+ imgstr->close();
+ delete imgstr;
+ }
+
+ success = gTrue;
+
+ if (width_out)
+ *width_out = width;
+ if (height_out)
+ *height_out = height;
+ if (rowstride_out)
+ *rowstride_out = width * 3;
+
+ delete colorMap;
+ fail1:
+ fetched_thumb.free();
+
+ return success;
+}
+
+void Page::makeBox(double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool upsideDown,
+ double sliceX, double sliceY, double sliceW, double sliceH,
+ PDFRectangle *box, GBool *crop) {
+ PDFRectangle *mediaBox, *cropBox, *baseBox;
+ double kx, ky;
+
+ mediaBox = getMediaBox();
+ cropBox = getCropBox();
+ if (sliceW >= 0 && sliceH >= 0) {
+ baseBox = useMediaBox ? mediaBox : cropBox;
+ kx = 72.0 / hDPI;
+ ky = 72.0 / vDPI;
+ if (rotate == 90) {
+ if (upsideDown) {
+ box->x1 = baseBox->x1 + ky * sliceY;
+ box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
+ } else {
+ box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
+ box->x2 = baseBox->x2 - ky * sliceY;
+ }
+ box->y1 = baseBox->y1 + kx * sliceX;
+ box->y2 = baseBox->y1 + kx * (sliceX + sliceW);
+ } else if (rotate == 180) {
+ box->x1 = baseBox->x2 - kx * (sliceX + sliceW);
+ box->x2 = baseBox->x2 - kx * sliceX;
+ if (upsideDown) {
+ box->y1 = baseBox->y1 + ky * sliceY;
+ box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
+ } else {
+ box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
+ box->y2 = baseBox->y2 - ky * sliceY;
+ }
+ } else if (rotate == 270) {
+ if (upsideDown) {
+ box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
+ box->x2 = baseBox->x2 - ky * sliceY;
+ } else {
+ box->x1 = baseBox->x1 + ky * sliceY;
+ box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
+ }
+ box->y1 = baseBox->y2 - kx * (sliceX + sliceW);
+ box->y2 = baseBox->y2 - kx * sliceX;
+ } else {
+ box->x1 = baseBox->x1 + kx * sliceX;
+ box->x2 = baseBox->x1 + kx * (sliceX + sliceW);
+ if (upsideDown) {
+ box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
+ box->y2 = baseBox->y2 - ky * sliceY;
+ } else {
+ box->y1 = baseBox->y1 + ky * sliceY;
+ box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
+ }
+ }
+ } else if (useMediaBox) {
+ *box = *mediaBox;
+ } else {
+ *box = *cropBox;
+ *crop = gFalse;
+ }
+}
+
+void Page::processLinks(OutputDev *out) {
+ Links *links;
+ int i;
+
+ links = getLinks();
+ for (i = 0; i < links->getNumLinks(); ++i) {
+ out->processLink(links->getLink(i));
+ }
+ delete links;
+}
+
+void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool upsideDown) {
+ GfxState *state;
+ int i;
+ rotate += getRotate();
+ if (rotate >= 360) {
+ rotate -= 360;
+ } else if (rotate < 0) {
+ rotate += 360;
+ }
+ state = new GfxState(hDPI, vDPI,
+ useMediaBox ? getMediaBox() : getCropBox(),
+ rotate, upsideDown);
+ for (i = 0; i < 6; ++i) {
+ ctm[i] = state->getCTM()[i];
+ }
+ delete state;
+}
+
+LinkAction* Page::getAdditionalAction(PageAdditionalActionsType type) {
+ Object additionalActionsObject;
+ LinkAction *linkAction = NULL;
+
+ if (actions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+ const char *key = (type == actionOpenPage ? "O" :
+ type == actionClosePage ? "C" : NULL);
+
+ Object actionObject;
+
+ if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+ linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
+ actionObject.free();
+ }
+
+ additionalActionsObject.free();
+
+ return linkAction;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Page.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Page.h
new file mode 100644
index 00000000000..2aaabae9b16
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Page.h
@@ -0,0 +1,287 @@
+//========================================================================
+//
+// Page.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2006 Pino Toscano <pino@kde.org>
+// Copyright (C) 2006, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2008 Iñigo Martínez <inigomartinez@gmail.com>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef PAGE_H
+#define PAGE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "Object.h"
+#include "goo/GooMutex.h"
+
+class Dict;
+class PDFDoc;
+class XRef;
+class OutputDev;
+class Links;
+class LinkAction;
+class Annots;
+class Annot;
+class Gfx;
+class FormPageWidgets;
+class Form;
+
+//------------------------------------------------------------------------
+
+class PDFRectangle {
+public:
+ double x1, y1, x2, y2;
+
+ PDFRectangle() { x1 = y1 = x2 = y2 = 0; }
+ PDFRectangle(double x1A, double y1A, double x2A, double y2A)
+ { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; }
+ GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; }
+ GBool contains(double x, double y) { return x1 <= x && x <= x2 && y1 <= y && y <= y2; }
+ void clipTo(PDFRectangle *rect);
+
+ bool operator==(const PDFRectangle &rect) const { return x1 == rect.x1 && y1 == rect.y1 && x2 == rect.x2 && y2 == rect.y2; }
+};
+
+//------------------------------------------------------------------------
+// PageAttrs
+//------------------------------------------------------------------------
+
+class PageAttrs {
+public:
+
+ // Construct a new PageAttrs object by merging a dictionary
+ // (of type Pages or Page) into another PageAttrs object. If
+ // <attrs> is NULL, uses defaults.
+ PageAttrs(PageAttrs *attrs, Dict *dict);
+
+ // Destructor.
+ ~PageAttrs();
+
+ // Accessors.
+ PDFRectangle *getMediaBox() { return &mediaBox; }
+ PDFRectangle *getCropBox() { return &cropBox; }
+ GBool isCropped() { return haveCropBox; }
+ PDFRectangle *getBleedBox() { return &bleedBox; }
+ PDFRectangle *getTrimBox() { return &trimBox; }
+ PDFRectangle *getArtBox() { return &artBox; }
+ int getRotate() { return rotate; }
+ GooString *getLastModified()
+ { return lastModified.isString()
+ ? lastModified.getString() : (GooString *)NULL; }
+ Dict *getBoxColorInfo()
+ { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; }
+ Dict *getGroup()
+ { return group.isDict() ? group.getDict() : (Dict *)NULL; }
+ Stream *getMetadata()
+ { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; }
+ Dict *getPieceInfo()
+ { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; }
+ Dict *getSeparationInfo()
+ { return separationInfo.isDict()
+ ? separationInfo.getDict() : (Dict *)NULL; }
+ Dict *getResourceDict()
+ { return resources.isDict() ? resources.getDict() : (Dict *)NULL; }
+ void replaceResource(Object obj1)
+ { resources.free(); obj1.copy(&resources); }
+
+ // Clip all other boxes to the MediaBox.
+ void clipBoxes();
+
+private:
+
+ GBool readBox(Dict *dict, const char *key, PDFRectangle *box);
+
+ PDFRectangle mediaBox;
+ PDFRectangle cropBox;
+ GBool haveCropBox;
+ PDFRectangle bleedBox;
+ PDFRectangle trimBox;
+ PDFRectangle artBox;
+ int rotate;
+ Object lastModified;
+ Object boxColorInfo;
+ Object group;
+ Object metadata;
+ Object pieceInfo;
+ Object separationInfo;
+ Object resources;
+};
+
+//------------------------------------------------------------------------
+// Page
+//------------------------------------------------------------------------
+
+class Page {
+public:
+
+ // Constructor.
+ Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form);
+
+ // Destructor.
+ ~Page();
+
+ // Is page valid?
+ GBool isOk() { return ok; }
+
+ // Get page parameters.
+ int getNum() { return num; }
+ PDFRectangle *getMediaBox() { return attrs->getMediaBox(); }
+ PDFRectangle *getCropBox() { return attrs->getCropBox(); }
+ GBool isCropped() { return attrs->isCropped(); }
+ double getMediaWidth()
+ { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; }
+ double getMediaHeight()
+ { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; }
+ double getCropWidth()
+ { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; }
+ double getCropHeight()
+ { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; }
+ PDFRectangle *getBleedBox() { return attrs->getBleedBox(); }
+ PDFRectangle *getTrimBox() { return attrs->getTrimBox(); }
+ PDFRectangle *getArtBox() { return attrs->getArtBox(); }
+ int getRotate() { return attrs->getRotate(); }
+ GooString *getLastModified() { return attrs->getLastModified(); }
+ Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); }
+ Dict *getGroup() { return attrs->getGroup(); }
+ Stream *getMetadata() { return attrs->getMetadata(); }
+ Dict *getPieceInfo() { return attrs->getPieceInfo(); }
+ Dict *getSeparationInfo() { return attrs->getSeparationInfo(); }
+ PDFDoc *getDoc() { return doc; }
+ Ref getRef() { return pageRef; }
+
+ // Get resource dictionary.
+ Dict *getResourceDict();
+ Dict *getResourceDictCopy(XRef *xrefA);
+
+ // Get annotations array.
+ Object *getAnnots(Object *obj, XRef *xrefA = NULL) { return annotsObj.fetch((xrefA == NULL) ? xref : xrefA, obj); }
+ // Add a new annotation to the page
+ void addAnnot(Annot *annot);
+ // Remove an existing annotation from the page
+ void removeAnnot(Annot *annot);
+
+ // Return a list of links.
+ Links *getLinks();
+
+ // Return a list of annots. It will be valid until the page is destroyed
+ Annots *getAnnots(XRef *xrefA = NULL);
+
+ // Get contents.
+ Object *getContents(Object *obj) { return contents.fetch(xref, obj); }
+
+ // Get thumb.
+ Object *getThumb(Object *obj) { return thumb.fetch(xref, obj); }
+ GBool loadThumb(unsigned char **data, int *width, int *height, int *rowstride);
+
+ // Get transition.
+ Object *getTrans(Object *obj) { return trans.fetch(xref, obj); }
+
+ // Get form.
+ FormPageWidgets *getFormWidgets();
+
+ // Get duration, the maximum length of time, in seconds,
+ // that the page is displayed before the presentation automatically
+ // advances to the next page
+ double getDuration() { return duration; }
+
+ // Get actions
+ Object *getActions(Object *obj) { return actions.fetch(xref, obj); }
+
+ enum PageAdditionalActionsType {
+ actionOpenPage, ///< Performed when opening the page
+ actionClosePage, ///< Performed when closing the page
+ };
+
+ LinkAction *getAdditionalAction(PageAdditionalActionsType type);
+
+ Gfx *createGfx(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData, XRef *xrefA = NULL);
+
+ // Display a page.
+ void display(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+ void *annotDisplayDecideCbkData = NULL,
+ GBool copyXRef = gFalse);
+
+ // Display part of a page.
+ void displaySlice(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+ void *annotDisplayDecideCbkData = NULL,
+ GBool copyXRef = gFalse);
+
+ void display(Gfx *gfx);
+
+ void makeBox(double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool upsideDown,
+ double sliceX, double sliceY, double sliceW, double sliceH,
+ PDFRectangle *box, GBool *crop);
+
+ void processLinks(OutputDev *out);
+
+ // Get the page's default CTM.
+ void getDefaultCTM(double *ctm, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool upsideDown);
+
+private:
+ // replace xref
+ void replaceXRef(XRef *xrefA);
+
+ PDFDoc *doc;
+ XRef *xref; // the xref table for this PDF file
+ Object pageObj; // page dictionary
+ Ref pageRef; // page reference
+ int num; // page number
+ PageAttrs *attrs; // page attributes
+ Annots *annots; // annotations
+ Object annotsObj; // annotations array
+ Object contents; // page contents
+ Object thumb; // page thumbnail
+ Object trans; // page transition
+ Object actions; // page additional actions
+ double duration; // page duration
+ GBool ok; // true if page is valid
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo.cc
new file mode 100644
index 00000000000..3153377f6d3
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo.cc
@@ -0,0 +1,230 @@
+//========================================================================
+//
+// This file is under the GPLv2 or later license
+//
+// Copyright (C) 2005-2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005, 2009, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2011 Simon Kellner <kellner@kit.edu>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "PageLabelInfo.h"
+#include "PageLabelInfo_p.h"
+
+PageLabelInfo::Interval::Interval(Object *dict, int baseA) {
+ Object obj;
+
+ style = None;
+ if (dict->dictLookup("S", &obj)->isName()) {
+ if (obj.isName("D")) {
+ style = Arabic;
+ } else if (obj.isName("R")) {
+ style = UppercaseRoman;
+ } else if (obj.isName("r")) {
+ style = LowercaseRoman;
+ } else if (obj.isName("A")) {
+ style = UppercaseLatin;
+ } else if (obj.isName("a")) {
+ style = LowercaseLatin;
+ }
+ }
+ obj.free();
+
+ if (dict->dictLookup("P", &obj)->isString())
+ prefix = obj.getString()->copy();
+ else
+ prefix = new GooString("");
+ obj.free();
+
+ if (dict->dictLookup("St", &obj)->isInt())
+ first = obj.getInt();
+ else
+ first = 1;
+ obj.free();
+
+ base = baseA;
+}
+
+PageLabelInfo::Interval::~Interval() {
+ delete prefix;
+}
+
+PageLabelInfo::PageLabelInfo(Object *tree, int numPages) {
+ int i;
+ Interval *interval, *next;
+
+ parse(tree);
+
+ for (i = 0; i < intervals.getLength(); i++) {
+ interval = (Interval *) intervals.get(i);
+
+ if (i + 1 < intervals.getLength()) {
+ next = (Interval *) intervals.get(i + 1);
+ interval->length = next->base - interval->base;
+ } else {
+ interval->length = numPages - interval->base;
+ }
+ if (interval->length < 0) interval->length = 0;
+ }
+}
+
+PageLabelInfo::~PageLabelInfo() {
+ int i;
+ for (i = 0; i < intervals.getLength(); ++i) {
+ delete (Interval*)intervals.get(i);
+ }
+}
+
+void PageLabelInfo::parse(Object *tree) {
+ Object nums, obj;
+ Object kids, kid, limits, low, high;
+ int i, base;
+ Interval *interval;
+
+ // leaf node
+ if (tree->dictLookup("Nums", &nums)->isArray()) {
+ for (i = 0; i < nums.arrayGetLength(); i += 2) {
+ if (!nums.arrayGet(i, &obj)->isInt()) {
+ obj.free();
+ continue;
+ }
+ base = obj.getInt();
+ obj.free();
+ if (!nums.arrayGet(i + 1, &obj)->isDict()) {
+ obj.free();
+ continue;
+ }
+
+ interval = new Interval(&obj, base);
+ obj.free();
+ intervals.append(interval);
+ }
+ }
+ nums.free();
+
+ if (tree->dictLookup("Kids", &kids)->isArray()) {
+ for (i = 0; i < kids.arrayGetLength(); ++i) {
+ if (kids.arrayGet(i, &kid)->isDict())
+ parse(&kid);
+ kid.free();
+ }
+ }
+ kids.free();
+}
+
+GBool PageLabelInfo::labelToIndex(GooString *label, int *index)
+{
+ Interval *interval;
+ char *str = label->getCString(), *end;
+ int prefixLength;
+ int i, number;
+
+ for (i = 0; i < intervals.getLength(); i++) {
+ interval = (Interval *) intervals.get(i);
+ const int base = interval->base;
+ prefixLength = interval->prefix->getLength();
+ if (label->cmpN(interval->prefix, prefixLength) != 0)
+ continue;
+
+ switch (interval->style) {
+ case Interval::Arabic:
+ number = strtol(str + prefixLength, &end, 10);
+ if (*end == '\0' && number - interval->first < interval->length) {
+ *index = base + number - interval->first;
+ return gTrue;
+ }
+ break;
+ case Interval::LowercaseRoman:
+ case Interval::UppercaseRoman:
+ number = fromRoman(str + prefixLength);
+ if (number >= 0 && number - interval->first < interval->length) {
+ *index = base + number - interval->first;
+ return gTrue;
+ }
+ break;
+ case Interval::UppercaseLatin:
+ case Interval::LowercaseLatin:
+ number = fromLatin(str + prefixLength);
+ if (number >= 0 && number - interval->first < interval->length) {
+ *index = base + number - interval->first;
+ return gTrue;
+ }
+ break;
+ case Interval::None:
+ break;
+ }
+ }
+
+ return gFalse;
+}
+
+GBool PageLabelInfo::indexToLabel(int index, GooString *label)
+{
+ char buffer[32];
+ int i, base, number;
+ Interval *interval;
+ GooString number_string;
+
+ base = 0;
+ interval = NULL;
+ for (i = 0; i < intervals.getLength(); i++) {
+ interval = (Interval *) intervals.get(i);
+ if (base <= index && index < base + interval->length)
+ break;
+ base += interval->length;
+ }
+
+ if (i == intervals.getLength())
+ return gFalse;
+
+ number = index - base + interval->first;
+ switch (interval->style) {
+ case Interval::Arabic:
+ snprintf (buffer, sizeof(buffer), "%d", number);
+ number_string.append(buffer);
+ break;
+ case Interval::LowercaseRoman:
+ toRoman(number, &number_string, gFalse);
+ break;
+ case Interval::UppercaseRoman:
+ toRoman(number, &number_string, gTrue);
+ break;
+ case Interval::LowercaseLatin:
+ toLatin(number, &number_string, gFalse);
+ break;
+ case Interval::UppercaseLatin:
+ toLatin(number, &number_string, gTrue);
+ break;
+ case Interval::None:
+ break;
+ }
+
+ label->clear();
+ label->append(interval->prefix);
+ if (label->hasUnicodeMarker()) {
+ int i, len;
+ char ucs2_char[2];
+
+ /* Convert the ascii number string to ucs2 and append. */
+ len = number_string.getLength ();
+ ucs2_char[0] = 0;
+ for (i = 0; i < len; ++i) {
+ ucs2_char[1] = number_string.getChar(i);
+ label->append(ucs2_char, 2);
+ }
+ } else {
+ label->append(&number_string);
+ }
+
+ return gTrue;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo.h
new file mode 100644
index 00000000000..960e710069d
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo.h
@@ -0,0 +1,51 @@
+//========================================================================
+//
+// This file is under the GPLv2 or later license
+//
+// Copyright (C) 2005-2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "goo/gtypes.h"
+#include "goo/GooList.h"
+#include "goo/GooString.h"
+#include "Object.h"
+
+class PageLabelInfo {
+public:
+ PageLabelInfo(Object *tree, int numPages);
+ ~PageLabelInfo();
+ GBool labelToIndex(GooString *label, int *index);
+ GBool indexToLabel(int index, GooString *label);
+
+private:
+ void parse(Object *tree);
+
+private:
+ struct Interval {
+ Interval(Object *dict, int baseA);
+ ~Interval();
+ GooString *prefix;
+ enum NumberStyle {
+ None,
+ Arabic,
+ LowercaseRoman,
+ UppercaseRoman,
+ UppercaseLatin,
+ LowercaseLatin
+ } style;
+ int first, base, length;
+ };
+
+ GooList intervals;
+};
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo_p.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo_p.h
new file mode 100644
index 00000000000..6cd5220d372
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageLabelInfo_p.h
@@ -0,0 +1,153 @@
+//========================================================================
+//
+// This file is under the GPLv2 or later license
+//
+// Copyright (C) 2005-2006 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005, 2009, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2011 Simon Kellner <kellner@kit.edu>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+/* http://mathworld.wolfram.com/RomanNumerals.html */
+
+#include "goo/GooString.h"
+#include "Error.h"
+
+static int fromRoman(const char *buffer) {
+ int digit_value, prev_digit_value, value;
+ int i;
+
+ prev_digit_value = INT_MAX;
+ value = 0;
+ for (i = 0; buffer[i] != '\0'; i++) {
+ switch (buffer[i]) {
+ case 'm':
+ case 'M':
+ digit_value = 1000;
+ break;
+ case 'd':
+ case 'D':
+ digit_value = 500;
+ break;
+ case 'c':
+ case 'C':
+ digit_value = 100;
+ break;
+ case 'l':
+ case 'L':
+ digit_value = 50;
+ break;
+ case 'x':
+ case 'X':
+ digit_value = 10;
+ break;
+ case 'v':
+ case 'V':
+ digit_value = 5;
+ break;
+ case 'i':
+ case 'I':
+ digit_value = 1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (digit_value <= prev_digit_value)
+ value += digit_value;
+ else
+ value += digit_value - prev_digit_value * 2;
+ prev_digit_value = digit_value;
+ }
+
+ return value;
+}
+
+static void toRoman(int number, GooString *str, GBool uppercase) {
+ static const char uppercaseNumerals[] = "IVXLCDM";
+ static const char lowercaseNumerals[] = "ivxlcdm";
+ int divisor;
+ int i, j, k;
+ const char *wh;
+
+ if (number >= 4000) {
+ error(errUnimplemented, -1, "Conversion to roman numberals of numbers >= 4000 not implemented");
+ return;
+ }
+
+ if (uppercase)
+ wh = uppercaseNumerals;
+ else
+ wh = lowercaseNumerals;
+
+ divisor = 1000;
+ for (k = 3; k >= 0; k--) {
+ i = number / divisor;
+ number = number % divisor;
+
+ switch (i) {
+ case 0:
+ break;
+ case 5:
+ str->append(wh[2 * k + 1]);
+ break;
+ case 9:
+ str->append(wh[2 * k + 0]);
+ str->append(wh[ 2 * k + 2]);
+ break;
+ case 4:
+ str->append(wh[2 * k + 0]);
+ str->append(wh[2 * k + 1]);
+ break;
+ default:
+ if (i > 5) {
+ str->append(wh[2 * k + 1]);
+ i -= 5;
+ }
+ for (j = 0; j < i; j++) {
+ str->append(wh[2 * k + 0]);
+ }
+ }
+
+ divisor = divisor / 10;
+ }
+}
+
+static int fromLatin(const char *buffer)
+{
+ int count;
+ const char *p;
+
+ for (p = buffer; *p; p++) {
+ if (*p != buffer[0])
+ return -1;
+ }
+
+ count = p - buffer;
+ if (buffer[0] >= 'a' && buffer[0] <= 'z')
+ return 26 * (count - 1) + buffer[0] - 'a' + 1;
+ if (buffer[0] >= 'A' && buffer[0] <= 'Z')
+ return 26 * (count - 1) + buffer[0] - 'A' + 1;
+
+ return -1;
+}
+
+static void toLatin(int number, GooString *str, GBool uppercase) {
+ char base, letter;
+ int i, count;
+
+ if (uppercase)
+ base = 'A';
+ else
+ base = 'a';
+
+ count = (number - 1) / 26 + 1;
+ letter = base + (number - 1) % 26;
+
+ for (i = 0; i < count; i++)
+ str->append(letter);
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PageTransition.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageTransition.cc
new file mode 100644
index 00000000000..441634c039f
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageTransition.cc
@@ -0,0 +1,138 @@
+/* PageTransition.cc
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
+ * Copyright (C) 2010, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "PageTransition.h"
+
+//------------------------------------------------------------------------
+// PageTransition
+//------------------------------------------------------------------------
+
+PageTransition::PageTransition (Object *trans) {
+ Object obj;
+ Dict *dict;
+
+ type = transitionReplace;
+ duration = 1;
+ alignment = transitionHorizontal;
+ direction = transitionInward;
+ angle = 0;
+ scale = 1.0;
+ rectangular = gFalse;
+ ok = gTrue;
+
+ if (!trans || !trans->isDict ()) {
+ ok = gFalse;
+ return;
+ }
+
+ dict = trans->getDict();
+
+ // get type
+ if (dict->lookup("S", &obj)->isName()) {
+ const char *s = obj.getName();
+
+ if (strcmp("R", s) == 0)
+ type = transitionReplace;
+ else if (strcmp("Split", s) == 0)
+ type = transitionSplit;
+ else if (strcmp("Blinds", s) == 0)
+ type = transitionBlinds;
+ else if (strcmp("Box", s) == 0)
+ type = transitionBox;
+ else if (strcmp("Wipe", s) == 0)
+ type = transitionWipe;
+ else if (strcmp("Dissolve", s) == 0)
+ type = transitionDissolve;
+ else if (strcmp("Glitter", s) == 0)
+ type = transitionGlitter;
+ else if (strcmp("Fly", s) == 0)
+ type = transitionFly;
+ else if (strcmp("Push", s) == 0)
+ type = transitionPush;
+ else if (strcmp("Cover", s) == 0)
+ type = transitionCover;
+ else if (strcmp("Uncover", s) == 0)
+ type = transitionUncover;
+ else if (strcmp("Fade", s) == 0)
+ type = transitionFade;
+ }
+ obj.free();
+
+ // get duration
+ if (dict->lookup("D", &obj)->isInt()) {
+ duration = obj.getInt();
+ }
+ obj.free();
+
+ // get alignment
+ if (dict->lookup("Dm", &obj)->isName()) {
+ const char *dm = obj.getName();
+
+ if (strcmp("H", dm) == 0)
+ alignment = transitionHorizontal;
+ else if (strcmp("V", dm) == 0)
+ alignment = transitionVertical;
+ }
+ obj.free();
+
+ // get direction
+ if (dict->lookup("M", &obj)->isName()) {
+ const char *m = obj.getName();
+
+ if (strcmp("I", m) == 0)
+ direction = transitionInward;
+ else if (strcmp("O", m) == 0)
+ direction = transitionOutward;
+ }
+ obj.free();
+
+ // get angle
+ if (dict->lookup("Di", &obj)->isInt()) {
+ angle = obj.getInt();
+ }
+ obj.free();
+
+ if (dict->lookup("Di", &obj)->isName()) {
+ if (strcmp("None", obj.getName()) == 0)
+ angle = 0;
+ }
+ obj.free();
+
+ // get scale
+ if (dict->lookup("SS", &obj)->isNum()) {
+ scale = obj.getNum();
+ }
+ obj.free();
+
+ // get rectangular
+ if (dict->lookup("B", &obj)->isBool()) {
+ rectangular = obj.getBool();
+ }
+ obj.free();
+}
+
+PageTransition::~PageTransition()
+{
+}
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PageTransition.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageTransition.h
new file mode 100644
index 00000000000..e892c6c5051
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PageTransition.h
@@ -0,0 +1,104 @@
+/* PageTransition.cc
+ * Copyright (C) 2005, Net Integration Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PAGE_TRANSITION_H
+#define PAGE_TRANSITION_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+
+//------------------------------------------------------------------------
+// PageTransition
+//------------------------------------------------------------------------
+
+// if changed remember to keep in sync with frontend enums
+enum PageTransitionType {
+ transitionReplace = 0,
+ transitionSplit,
+ transitionBlinds,
+ transitionBox,
+ transitionWipe,
+ transitionDissolve,
+ transitionGlitter,
+ transitionFly,
+ transitionPush,
+ transitionCover,
+ transitionUncover,
+ transitionFade
+};
+
+// if changed remember to keep in sync with frontend enums
+enum PageTransitionAlignment {
+ transitionHorizontal = 0,
+ transitionVertical
+};
+
+// if changed remember to keep in sync with frontend enums
+enum PageTransitionDirection {
+ transitionInward = 0,
+ transitionOutward
+};
+
+class PageTransition {
+public:
+ // Construct a Page Transition.
+ PageTransition (Object *trans);
+
+ // Destructor.
+ ~PageTransition ();
+
+ // Was the Page Transition created successfully?
+ GBool isOk() { return ok; }
+
+ // Get type
+ PageTransitionType getType() { return type; }
+
+ // Get duration
+ int getDuration() { return duration;}
+
+ // Get alignment
+ PageTransitionAlignment getAlignment() { return alignment; }
+
+ // Get direction
+ PageTransitionDirection getDirection() { return direction; }
+
+ // Get angle
+ int getAngle() { return angle; }
+
+ // Get scale
+ double getScale() { return scale; }
+
+ // Is rectangular?
+ GBool isRectangular() { return rectangular; }
+
+private:
+
+ PageTransitionType type; // transition style
+ int duration; // duration of the effect in seconds
+ PageTransitionAlignment alignment; // dimension of the effect
+ PageTransitionDirection direction; // direction of motion
+ int angle; // direction in degrees
+ double scale; // scale
+ GBool rectangular; // is the area to be flown in rectangular?
+ GBool ok; // set if created successfully
+};
+
+#endif /* PAGE_TRANSITION_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Parser.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Parser.cc
new file mode 100644
index 00000000000..28a54607f5c
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Parser.cc
@@ -0,0 +1,325 @@
+//========================================================================
+//
+// Parser.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2009, 201, 2010, 2013, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Decrypt.h"
+#include "Parser.h"
+#include "XRef.h"
+#include "Error.h"
+
+// Max number of nested objects. This is used to catch infinite loops
+// in the object structure. And also technically valid files with
+// lots of nested arrays that made us consume all the stack
+#define recursionLimit 500
+
+Parser::Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA) {
+ xref = xrefA;
+ lexer = lexerA;
+ inlineImg = 0;
+ allowStreams = allowStreamsA;
+ lexer->getObj(&buf1);
+ lexer->getObj(&buf2);
+}
+
+Parser::~Parser() {
+ buf1.free();
+ buf2.free();
+ delete lexer;
+}
+
+Object *Parser::getObj(Object *obj, int recursion)
+{
+ return getObj(obj, gFalse, NULL, cryptRC4, 0, 0, 0, recursion);
+}
+
+Object *Parser::getObj(Object *obj, GBool simpleOnly,
+ Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength,
+ int objNum, int objGen, int recursion,
+ GBool strict) {
+ char *key;
+ Stream *str;
+ Object obj2;
+ int num;
+ DecryptStream *decrypt;
+ GooString *s, *s2;
+ int c;
+
+ // refill buffer after inline image data
+ if (inlineImg == 2) {
+ buf1.free();
+ buf2.free();
+ lexer->getObj(&buf1);
+ lexer->getObj(&buf2);
+ inlineImg = 0;
+ }
+
+ // array
+ if (!simpleOnly && likely(recursion < recursionLimit) && buf1.isCmd("[")) {
+ shift();
+ obj->initArray(xref);
+ while (!buf1.isCmd("]") && !buf1.isEOF())
+ obj->arrayAdd(getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength,
+ objNum, objGen, recursion + 1));
+ if (buf1.isEOF()) {
+ error(errSyntaxError, getPos(), "End of file inside array");
+ if (strict) goto err;
+ }
+ shift();
+
+ // dictionary or stream
+ } else if (!simpleOnly && likely(recursion < recursionLimit) && buf1.isCmd("<<")) {
+ shift(objNum);
+ obj->initDict(xref);
+ while (!buf1.isCmd(">>") && !buf1.isEOF()) {
+ if (!buf1.isName()) {
+ error(errSyntaxError, getPos(), "Dictionary key must be a name object");
+ if (strict) goto err;
+ shift();
+ } else {
+ // buf1 might go away in shift(), so construct the key
+ key = copyString(buf1.getName());
+ shift();
+ if (buf1.isEOF() || buf1.isError()) {
+ gfree(key);
+ if (strict && buf1.isError()) goto err;
+ break;
+ }
+ obj->dictAdd(key, getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1));
+ }
+ }
+ if (buf1.isEOF()) {
+ error(errSyntaxError, getPos(), "End of file inside dictionary");
+ if (strict) goto err;
+ }
+ // stream objects are not allowed inside content streams or
+ // object streams
+ if (buf2.isCmd("stream")) {
+ if (allowStreams && (str = makeStream(obj, fileKey, encAlgorithm, keyLength,
+ objNum, objGen, recursion + 1,
+ strict))) {
+ obj->initStream(str);
+ } else {
+ obj->free();
+ obj->initError();
+ }
+ } else {
+ shift();
+ }
+
+ // indirect reference or integer
+ } else if (buf1.isInt()) {
+ num = buf1.getInt();
+ shift();
+ if (buf1.isInt() && buf2.isCmd("R")) {
+ obj->initRef(num, buf1.getInt());
+ shift();
+ shift();
+ } else {
+ obj->initInt(num);
+ }
+
+ // string
+ } else if (buf1.isString() && fileKey) {
+ s = buf1.getString();
+ s2 = new GooString();
+ obj2.initNull();
+ decrypt = new DecryptStream(new MemStream(s->getCString(), 0,
+ s->getLength(), &obj2),
+ fileKey, encAlgorithm, keyLength,
+ objNum, objGen);
+ decrypt->reset();
+ while ((c = decrypt->getChar()) != EOF) {
+ s2->append((char)c);
+ }
+ delete decrypt;
+ obj->initString(s2);
+ shift();
+
+ // simple object
+ } else {
+ // avoid re-allocating memory for complex objects like strings by
+ // shallow copy of <buf1> to <obj> and nulling <buf1> so that
+ // subsequent buf1.free() won't free this memory
+ buf1.shallowCopy(obj);
+ buf1.initNull();
+ shift();
+ }
+
+ return obj;
+
+err:
+ obj->free();
+ obj->initError();
+ return obj;
+
+}
+
+Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength,
+ int objNum, int objGen, int recursion,
+ GBool strict) {
+ Object obj;
+ BaseStream *baseStr;
+ Stream *str;
+ Goffset length;
+ Goffset pos, endPos;
+
+ // get stream start position
+ lexer->skipToNextLine();
+ if (!(str = lexer->getStream())) {
+ return NULL;
+ }
+ pos = str->getPos();
+
+ // get length
+ dict->dictLookup("Length", &obj, recursion);
+ if (obj.isInt()) {
+ length = obj.getInt();
+ obj.free();
+ } else if (obj.isInt64()) {
+ length = obj.getInt64();
+ obj.free();
+ } else {
+ error(errSyntaxError, getPos(), "Bad 'Length' attribute in stream");
+ obj.free();
+ if (strict) return NULL;
+ length = 0;
+ }
+
+ // check for length in damaged file
+ if (xref && xref->getStreamEnd(pos, &endPos)) {
+ length = endPos - pos;
+ }
+
+ // in badly damaged PDF files, we can run off the end of the input
+ // stream immediately after the "stream" token
+ if (!lexer->getStream()) {
+ return NULL;
+ }
+ baseStr = lexer->getStream()->getBaseStream();
+
+ // skip over stream data
+ if (Lexer::LOOK_VALUE_NOT_CACHED != lexer->lookCharLastValueCached) {
+ // take into account the fact that we've cached one value
+ pos = pos - 1;
+ lexer->lookCharLastValueCached = Lexer::LOOK_VALUE_NOT_CACHED;
+ }
+ lexer->setPos(pos + length);
+
+ // refill token buffers and check for 'endstream'
+ shift(); // kill '>>'
+ shift("endstream", objNum); // kill 'stream'
+ if (buf1.isCmd("endstream")) {
+ shift();
+ } else {
+ error(errSyntaxError, getPos(), "Missing 'endstream' or incorrect stream length");
+ if (strict) return NULL;
+ if (xref && lexer->getStream()) {
+ // shift until we find the proper endstream or we change to another object or reach eof
+ length = lexer->getPos() - pos;
+ if (buf1.isCmd("endstream")) {
+ obj.initInt64(length);
+ dict->dictSet("Length", &obj);
+ obj.free();
+ }
+ } else {
+ // When building the xref we can't use it so use this
+ // kludge for broken PDF files: just add 5k to the length, and
+ // hope its enough
+ length += 5000;
+ }
+ }
+
+ // make base stream
+ str = baseStr->makeSubStream(pos, gTrue, length, dict);
+
+ // handle decryption
+ if (fileKey) {
+ str = new DecryptStream(str, fileKey, encAlgorithm, keyLength,
+ objNum, objGen);
+ }
+
+ // get filters
+ str = str->addFilters(dict, recursion);
+
+ return str;
+}
+
+void Parser::shift(int objNum) {
+ if (inlineImg > 0) {
+ if (inlineImg < 2) {
+ ++inlineImg;
+ } else {
+ // in a damaged content stream, if 'ID' shows up in the middle
+ // of a dictionary, we need to reset
+ inlineImg = 0;
+ }
+ } else if (buf2.isCmd("ID")) {
+ lexer->skipChar(); // skip char after 'ID' command
+ inlineImg = 1;
+ }
+ buf1.free();
+ buf2.shallowCopy(&buf1);
+ if (inlineImg > 0) // don't buffer inline image data
+ buf2.initNull();
+ else
+ lexer->getObj(&buf2, objNum);
+}
+
+void Parser::shift(const char *cmdA, int objNum) {
+ if (inlineImg > 0) {
+ if (inlineImg < 2) {
+ ++inlineImg;
+ } else {
+ // in a damaged content stream, if 'ID' shows up in the middle
+ // of a dictionary, we need to reset
+ inlineImg = 0;
+ }
+ } else if (buf2.isCmd("ID")) {
+ lexer->skipChar(); // skip char after 'ID' command
+ inlineImg = 1;
+ }
+ buf1.free();
+ buf2.shallowCopy(&buf1);
+ if (inlineImg > 0) {
+ buf2.initNull();
+ } else if (buf1.isCmd(cmdA)) {
+ lexer->getObj(&buf2, objNum);
+ } else {
+ lexer->getObj(&buf2, cmdA, objNum);
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Parser.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Parser.h
new file mode 100644
index 00000000000..1ce9445e19d
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Parser.h
@@ -0,0 +1,82 @@
+//========================================================================
+//
+// Parser.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2010, 2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Lexer.h"
+
+//------------------------------------------------------------------------
+// Parser
+//------------------------------------------------------------------------
+
+class Parser {
+public:
+
+ // Constructor.
+ Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA);
+
+ // Destructor.
+ ~Parser();
+
+ // Get the next object from the input stream. If <simpleOnly> is
+ // true, do not parse compound objects (arrays, dictionaries, or
+ // streams).
+ Object *getObj(Object *obj, GBool simpleOnly = gFalse,
+ Guchar *fileKey = NULL,
+ CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0,
+ int objNum = 0, int objGen = 0, int recursion = 0,
+ GBool strict = gFalse);
+
+ Object *getObj(Object *obj, int recursion);
+
+ // Get stream.
+ Stream *getStream() { return lexer->getStream(); }
+
+ // Get current position in file.
+ Goffset getPos() { return lexer->getPos(); }
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Lexer *lexer; // input stream
+ GBool allowStreams; // parse stream objects?
+ Object buf1, buf2; // next two tokens
+ int inlineImg; // set when inline image data is encountered
+
+ Stream *makeStream(Object *dict, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength,
+ int objNum, int objGen, int recursion,
+ GBool strict);
+ void shift(int objNum = -1);
+ void shift(const char *cmdA, int objNum);
+};
+
+#endif
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PopplerCache.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PopplerCache.cc
new file mode 100644
index 00000000000..6018a77b70f
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PopplerCache.cc
@@ -0,0 +1,163 @@
+//========================================================================
+//
+// PopplerCache.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright (C) 2009 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2009, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+//
+//========================================================================
+
+#include "PopplerCache.h"
+
+#include "XRef.h"
+
+PopplerCacheKey::~PopplerCacheKey()
+{
+}
+
+PopplerCacheItem::~PopplerCacheItem()
+{
+}
+
+PopplerCache::PopplerCache(int cacheSizeA)
+{
+ cacheSize = cacheSizeA;
+ keys = new PopplerCacheKey*[cacheSize];
+ items = new PopplerCacheItem*[cacheSize];
+ lastValidCacheIndex = -1;
+}
+
+PopplerCache::~PopplerCache()
+{
+ for (int i = 0; i <= lastValidCacheIndex; ++i) {
+ delete keys[i];
+ delete items[i];
+ }
+ delete[] keys;
+ delete[] items;
+}
+
+PopplerCacheItem *PopplerCache::lookup(const PopplerCacheKey &key)
+{
+ if (lastValidCacheIndex < 0)
+ return 0;
+
+ if (*keys[0] == key) {
+ return items[0];
+ }
+ for (int i = 1; i <= lastValidCacheIndex; i++) {
+ if (*keys[i] == key) {
+ PopplerCacheKey *keyHit = keys[i];
+ PopplerCacheItem *itemHit = items[i];
+
+ for (int j = i; j > 0; j--) {
+ keys[j] = keys[j - 1];
+ items[j] = items[j - 1];
+ }
+
+ keys[0] = keyHit;
+ items[0] = itemHit;
+ return itemHit;
+ }
+ }
+ return 0;
+}
+
+void PopplerCache::put(PopplerCacheKey *key, PopplerCacheItem *item)
+{
+ int movingStartIndex = lastValidCacheIndex + 1;
+ if (lastValidCacheIndex == cacheSize - 1) {
+ delete keys[lastValidCacheIndex];
+ delete items[lastValidCacheIndex];
+ movingStartIndex = cacheSize - 1;
+ } else {
+ lastValidCacheIndex++;
+ }
+ for (int i = movingStartIndex; i > 0; i--) {
+ keys[i] = keys[i - 1];
+ items[i] = items[i - 1];
+ }
+ keys[0] = key;
+ items[0] = item;
+}
+
+int PopplerCache::size()
+{
+ return cacheSize;
+}
+
+int PopplerCache::numberOfItems()
+{
+ return lastValidCacheIndex + 1;
+}
+
+PopplerCacheItem *PopplerCache::item(int index)
+{
+ return items[index];
+}
+
+PopplerCacheKey *PopplerCache::key(int index)
+{
+ return keys[index];
+}
+
+class ObjectKey : public PopplerCacheKey {
+ public:
+ ObjectKey(int numA, int genA) : num(numA), gen(genA)
+ {
+ }
+
+ bool operator==(const PopplerCacheKey &key) const
+ {
+ const ObjectKey *k = static_cast<const ObjectKey*>(&key);
+ return k->num == num && k->gen == gen;
+ }
+
+ int num, gen;
+};
+
+class ObjectItem : public PopplerCacheItem {
+ public:
+ ObjectItem(Object *obj)
+ {
+ obj->copy(&item);
+ }
+
+ ~ObjectItem()
+ {
+ item.free();
+ }
+
+ Object item;
+};
+
+PopplerObjectCache::PopplerObjectCache(int cacheSize, XRef *xrefA) {
+ cache = new PopplerCache (cacheSize);
+ xref = xrefA;
+}
+
+PopplerObjectCache::~PopplerObjectCache() {
+ delete cache;
+}
+
+Object *PopplerObjectCache::put(const Ref &ref) {
+ Object obj;
+ xref->fetch(ref.num, ref.gen, &obj);
+
+ ObjectKey *key = new ObjectKey(ref.num, ref.gen);
+ ObjectItem *item = new ObjectItem(&obj);
+ cache->put(key, item);
+ obj.free();
+
+ return &item->item;
+}
+
+Object *PopplerObjectCache::lookup(const Ref &ref, Object *obj) {
+ ObjectKey key(ref.num, ref.gen);
+ ObjectItem *item = static_cast<ObjectItem *>(cache->lookup(key));
+
+ return item ? item->item.copy(obj) : obj->initNull();
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PopplerCache.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PopplerCache.h
new file mode 100644
index 00000000000..74010a2fa6b
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PopplerCache.h
@@ -0,0 +1,78 @@
+//========================================================================
+//
+// PopplerCache.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright (C) 2009 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2009, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+//
+//========================================================================
+
+#ifndef POPPLER_CACHE_H
+#define POPPLER_CACHE_H
+
+#include "Object.h"
+
+class PopplerCacheItem
+{
+ public:
+ virtual ~PopplerCacheItem();
+};
+
+class PopplerCacheKey
+{
+ public:
+ virtual ~PopplerCacheKey();
+ virtual bool operator==(const PopplerCacheKey &key) const = 0;
+};
+
+class PopplerCache
+{
+ public:
+ PopplerCache(int cacheSizeA);
+ ~PopplerCache();
+
+ /* The item returned is owned by the cache */
+ PopplerCacheItem *lookup(const PopplerCacheKey &key);
+
+ /* The key and item pointers ownership is taken by the cache */
+ void put(PopplerCacheKey *key, PopplerCacheItem *item);
+
+ /* The max size of the cache */
+ int size();
+
+ /* The number of items in the cache */
+ int numberOfItems();
+
+ /* The n-th item in the cache */
+ PopplerCacheItem *item(int index);
+
+ /* The n-th key in the cache */
+ PopplerCacheKey *key(int index);
+
+ private:
+ PopplerCache(const PopplerCache &cache); // not allowed
+
+ PopplerCacheKey **keys;
+ PopplerCacheItem **items;
+ int lastValidCacheIndex;
+ int cacheSize;
+};
+
+class PopplerObjectCache
+{
+ public:
+ PopplerObjectCache (int cacheSizeA, XRef *xrefA);
+ ~PopplerObjectCache();
+
+ Object *put(const Ref &ref);
+ Object *lookup(const Ref &ref, Object *obj);
+
+ private:
+ XRef *xref;
+ PopplerCache *cache;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PreScanOutputDev.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/PreScanOutputDev.cc
new file mode 100644
index 00000000000..b2af18d86b8
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PreScanOutputDev.cc
@@ -0,0 +1,369 @@
+//========================================================================
+//
+// PreScanOutputDev.cc
+//
+// Copyright 2005 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2010, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2011, 2014 William Bader <williambader@hotmail.com>
+// Copyright (C) 2011, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2011 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <math.h>
+#include "GlobalParams.h"
+#include "Gfx.h"
+#include "GfxFont.h"
+#include "Link.h"
+#include "Catalog.h"
+#include "Page.h"
+#include "PreScanOutputDev.h"
+
+//------------------------------------------------------------------------
+// PreScanOutputDev
+//------------------------------------------------------------------------
+
+PreScanOutputDev::PreScanOutputDev(PDFDoc *docA) {
+ level = globalParams->getPSLevel();
+ doc = docA;
+ clearStats();
+}
+
+PreScanOutputDev::~PreScanOutputDev() {
+}
+
+void PreScanOutputDev::startPage(int /*pageNum*/, GfxState * /*state*/, XRef * /*xref*/) {
+}
+
+void PreScanOutputDev::endPage() {
+}
+
+void PreScanOutputDev::stroke(GfxState *state) {
+ double *dash;
+ int dashLen;
+ double dashStart;
+
+ check(state->getStrokeColorSpace(), state->getStrokeColor(),
+ state->getStrokeOpacity(), state->getBlendMode());
+ state->getLineDash(&dash, &dashLen, &dashStart);
+ if (dashLen != 0) {
+ gdi = gFalse;
+ }
+}
+
+void PreScanOutputDev::fill(GfxState *state) {
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+}
+
+void PreScanOutputDev::eoFill(GfxState *state) {
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+}
+
+GBool PreScanOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *catalog, Object *str,
+ double *pmat, int paintType, int /*tilingType*/, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep) {
+ if (paintType == 1) {
+ GBool tilingNeeded = (x1 - x0 != 1 || y1 - y0 != 1);
+ if (tilingNeeded) {
+ inTilingPatternFill++;
+ }
+ gfx->drawForm(str, resDict, mat, bbox);
+ if (tilingNeeded) {
+ inTilingPatternFill--;
+ }
+ } else {
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+ }
+ return gTrue;
+}
+
+GBool PreScanOutputDev::functionShadedFill(GfxState *state,
+ GfxFunctionShading *shading) {
+ if (shading->getColorSpace()->getMode() != csDeviceGray &&
+ shading->getColorSpace()->getMode() != csCalGray) {
+ gray = gFalse;
+ }
+ mono = gFalse;
+ if (state->getFillOpacity() != 1 ||
+ state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ return gTrue;
+}
+
+GBool PreScanOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/) {
+ if (shading->getColorSpace()->getMode() != csDeviceGray &&
+ shading->getColorSpace()->getMode() != csCalGray) {
+ gray = gFalse;
+ }
+ mono = gFalse;
+ if (state->getFillOpacity() != 1 ||
+ state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ return gTrue;
+}
+
+GBool PreScanOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/) {
+ if (shading->getColorSpace()->getMode() != csDeviceGray &&
+ shading->getColorSpace()->getMode() != csCalGray) {
+ gray = gFalse;
+ }
+ mono = gFalse;
+ if (state->getFillOpacity() != 1 ||
+ state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ return gTrue;
+}
+
+void PreScanOutputDev::clip(GfxState * /*state*/) {
+ //~ check for a rectangle "near" the edge of the page;
+ //~ else set gdi to false
+}
+
+void PreScanOutputDev::eoClip(GfxState * /*state*/) {
+ //~ see clip()
+}
+
+void PreScanOutputDev::beginStringOp(GfxState *state) {
+ int render;
+ GfxFont *font;
+ double m11, m12, m21, m22;
+ GBool simpleTTF;
+
+ render = state->getRender();
+ if (!(render & 1)) {
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+ }
+ if ((render & 3) == 1 || (render & 3) == 2) {
+ check(state->getStrokeColorSpace(), state->getStrokeColor(),
+ state->getStrokeOpacity(), state->getBlendMode());
+ }
+
+ font = state->getFont();
+ state->getFontTransMat(&m11, &m12, &m21, &m22);
+ //~ this should check for external fonts that are non-TrueType
+ simpleTTF = fabs(m11 + m22) < 0.01 &&
+ m11 > 0 &&
+ fabs(m12) < 0.01 &&
+ fabs(m21) < 0.01 &&
+ fabs(state->getHorizScaling() - 1) < 0.001 &&
+ (font->getType() == fontTrueType ||
+ font->getType() == fontTrueTypeOT);
+ if (simpleTTF) {
+ //~ need to create a FoFiTrueType object, and check for a Unicode cmap
+ }
+ if (state->getRender() != 0 || !simpleTTF) {
+ gdi = gFalse;
+ }
+}
+
+void PreScanOutputDev::endStringOp(GfxState * /*state*/) {
+}
+
+GBool PreScanOutputDev::beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/,
+ double /*dx*/, double /*dy*/,
+ CharCode /*code*/, Unicode * /*u*/, int /*uLen*/) {
+ // return false so all Type 3 chars get rendered (no caching)
+ return gFalse;
+}
+
+void PreScanOutputDev::endType3Char(GfxState * /*state*/) {
+}
+
+void PreScanOutputDev::drawImageMask(GfxState *state, Object * /*ref*/, Stream *str,
+ int width, int height, GBool /*invert*/,
+ GBool /*interpolate*/, GBool inlineImg) {
+ int i, j;
+
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+ gdi = gFalse;
+ if ((level == psLevel1 || level == psLevel1Sep) &&
+ (state->getFillColorSpace()->getMode() == csPattern || inTilingPatternFill > 0)) {
+ patternImgMask = gTrue;
+ }
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ str->close();
+ }
+}
+
+void PreScanOutputDev::drawImage(GfxState *state, Object * /*ref*/, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool /*interpolate*/, int * /*maskColors*/, GBool inlineImg) {
+ GfxColorSpace *colorSpace;
+ int i, j;
+
+ colorSpace = colorMap->getColorSpace();
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ }
+ if (colorSpace->getMode() == csDeviceGray ||
+ colorSpace->getMode() == csCalGray) {
+ if (colorMap->getBits() > 1) {
+ mono = gFalse;
+ }
+ } else {
+ gray = gFalse;
+ mono = gFalse;
+ }
+ if (state->getFillOpacity() != 1 ||
+ state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ gdi = gFalse;
+ if ((level == psLevel1 || level == psLevel1Sep) &&
+ inTilingPatternFill > 0) {
+ patternImgMask = gTrue;
+ }
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ str->close();
+ }
+}
+
+void PreScanOutputDev::drawMaskedImage(GfxState *state, Object * /*ref*/,
+ Stream * /*str*/,
+ int /*width*/, int /*height*/,
+ GfxImageColorMap *colorMap,
+ GBool /*interpolate*/,
+ Stream * /*maskStr*/,
+ int /*maskWidth*/, int /*maskHeight*/,
+ GBool /*maskInvert*/, GBool /*maskInterpolate*/) {
+ GfxColorSpace *colorSpace;
+
+ colorSpace = colorMap->getColorSpace();
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ }
+ if (colorSpace->getMode() == csDeviceGray ||
+ colorSpace->getMode() == csCalGray) {
+ if (colorMap->getBits() > 1) {
+ mono = gFalse;
+ }
+ } else {
+ gray = gFalse;
+ mono = gFalse;
+ }
+ if (state->getFillOpacity() != 1 ||
+ state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ gdi = gFalse;
+}
+
+void PreScanOutputDev::drawSoftMaskedImage(GfxState * /*state*/, Object * /*ref*/,
+ Stream * /*str*/,
+ int /*width*/, int /*height*/,
+ GfxImageColorMap *colorMap,
+ GBool /*interpolate*/,
+ Stream * /*maskStr*/,
+ int /*maskWidth*/, int /*maskHeight*/,
+ GfxImageColorMap * /*maskColorMap*/,
+ GBool /*maskInterpolate*/) {
+ GfxColorSpace *colorSpace;
+
+ colorSpace = colorMap->getColorSpace();
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ }
+ if (colorSpace->getMode() != csDeviceGray &&
+ colorSpace->getMode() != csCalGray) {
+ gray = gFalse;
+ }
+ mono = gFalse;
+ transparency = gTrue;
+ gdi = gFalse;
+}
+
+void PreScanOutputDev::beginTransparencyGroup(
+ GfxState * /*state*/, double * /*bbox*/,
+ GfxColorSpace * /*blendingColorSpace*/,
+ GBool /*isolated*/, GBool /*knockout*/,
+ GBool /*forSoftMask*/) {
+ gdi = gFalse;
+}
+
+void PreScanOutputDev::paintTransparencyGroup(GfxState *state, double * /*bbox*/)
+{
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+}
+
+void PreScanOutputDev::setSoftMask(GfxState * /*state*/, double * /*bbox*/, GBool /*alpha*/,
+ Function * /*transferFunc*/, GfxColor * /*backdropColor*/)
+{
+ transparency = gTrue;
+}
+
+void PreScanOutputDev::check(GfxColorSpace *colorSpace, GfxColor *color,
+ double opacity, GfxBlendMode blendMode) {
+ GfxRGB rgb;
+
+ if (colorSpace->getMode() == csPattern) {
+ mono = gFalse;
+ gray = gFalse;
+ gdi = gFalse;
+ } else {
+ colorSpace->getRGB(color, &rgb);
+ if (rgb.r != rgb.g || rgb.g != rgb.b || rgb.b != rgb.r) {
+ mono = gFalse;
+ gray = gFalse;
+ } else if (!((rgb.r == 0 && rgb.g == 0 && rgb.b == 0) ||
+ (rgb.r == gfxColorComp1 &&
+ rgb.g == gfxColorComp1 &&
+ rgb.b == gfxColorComp1))) {
+ mono = gFalse;
+ }
+ }
+ if (opacity != 1 || blendMode != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+}
+
+void PreScanOutputDev::clearStats() {
+ mono = gTrue;
+ gray = gTrue;
+ transparency = gFalse;
+ gdi = gTrue;
+ patternImgMask = gFalse;
+ inTilingPatternFill = 0;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/PreScanOutputDev.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/PreScanOutputDev.h
new file mode 100644
index 00000000000..50fcbf22f73
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/PreScanOutputDev.h
@@ -0,0 +1,182 @@
+//========================================================================
+//
+// PreScanOutputDev.h
+//
+// Copyright 2005 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2011, 2014 William Bader <williambader@hotmail.com>
+// Copyright (C) 2011, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2011 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef PRESCANOUTPUTDEV_H
+#define PRESCANOUTPUTDEV_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "Object.h"
+#include "GfxState.h"
+#include "GlobalParams.h"
+#include "OutputDev.h"
+
+//------------------------------------------------------------------------
+// PreScanOutputDev
+//------------------------------------------------------------------------
+
+class PreScanOutputDev: public OutputDev {
+public:
+
+ // Constructor.
+ PreScanOutputDev(PDFDoc *docA);
+
+ // Destructor.
+ virtual ~PreScanOutputDev();
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gTrue; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
+ // Does this device use tilingPatternFill()? If this returns false,
+ // tiling pattern fills will be reduced to a series of other drawing
+ // operations.
+ virtual GBool useTilingPatternFill() { return gTrue; }
+
+ // Does this device use functionShadedFill(), axialShadedFill(), and
+ // radialShadedFill()? If this returns false, these shaded fills
+ // will be reduced to a series of other drawing operations.
+ virtual GBool useShadedFills(int type) { return gTrue; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gTrue; }
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state, XRef *xref);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep);
+ virtual GBool functionShadedFill(GfxState *state,
+ GfxFunctionShading *shading);
+ virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax);
+ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading, double tMin, double tMax);
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+ virtual void eoClip(GfxState *state);
+
+ //----- text drawing
+ virtual void beginStringOp(GfxState *state);
+ virtual void endStringOp(GfxState *state);
+ virtual GBool beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen);
+ virtual void endType3Char(GfxState *state);
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ GBool maskInvert, GBool maskInterpolate);
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate);
+
+ //----- transparency groups and soft masks
+ virtual void beginTransparencyGroup(GfxState *state, double *bbox,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ GBool forSoftMask);
+ virtual void paintTransparencyGroup(GfxState *state, double *bbox);
+ virtual void setSoftMask(GfxState *state, double *bbox, GBool alpha,
+ Function *transferFunc, GfxColor *backdropColor);
+
+ //----- special access
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() are all monochrome (black or white).
+ GBool isMonochrome() { return mono; }
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() are all gray.
+ GBool isGray() { return gray; }
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() included any transparency.
+ GBool usesTransparency() { return transparency; }
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() are all rasterizable by GDI calls in GDIOutputDev.
+ GBool isAllGDI() { return gdi; }
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() included any image mask fills with a pattern color
+ // space. (only level1!)
+ GBool usesPatternImageMask() { return patternImgMask; }
+
+ // Clear the stats used by the above functions.
+ void clearStats();
+
+private:
+
+ void check(GfxColorSpace *colorSpace, GfxColor *color,
+ double opacity, GfxBlendMode blendMode);
+
+ PDFDoc *doc;
+ GBool mono;
+ GBool gray;
+ GBool transparency;
+ GBool gdi;
+ PSLevel level; // PostScript level (1, 2, separation)
+ GBool patternImgMask;
+ int inTilingPatternFill;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/ProfileData.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/ProfileData.cc
new file mode 100644
index 00000000000..a0c44747a56
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/ProfileData.cc
@@ -0,0 +1,44 @@
+//========================================================================
+//
+// ProfileData.cc
+//
+// Copyright 2005 Jonathan Blandford <jrb@gnome.org>
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include "ProfileData.h"
+
+//------------------------------------------------------------------------
+// ProfileData
+//------------------------------------------------------------------------
+
+ProfileData::ProfileData() {
+ count = 0;
+ total = 0.0;
+ min = 0.0;
+ max = 0.0;
+}
+
+void
+ProfileData::addElement (double elapsed) {
+ if (count == 0) {
+ min = elapsed;
+ max = elapsed;
+ } else {
+ if (elapsed < min)
+ min = elapsed;
+ if (elapsed > max)
+ max = elapsed;
+ }
+ total += elapsed;
+ count ++;
+}
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/ProfileData.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/ProfileData.h
new file mode 100644
index 00000000000..418ee010755
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/ProfileData.h
@@ -0,0 +1,41 @@
+//========================================================================
+//
+// ProfileData.h
+//
+// Copyright 2005 Jonathan Blandford <jrb@gnome.org>
+//
+//========================================================================
+
+#ifndef PROFILE_DATA_H
+#define PROFILE_DATA_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+//------------------------------------------------------------------------
+// ProfileData
+//------------------------------------------------------------------------
+
+class ProfileData {
+public:
+
+ // Constructor.
+ ProfileData ();
+
+ // Destructor.
+ ~ProfileData() {}
+
+ void addElement (double elapsed);
+ int getCount () { return count; }
+ double getTotal () { return total; }
+ double getMin () { return max; }
+ double getMax () { return max; }
+private:
+ int count; // size of <elems> array
+ double total; // number of elements in array
+ double min; // reference count
+ double max; // reference count
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Rendition.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Rendition.cc
new file mode 100644
index 00000000000..c040bf2b4a8
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Rendition.cc
@@ -0,0 +1,401 @@
+//*********************************************************************************
+// Rendition.cc
+//---------------------------------------------------------------------------------
+//
+//---------------------------------------------------------------------------------
+// Hugo Mercier <hmercier31[at]gmail.com> (c) 2008
+// Pino Toscano <pino@kde.org> (c) 2008
+// Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
+// Tobias Koenig <tobias.koenig@kdab.com> (c) 2012
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//*********************************************************************************
+
+#include <math.h>
+#include "Rendition.h"
+#include "FileSpec.h"
+
+MediaWindowParameters::MediaWindowParameters() {
+ // default values
+ type = windowEmbedded;
+ width = -1;
+ height = -1;
+ relativeTo = windowRelativeToDocument;
+ XPosition = 0.5;
+ YPosition = 0.5;
+ hasTitleBar = gTrue;
+ hasCloseButton = gTrue;
+ isResizeable = gTrue;
+}
+
+MediaWindowParameters::~MediaWindowParameters() {
+}
+
+void MediaWindowParameters::parseFWParams(Object* obj) {
+ Object tmp;
+
+ if (obj->dictLookup("D", &tmp)->isArray()) {
+ Array * dim = tmp.getArray();
+
+ if (dim->getLength() >= 2) {
+ Object dd;
+ if (dim->get(0, &dd)->isInt()) {
+ width = dd.getInt();
+ }
+ dd.free();
+ if (dim->get(1, &dd)->isInt()) {
+ height = dd.getInt();
+ }
+ dd.free();
+ }
+ }
+ tmp.free();
+
+ if (obj->dictLookup("RT", &tmp)->isInt()) {
+ int t = tmp.getInt();
+ switch(t) {
+ case 0: relativeTo = windowRelativeToDocument; break;
+ case 1: relativeTo = windowRelativeToApplication; break;
+ case 2: relativeTo = windowRelativeToDesktop; break;
+ }
+ }
+ tmp.free();
+
+ if (obj->dictLookup("P",&tmp)->isInt()) {
+ int t = tmp.getInt();
+
+ switch(t) {
+ case 0: // Upper left
+ XPosition = 0.0;
+ YPosition = 0.0;
+ break;
+ case 1: // Upper Center
+ XPosition = 0.5;
+ YPosition = 0.0;
+ break;
+ case 2: // Upper Right
+ XPosition = 1.0;
+ YPosition = 0.0;
+ break;
+ case 3: // Center Left
+ XPosition = 0.0;
+ YPosition = 0.5;
+ break;
+ case 4: // Center
+ XPosition = 0.5;
+ YPosition = 0.5;
+ break;
+ case 5: // Center Right
+ XPosition = 1.0;
+ YPosition = 0.5;
+ break;
+ case 6: // Lower Left
+ XPosition = 0.0;
+ YPosition = 1.0;
+ break;
+ case 7: // Lower Center
+ XPosition = 0.5;
+ YPosition = 1.0;
+ break;
+ case 8: // Lower Right
+ XPosition = 1.0;
+ YPosition = 1.0;
+ break;
+ }
+ }
+ tmp.free();
+
+ if (obj->dictLookup("T", &tmp)->isBool()) {
+ hasTitleBar = tmp.getBool();
+ }
+ tmp.free();
+ if (obj->dictLookup("UC", &tmp)->isBool()) {
+ hasCloseButton = tmp.getBool();
+ }
+ tmp.free();
+ if (obj->dictLookup("R", &tmp)->isInt()) {
+ isResizeable = (tmp.getInt() != 0);
+ }
+ tmp.free();
+
+}
+
+MediaParameters::MediaParameters() {
+ // instanciate to default values
+
+ volume = 100;
+ fittingPolicy = fittingUndefined;
+ autoPlay = gTrue;
+ repeatCount = 1.0;
+ opacity = 1.0;
+ showControls = gFalse;
+ duration = 0;
+}
+
+MediaParameters::~MediaParameters() {
+}
+
+void MediaParameters::parseMediaPlayParameters(Object* obj) {
+
+ Object tmp;
+
+ if (obj->dictLookup("V", &tmp)->isInt()) {
+ volume = tmp.getInt();
+ }
+ tmp.free();
+
+ if (obj->dictLookup("C", &tmp)->isBool()) {
+ showControls = tmp.getBool();
+ }
+ tmp.free();
+
+ if (obj->dictLookup("F", &tmp)->isInt()) {
+ int t = tmp.getInt();
+
+ switch(t) {
+ case 0: fittingPolicy = fittingMeet; break;
+ case 1: fittingPolicy = fittingSlice; break;
+ case 2: fittingPolicy = fittingFill; break;
+ case 3: fittingPolicy = fittingScroll; break;
+ case 4: fittingPolicy = fittingHidden; break;
+ case 5: fittingPolicy = fittingUndefined; break;
+ }
+ }
+ tmp.free();
+
+ // duration parsing
+ // duration's default value is set to 0, which means : intrinsinc media duration
+ if (obj->dictLookup("D", &tmp)->isDict()) {
+ Object oname, ddict, tmp2;
+ if (tmp.dictLookup("S", &oname)->isName()) {
+ char* name = oname.getName();
+ if (!strcmp(name, "F"))
+ duration = -1; // infinity
+ else if (!strcmp(name, "T")) {
+ if (tmp.dictLookup("T", &ddict)->isDict()) {
+ if (ddict.dictLookup("V", &tmp2)->isNum()) {
+ duration = Gulong(tmp2.getNum());
+ }
+ tmp2.free();
+ }
+ ddict.free();
+ }
+ }
+ oname.free();
+ }
+ tmp.free();
+
+
+ if (obj->dictLookup("A", &tmp)->isBool()) {
+ autoPlay = tmp.getBool();
+ }
+ tmp.free();
+
+ if (obj->dictLookup("RC", &tmp)->isNum()) {
+ repeatCount = tmp.getNum();
+ }
+ tmp.free();
+
+}
+
+void MediaParameters::parseMediaScreenParameters(Object* obj) {
+ Object tmp;
+
+ if (obj->dictLookup("W", &tmp)->isInt()) {
+ int t = tmp.getInt();
+
+ switch(t) {
+ case 0: windowParams.type = MediaWindowParameters::windowFloating; break;
+ case 1: windowParams.type = MediaWindowParameters::windowFullscreen; break;
+ case 2: windowParams.type = MediaWindowParameters::windowHidden; break;
+ case 3: windowParams.type = MediaWindowParameters::windowEmbedded; break;
+ }
+ }
+ tmp.free();
+
+ // background color
+ if (obj->dictLookup("B", &tmp)->isArray()) {
+ Array* color = tmp.getArray();
+
+ Object component;
+
+ color->get(0, &component);
+ bgColor.r = component.getNum();
+ component.free();
+
+ color->get(1, &component);
+ bgColor.g = component.getNum();
+ component.free();
+
+ color->get(2, &component);
+ bgColor.b = component.getNum();
+ component.free();
+ }
+ tmp.free();
+
+
+ // opacity
+ if (obj->dictLookup("O", &tmp)->isNum()) {
+ opacity = tmp.getNum();
+ }
+ tmp.free();
+
+ if (windowParams.type == MediaWindowParameters::windowFloating) {
+ Object winDict;
+ if (obj->dictLookup("F",&winDict)->isDict()) {
+ windowParams.parseFWParams(&winDict);
+ }
+ winDict.free();
+ }
+}
+
+MediaRendition::~MediaRendition() {
+ if (fileName)
+ delete fileName;
+ if (contentType)
+ delete contentType;
+
+ if (embeddedStream && (!embeddedStream->decRef())) {
+ delete embeddedStream;
+ }
+}
+
+MediaRendition::MediaRendition(Object* obj) {
+ Object tmp, tmp2;
+ GBool hasClip = gFalse;
+
+ ok = gTrue;
+ fileName = NULL;
+ contentType = NULL;
+ isEmbedded = gFalse;
+ embeddedStream = NULL;
+
+ //
+ // Parse media clip data
+ //
+ if (obj->dictLookup("C", &tmp2)->isDict()) { // media clip
+ hasClip = gTrue;
+ if (tmp2.dictLookup("S", &tmp)->isName()) {
+ if (!strcmp(tmp.getName(), "MCD")) { // media clip data
+ Object obj1, obj2;
+ if (tmp2.dictLookup("D", &obj1)->isDict()) {
+ if (obj1.dictLookup("F", &obj2)->isString()) {
+ fileName = obj2.getString()->copy();
+ }
+ obj2.free();
+ if (obj1.dictLookup("EF", &obj2)->isDict()) {
+ Object embedded;
+ if (obj2.dictLookup("F", &embedded)->isStream()) {
+ isEmbedded = gTrue;
+ embeddedStream = embedded.getStream();
+ // "copy" stream
+ embeddedStream->incRef();
+ }
+ embedded.free();
+ }
+ obj2.free();
+
+ // TODO: D might be a form XObject too
+ } else {
+ error (errSyntaxError, -1, "Invalid Media Clip Data");
+ ok = gFalse;
+ }
+ obj1.free();
+
+ // FIXME: ignore CT if D is a form XObject
+ if (tmp2.dictLookup("CT", &obj1)->isString()) {
+ contentType = obj1.getString()->copy();
+ }
+ obj1.free();
+ } else if (!strcmp(tmp.getName(), "MCS")) { // media clip data
+ // TODO
+ }
+ } else {
+ error (errSyntaxError, -1, "Invalid Media Clip");
+ ok = gFalse;
+ }
+ tmp.free();
+ }
+ tmp2.free();
+
+ if (!ok)
+ return;
+
+ //
+ // parse Media Play Parameters
+ if (obj->dictLookup("P", &tmp2)->isDict()) { // media play parameters
+ Object params;
+ if (tmp2.dictLookup("MH", &params)->isDict()) {
+ MH.parseMediaPlayParameters(&params);
+ }
+ params.free();
+ if (tmp2.dictLookup("BE", &params)->isDict()) {
+ BE.parseMediaPlayParameters(&params);
+ }
+ params.free();
+ } else if (!hasClip) {
+ error (errSyntaxError, -1, "Invalid Media Rendition");
+ ok = gFalse;
+ }
+ tmp2.free();
+
+ //
+ // parse Media Screen Parameters
+ if (obj->dictLookup("SP", &tmp2)->isDict()) { // media screen parameters
+ Object params;
+ if (tmp2.dictLookup("MH", &params)->isDict()) {
+ MH.parseMediaScreenParameters(&params);
+ }
+ params.free();
+ if (tmp2.dictLookup("BE", &params)->isDict()) {
+ BE.parseMediaScreenParameters(&params);
+ }
+ params.free();
+ }
+ tmp2.free();
+}
+
+void MediaRendition::outputToFile(FILE* fp) {
+ if (!isEmbedded)
+ return;
+
+ embeddedStream->reset();
+
+ while (1) {
+ int c = embeddedStream->getChar();
+ if (c == EOF)
+ break;
+
+ fwrite(&c, 1, 1, fp);
+ }
+
+}
+
+MediaRendition *MediaRendition::copy() {
+ // call default copy constructor
+ MediaRendition* new_media = new MediaRendition(*this);
+
+ if (contentType)
+ new_media->contentType = contentType->copy();
+ if (fileName)
+ new_media->fileName = fileName->copy();
+
+ if (new_media->embeddedStream)
+ new_media->embeddedStream->incRef();
+
+ return new_media;
+}
+
+// TODO: SelectorRendition
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Rendition.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Rendition.h
new file mode 100644
index 00000000000..75bfeff32c9
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Rendition.h
@@ -0,0 +1,157 @@
+//*********************************************************************************
+// Rendition.h
+//---------------------------------------------------------------------------------
+//
+//---------------------------------------------------------------------------------
+// Hugo Mercier <hmercier31[at]gmail.com> (c) 2008
+// Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//*********************************************************************************
+
+#ifndef _RENDITION_H_
+#define _RENDITION_H_
+
+#include "Object.h"
+
+struct MediaWindowParameters {
+
+ MediaWindowParameters();
+ ~MediaWindowParameters();
+
+ // parse from a floating window parameters dictionary
+ void parseFWParams(Object* obj);
+
+ enum MediaWindowType {
+ windowFloating = 0,
+ windowFullscreen,
+ windowHidden,
+ windowEmbedded
+ };
+
+ enum MediaWindowRelativeTo {
+ windowRelativeToDocument = 0,
+ windowRelativeToApplication,
+ windowRelativeToDesktop
+ };
+
+
+ // DEFAULT VALUE
+
+ MediaWindowType type; // movieWindowEmbedded
+
+
+ int width; // -1
+ int height; // -1
+
+ // floating window position
+ MediaWindowRelativeTo relativeTo; // windowRelativeToDocument (or to desktop)
+ double XPosition; // 0.5
+ double YPosition; // 0.5
+
+ GBool hasTitleBar; // true
+ GBool hasCloseButton; // true
+ GBool isResizeable; // true
+};
+
+
+struct MediaParameters {
+
+ MediaParameters();
+ ~MediaParameters();
+
+ // parse from a "Media Play Parameters" dictionary
+ void parseMediaPlayParameters(Object* playObj);
+ // parse from a "Media Screen Parameters" dictionary
+ void parseMediaScreenParameters(Object* screenObj);
+
+ enum MediaFittingPolicy {
+ fittingMeet = 0,
+ fittingSlice,
+ fittingFill,
+ fittingScroll,
+ fittingHidden,
+ fittingUndefined
+ };
+
+ struct Color {
+ double r, g, b;
+ };
+
+ int duration; // 0
+
+ int volume; // 100
+
+ // defined in media play parameters, p 770
+ // correspond to 'fit' SMIL's attribute
+ MediaFittingPolicy fittingPolicy; // fittingUndefined
+
+ GBool autoPlay; // true
+
+ // repeat count, can be real values, 0 means forever
+ double repeatCount; // 1.0
+
+ // background color // black = (0.0 0.0 0.0)
+ Color bgColor;
+
+ // opacity in [0.0 1.0]
+ double opacity; // 1.0
+
+
+ GBool showControls; // false
+
+ MediaWindowParameters windowParams;
+};
+
+class MediaRendition {
+ public:
+ MediaRendition(Object *obj);
+ ~MediaRendition();
+
+ GBool isOk () { return ok; }
+
+ MediaParameters* getMHParameters() { return &MH; }
+ MediaParameters* getBEParameters() { return &BE; }
+
+ GooString* getContentType() { return contentType; }
+ GooString* getFileName() { return fileName; }
+
+ GBool getIsEmbedded() { return isEmbedded; }
+ Stream* getEmbbededStream() { return embeddedStream; }
+ // write embedded stream to file
+ void outputToFile(FILE*);
+
+ MediaRendition* copy();
+
+ private:
+ GBool ok;
+
+ // "Must Honor" parameters
+ MediaParameters MH;
+ // "Best Effort" parameters
+ MediaParameters BE;
+
+ GBool isEmbedded;
+
+ GooString* contentType;
+
+ // if it's embedded
+ Stream* embeddedStream;
+
+ // if it's not embedded
+ GooString* fileName;
+};
+
+#endif /* _RENDITION_H_ */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/SecurityHandler.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/SecurityHandler.cc
new file mode 100644
index 00000000000..63d8b4e1287
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/SecurityHandler.cc
@@ -0,0 +1,461 @@
+//========================================================================
+//
+// SecurityHandler.cc
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010, 2012, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2014 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "GooString.h"
+#include "PDFDoc.h"
+#include "Decrypt.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#ifdef ENABLE_PLUGINS
+# include "XpdfPluginAPI.h"
+#endif
+#include "SecurityHandler.h"
+
+#include <limits.h>
+
+//------------------------------------------------------------------------
+// SecurityHandler
+//------------------------------------------------------------------------
+
+SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
+ Object filterObj;
+ SecurityHandler *secHdlr;
+#ifdef ENABLE_PLUGINS
+ XpdfSecurityHandler *xsh;
+#endif
+
+ encryptDictA->dictLookup("Filter", &filterObj);
+ if (filterObj.isName("Standard")) {
+ secHdlr = new StandardSecurityHandler(docA, encryptDictA);
+ } else if (filterObj.isName()) {
+#ifdef ENABLE_PLUGINS
+ if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) {
+ secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh);
+ } else {
+#endif
+ error(errSyntaxError, -1, "Couldn't find the '{0:s}' security handler",
+ filterObj.getName());
+ secHdlr = NULL;
+#ifdef ENABLE_PLUGINS
+ }
+#endif
+ } else {
+ error(errSyntaxError, -1,
+ "Missing or invalid 'Filter' entry in encryption dictionary");
+ secHdlr = NULL;
+ }
+ filterObj.free();
+ return secHdlr;
+}
+
+SecurityHandler::SecurityHandler(PDFDoc *docA) {
+ doc = docA;
+}
+
+SecurityHandler::~SecurityHandler() {
+}
+
+GBool SecurityHandler::checkEncryption(GooString *ownerPassword,
+ GooString *userPassword) {
+ void *authData;
+ GBool ok;
+ int i;
+
+ if (ownerPassword || userPassword) {
+ authData = makeAuthData(ownerPassword, userPassword);
+ } else {
+ authData = NULL;
+ }
+ ok = authorize(authData);
+ if (authData) {
+ freeAuthData(authData);
+ }
+ for (i = 0; !ok && i < 3; ++i) {
+ if (!(authData = getAuthData())) {
+ break;
+ }
+ ok = authorize(authData);
+ if (authData) {
+ freeAuthData(authData);
+ }
+ }
+ if (!ok) {
+ if (!ownerPassword && !userPassword) {
+ GooString dummy;
+ return checkEncryption(&dummy, &dummy);
+ } else {
+ error(errCommandLine, -1, "Incorrect password");
+ }
+ }
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// StandardSecurityHandler
+//------------------------------------------------------------------------
+
+class StandardAuthData {
+public:
+
+ StandardAuthData(GooString *ownerPasswordA, GooString *userPasswordA) {
+ ownerPassword = ownerPasswordA;
+ userPassword = userPasswordA;
+ }
+
+ ~StandardAuthData() {
+ if (ownerPassword) {
+ delete ownerPassword;
+ }
+ if (userPassword) {
+ delete userPassword;
+ }
+ }
+
+ GooString *ownerPassword;
+ GooString *userPassword;
+};
+
+StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
+ Object *encryptDictA):
+ SecurityHandler(docA)
+{
+ Object versionObj, revisionObj, lengthObj;
+ Object ownerKeyObj, userKeyObj, ownerEncObj, userEncObj;
+ Object permObj, fileIDObj, fileIDObj1;
+ Object cryptFiltersObj, streamFilterObj, stringFilterObj;
+ Object cryptFilterObj, cfmObj, cfLengthObj;
+ Object encryptMetadataObj;
+
+ ok = gFalse;
+ fileID = NULL;
+ ownerKey = NULL;
+ userKey = NULL;
+ ownerEnc = NULL;
+ userEnc = NULL;
+ fileKeyLength = 0;
+
+ encryptDictA->dictLookup("V", &versionObj);
+ encryptDictA->dictLookup("R", &revisionObj);
+ encryptDictA->dictLookup("Length", &lengthObj);
+ encryptDictA->dictLookup("O", &ownerKeyObj);
+ encryptDictA->dictLookup("U", &userKeyObj);
+ encryptDictA->dictLookup("OE", &ownerEncObj);
+ encryptDictA->dictLookup("UE", &userEncObj);
+ encryptDictA->dictLookup("P", &permObj);
+ if (permObj.isInt64()) {
+ unsigned int permUint = permObj.getInt64();
+ int perms = permUint - UINT_MAX - 1;
+ permObj.free();
+ permObj.initInt(perms);
+ }
+ doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
+ if (versionObj.isInt() &&
+ revisionObj.isInt() &&
+ permObj.isInt() &&
+ ownerKeyObj.isString() &&
+ userKeyObj.isString()) {
+ encVersion = versionObj.getInt();
+ encRevision = revisionObj.getInt();
+ if ((encRevision <= 4 &&
+ ownerKeyObj.getString()->getLength() == 32 &&
+ userKeyObj.getString()->getLength() == 32) ||
+ (encRevision == 5 &&
+ // the spec says 48 bytes, but Acrobat pads them out longer
+ ownerKeyObj.getString()->getLength() >= 48 &&
+ userKeyObj.getString()->getLength() >= 48 &&
+ ownerEncObj.isString() &&
+ ownerEncObj.getString()->getLength() == 32 &&
+ userEncObj.isString() &&
+ userEncObj.getString()->getLength() == 32)) {
+ encAlgorithm = cryptRC4;
+ // revision 2 forces a 40-bit key - some buggy PDF generators
+ // set the Length value incorrectly
+ if (encRevision == 2 || !lengthObj.isInt()) {
+ fileKeyLength = 5;
+ } else {
+ fileKeyLength = lengthObj.getInt() / 8;
+ }
+ encryptMetadata = gTrue;
+ //~ this currently only handles a subset of crypt filter functionality
+ //~ (in particular, it ignores the EFF entry in encryptDictA, and
+ //~ doesn't handle the case where StmF, StrF, and EFF are not all the
+ //~ same)
+ if ((encVersion == 4 || encVersion == 5) &&
+ (encRevision == 4 || encRevision == 5)) {
+ encryptDictA->dictLookup("CF", &cryptFiltersObj);
+ encryptDictA->dictLookup("StmF", &streamFilterObj);
+ encryptDictA->dictLookup("StrF", &stringFilterObj);
+ if (cryptFiltersObj.isDict() &&
+ streamFilterObj.isName() &&
+ stringFilterObj.isName() &&
+ !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) {
+ if (!strcmp(streamFilterObj.getName(), "Identity")) {
+ // no encryption on streams or strings
+ encVersion = encRevision = -1;
+ } else {
+ if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
+ &cryptFilterObj)->isDict()) {
+ cryptFilterObj.dictLookup("CFM", &cfmObj);
+ if (cfmObj.isName("V2")) {
+ encVersion = 2;
+ encRevision = 3;
+ if (cryptFilterObj.dictLookup("Length",
+ &cfLengthObj)->isInt()) {
+ //~ according to the spec, this should be cfLengthObj / 8
+ fileKeyLength = cfLengthObj.getInt();
+ }
+ cfLengthObj.free();
+ } else if (cfmObj.isName("AESV2")) {
+ encVersion = 2;
+ encRevision = 3;
+ encAlgorithm = cryptAES;
+ if (cryptFilterObj.dictLookup("Length",
+ &cfLengthObj)->isInt()) {
+ //~ according to the spec, this should be cfLengthObj / 8
+ fileKeyLength = cfLengthObj.getInt();
+ }
+ cfLengthObj.free();
+ } else if (cfmObj.isName("AESV3")) {
+ encVersion = 5;
+ encRevision = 5;
+ encAlgorithm = cryptAES256;
+ if (cryptFilterObj.dictLookup("Length",
+ &cfLengthObj)->isInt()) {
+ //~ according to the spec, this should be cfLengthObj / 8
+ fileKeyLength = cfLengthObj.getInt();
+ }
+ cfLengthObj.free();
+ }
+ cfmObj.free();
+ }
+ cryptFilterObj.free();
+ }
+ }
+ stringFilterObj.free();
+ streamFilterObj.free();
+ cryptFiltersObj.free();
+ if (encryptDictA->dictLookup("EncryptMetadata",
+ &encryptMetadataObj)->isBool()) {
+ encryptMetadata = encryptMetadataObj.getBool();
+ }
+ encryptMetadataObj.free();
+ }
+ permFlags = permObj.getInt();
+ ownerKey = ownerKeyObj.getString()->copy();
+ userKey = userKeyObj.getString()->copy();
+ if (encVersion >= 1 && encVersion <= 2 &&
+ encRevision >= 2 && encRevision <= 3) {
+ if (fileIDObj.isArray()) {
+ if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
+ fileID = fileIDObj1.getString()->copy();
+ } else {
+ fileID = new GooString();
+ }
+ fileIDObj1.free();
+ } else {
+ fileID = new GooString();
+ }
+ if (fileKeyLength > 16 || fileKeyLength < 0) {
+ fileKeyLength = 16;
+ }
+ ok = gTrue;
+ } else if (encVersion == 5 && encRevision == 5) {
+ fileID = new GooString(); // unused for V=R=5
+ if (ownerEncObj.isString() && userEncObj.isString()) {
+ ownerEnc = ownerEncObj.getString()->copy();
+ userEnc = userEncObj.getString()->copy();
+ if (fileKeyLength > 32 || fileKeyLength < 0) {
+ fileKeyLength = 32;
+ }
+ ok = gTrue;
+ } else {
+ error(errSyntaxError, -1, "Weird encryption owner/user info");
+ }
+ } else if (!(encVersion == -1 && encRevision == -1)) {
+ error(errUnimplemented, -1,
+ "Unsupported version/revision ({0:d}/{1:d}) of Standard security handler",
+ encVersion, encRevision);
+ }
+ } else {
+ error(errSyntaxError, -1, "Invalid encryption key length");
+ }
+ } else {
+ error(errSyntaxError, -1, "Weird encryption info");
+ }
+ fileIDObj.free();
+ permObj.free();
+ userEncObj.free();
+ ownerEncObj.free();
+ userKeyObj.free();
+ ownerKeyObj.free();
+ lengthObj.free();
+ revisionObj.free();
+ versionObj.free();
+}
+
+StandardSecurityHandler::~StandardSecurityHandler() {
+ if (fileID) {
+ delete fileID;
+ }
+ if (ownerKey) {
+ delete ownerKey;
+ }
+ if (userKey) {
+ delete userKey;
+ }
+ if (ownerEnc) {
+ delete ownerEnc;
+ }
+ if (userEnc) {
+ delete userEnc;
+ }
+}
+
+GBool StandardSecurityHandler::isUnencrypted() {
+ return encVersion == -1 && encRevision == -1;
+}
+
+void *StandardSecurityHandler::makeAuthData(GooString *ownerPassword,
+ GooString *userPassword) {
+ return new StandardAuthData(ownerPassword ? ownerPassword->copy()
+ : (GooString *)NULL,
+ userPassword ? userPassword->copy()
+ : (GooString *)NULL);
+}
+
+void *StandardSecurityHandler::getAuthData() {
+ return NULL;
+}
+
+void StandardSecurityHandler::freeAuthData(void *authData) {
+ delete (StandardAuthData *)authData;
+}
+
+GBool StandardSecurityHandler::authorize(void *authData) {
+ GooString *ownerPassword, *userPassword;
+
+ if (!ok) {
+ return gFalse;
+ }
+ if (authData) {
+ ownerPassword = ((StandardAuthData *)authData)->ownerPassword;
+ userPassword = ((StandardAuthData *)authData)->userPassword;
+ } else {
+ ownerPassword = NULL;
+ userPassword = NULL;
+ }
+ if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength,
+ ownerKey, userKey, ownerEnc, userEnc,
+ permFlags, fileID,
+ ownerPassword, userPassword, fileKey,
+ encryptMetadata, &ownerPasswordOk)) {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+#ifdef ENABLE_PLUGINS
+
+//------------------------------------------------------------------------
+// ExternalSecurityHandler
+//------------------------------------------------------------------------
+
+ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA,
+ Object *encryptDictA,
+ XpdfSecurityHandler *xshA):
+ SecurityHandler(docA)
+{
+ encryptDictA->copy(&encryptDict);
+ xsh = xshA;
+ encAlgorithm = cryptRC4; //~ this should be obtained via getKey
+ ok = gFalse;
+
+ if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA,
+ (XpdfObject)encryptDictA, &docData)) {
+ return;
+ }
+
+ ok = gTrue;
+}
+
+ExternalSecurityHandler::~ExternalSecurityHandler() {
+ (*xsh->freeDoc)(xsh->handlerData, docData);
+ encryptDict.free();
+}
+
+void *ExternalSecurityHandler::makeAuthData(GooString *ownerPassword,
+ GooString *userPassword) {
+ char *opw, *upw;
+ void *authData;
+
+ opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL;
+ upw = userPassword ? userPassword->getCString() : (char *)NULL;
+ if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) {
+ return NULL;
+ }
+ return authData;
+}
+
+void *ExternalSecurityHandler::getAuthData() {
+ void *authData;
+
+ if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) {
+ return NULL;
+ }
+ return authData;
+}
+
+void ExternalSecurityHandler::freeAuthData(void *authData) {
+ (*xsh->freeAuthData)(xsh->handlerData, docData, authData);
+}
+
+GBool ExternalSecurityHandler::authorize(void *authData) {
+ char *key;
+ int length;
+
+ if (!ok) {
+ return gFalse;
+ }
+ permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData);
+ if (!(permFlags & xpdfPermissionOpen)) {
+ return gFalse;
+ }
+ if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion, &encRevision)) {
+ return gFalse;
+ }
+ if ((fileKeyLength = length) > 16) {
+ fileKeyLength = 16;
+ }
+ memcpy(fileKey, key, fileKeyLength);
+ (*xsh->freeKey)(xsh->handlerData, docData, key, length);
+ return gTrue;
+}
+
+#endif // ENABLE_PLUGINS
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/SecurityHandler.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/SecurityHandler.h
new file mode 100644
index 00000000000..c2991c8f375
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/SecurityHandler.h
@@ -0,0 +1,183 @@
+//========================================================================
+//
+// SecurityHandler.h
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SECURITYHANDLER_H
+#define SECURITYHANDLER_H
+
+#include "poppler-config.h"
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "Object.h"
+
+class GooString;
+class PDFDoc;
+struct XpdfSecurityHandler;
+
+//------------------------------------------------------------------------
+// SecurityHandler
+//------------------------------------------------------------------------
+
+class SecurityHandler {
+public:
+
+ static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA);
+
+ SecurityHandler(PDFDoc *docA);
+ virtual ~SecurityHandler();
+
+ // Returns true if the file is actually unencrypted.
+ virtual GBool isUnencrypted() { return gFalse; }
+
+ // Check the document's encryption. If the document is encrypted,
+ // this will first try <ownerPassword> and <userPassword> (in
+ // "batch" mode), and if those fail, it will attempt to request a
+ // password from the user. This is the high-level function that
+ // calls the lower level functions for the specific security handler
+ // (requesting a password three times, etc.). Returns true if the
+ // document can be opened (if it's unencrypted, or if a correct
+ // password is obtained); false otherwise (encrypted and no correct
+ // password).
+ GBool checkEncryption(GooString *ownerPassword,
+ GooString *userPassword);
+
+ // Create authorization data for the specified owner and user
+ // passwords. If the security handler doesn't support "batch" mode,
+ // this function should return NULL.
+ virtual void *makeAuthData(GooString *ownerPassword,
+ GooString *userPassword) = 0;
+
+ // Construct authorization data, typically by prompting the user for
+ // a password. Returns an authorization data object, or NULL to
+ // cancel.
+ virtual void *getAuthData() = 0;
+
+ // Free the authorization data returned by makeAuthData or
+ // getAuthData.
+ virtual void freeAuthData(void *authData) = 0;
+
+ // Attempt to authorize the document, using the supplied
+ // authorization data (which may be NULL). Returns true if
+ // successful (i.e., if at least the right to open the document was
+ // granted).
+ virtual GBool authorize(void *authData) = 0;
+
+ // Return the various authorization parameters. These are only
+ // valid after authorize has returned true.
+ virtual int getPermissionFlags() = 0;
+ virtual GBool getOwnerPasswordOk() = 0;
+ virtual Guchar *getFileKey() = 0;
+ virtual int getFileKeyLength() = 0;
+ virtual int getEncVersion() = 0;
+ virtual int getEncRevision() = 0;
+ virtual CryptAlgorithm getEncAlgorithm() = 0;
+
+protected:
+
+ PDFDoc *doc;
+};
+
+//------------------------------------------------------------------------
+// StandardSecurityHandler
+//------------------------------------------------------------------------
+
+class StandardSecurityHandler: public SecurityHandler {
+public:
+
+ StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA);
+ virtual ~StandardSecurityHandler();
+
+ virtual GBool isUnencrypted();
+ virtual void *makeAuthData(GooString *ownerPassword,
+ GooString *userPassword);
+ virtual void *getAuthData();
+ virtual void freeAuthData(void *authData);
+ virtual GBool authorize(void *authData);
+ virtual int getPermissionFlags() { return permFlags; }
+ virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; }
+ virtual Guchar *getFileKey() { return fileKey; }
+ virtual int getFileKeyLength() { return fileKeyLength; }
+ virtual int getEncVersion() { return encVersion; }
+ virtual int getEncRevision() { return encRevision; }
+ virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; }
+
+private:
+
+ int permFlags;
+ GBool ownerPasswordOk;
+ Guchar fileKey[32];
+ int fileKeyLength;
+ int encVersion;
+ int encRevision;
+ GBool encryptMetadata;
+ CryptAlgorithm encAlgorithm;
+
+ GooString *ownerKey, *userKey;
+ GooString *ownerEnc, *userEnc;
+ GooString *fileID;
+ GBool ok;
+};
+
+#ifdef ENABLE_PLUGINS
+//------------------------------------------------------------------------
+// ExternalSecurityHandler
+//------------------------------------------------------------------------
+
+class ExternalSecurityHandler: public SecurityHandler {
+public:
+
+ ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA,
+ XpdfSecurityHandler *xshA);
+ virtual ~ExternalSecurityHandler();
+
+ virtual void *makeAuthData(GooString *ownerPassword,
+ GooString *userPassword);
+ virtual void *getAuthData();
+ virtual void freeAuthData(void *authData);
+ virtual GBool authorize(void *authData);
+ virtual int getPermissionFlags() { return permFlags; }
+ virtual GBool getOwnerPasswordOk() { return gFalse; }
+ virtual Guchar *getFileKey() { return fileKey; }
+ virtual int getFileKeyLength() { return fileKeyLength; }
+ virtual int getEncVersion() { return encVersion; }
+ virtual int getEncRevision() { return encRevision; }
+ virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; }
+
+private:
+
+ Object encryptDict;
+ XpdfSecurityHandler *xsh;
+ void *docData;
+ int permFlags;
+ Guchar fileKey[16];
+ int fileKeyLength;
+ int encVersion;
+ int encRevision;
+ CryptAlgorithm encAlgorithm;
+ GBool ok;
+};
+#endif // ENABLE_PLUGINS
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Sound.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Sound.cc
new file mode 100644
index 00000000000..6129fdcb47d
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Sound.cc
@@ -0,0 +1,145 @@
+/* Sound.cc - an object that holds the sound structure
+ * Copyright (C) 2006-2007, Pino Toscano <pino@kde.org>
+ * Copyright (C) 2009, Albert Astals Cid <aacid@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "GooString.h"
+#include "Object.h"
+#include "Sound.h"
+#include "Stream.h"
+#include "FileSpec.h"
+
+Sound *Sound::parseSound(Object *obj)
+{
+ // let's try to see if this Object is a Sound, according to the PDF specs
+ // (section 9.2)
+ Stream *str = NULL;
+ // the Object must be a Stream
+ if (obj->isStream()) {
+ str = obj->getStream();
+ } else {
+ return NULL;
+ }
+ // the Stream must have a Dict
+ Dict *dict = str->getDict();
+ if (dict == NULL)
+ return NULL;
+ Object tmp;
+ // the Dict must have the 'R' key of type num
+ dict->lookup("R", &tmp);
+ if (tmp.isNum()) {
+ return new Sound(obj);
+ } else {
+ return NULL;
+ }
+}
+
+Sound::Sound(Object *obj, bool readAttrs)
+{
+ streamObj = new Object();
+ streamObj->initNull();
+ obj->copy(streamObj);
+
+ fileName = NULL;
+ samplingRate = 0.0;
+ channels = 1;
+ bitsPerSample = 8;
+ encoding = soundRaw;
+
+ if (readAttrs)
+ {
+ Object tmp;
+ Dict *dict = streamObj->getStream()->getDict();
+ dict->lookup("F", &tmp);
+ if (!tmp.isNull()) {
+ Object obj1;
+ // valid 'F' key -> external file
+ kind = soundExternal;
+ if (getFileSpecNameForPlatform (&tmp, &obj1)) {
+ fileName = obj1.getString()->copy();
+ obj1.free();
+ }
+ } else {
+ // no file specification, then the sound data have to be
+ // extracted from the stream
+ kind = soundEmbedded;
+ }
+ tmp.free();
+ // sampling rate
+ dict->lookup("R", &tmp);
+ if (tmp.isNum()) {
+ samplingRate = tmp.getNum();
+ }
+ tmp.free();
+ // sound channels
+ dict->lookup("C", &tmp);
+ if (tmp.isInt()) {
+ channels = tmp.getInt();
+ }
+ tmp.free();
+ // bits per sample
+ dict->lookup("B", &tmp);
+ if (tmp.isInt()) {
+ bitsPerSample = tmp.getInt();
+ }
+ tmp.free();
+ // encoding format
+ dict->lookup("E", &tmp);
+ if (tmp.isName())
+ {
+ const char *enc = tmp.getName();
+ if (strcmp("Raw", enc) == 0) {
+ encoding = soundRaw;
+ } else if (strcmp("Signed", enc) == 0) {
+ encoding = soundSigned;
+ } else if (strcmp("muLaw", enc) == 0) {
+ encoding = soundMuLaw;
+ } else if (strcmp("ALaw", enc) == 0) {
+ encoding = soundALaw;
+ }
+ }
+ tmp.free();
+ }
+}
+
+Sound::~Sound()
+{
+ delete fileName;
+ streamObj->free();
+ delete streamObj;
+}
+
+Stream *Sound::getStream()
+{
+ return streamObj->getStream();
+}
+
+Sound *Sound::copy()
+{
+ Sound *newsound = new Sound(streamObj, false);
+
+ newsound->kind = kind;
+ if (fileName) {
+ newsound->fileName = fileName->copy();
+ }
+ newsound->samplingRate = samplingRate;
+ newsound->channels = channels;
+ newsound->bitsPerSample = bitsPerSample;
+ newsound->encoding = encoding;
+
+ return newsound;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Sound.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Sound.h
new file mode 100644
index 00000000000..acb0f8d9acd
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Sound.h
@@ -0,0 +1,74 @@
+/* Sound.h - an object that holds the sound structure
+ * Copyright (C) 2006-2007, Pino Toscano <pino@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef Sound_H
+#define Sound_H
+
+class GooString;
+class Object;
+class Stream;
+
+//------------------------------------------------------------------------
+
+enum SoundKind {
+ soundEmbedded, // embedded sound
+ soundExternal // external sound
+};
+
+enum SoundEncoding {
+ soundRaw, // raw encoding
+ soundSigned, // twos-complement values
+ soundMuLaw, // mu-law-encoded samples
+ soundALaw // A-law-encoded samples
+};
+
+class Sound
+{
+public:
+ // Try to parse the Object s
+ static Sound *parseSound(Object *s);
+
+ // Destructor
+ ~Sound();
+
+ Object *getObject() { return streamObj; }
+ Stream *getStream();
+
+ SoundKind getSoundKind() { return kind; }
+ GooString *getFileName() { return fileName; }
+ double getSamplingRate() { return samplingRate; }
+ int getChannels() { return channels; }
+ int getBitsPerSample() { return bitsPerSample; }
+ SoundEncoding getEncoding() { return encoding; }
+
+ Sound *copy();
+
+private:
+ // Create a sound. The Object obj is ensured to be a Stream with a Dict
+ Sound(Object *obj, bool readAttrs = true);
+
+ Object *streamObj;
+ SoundKind kind;
+ GooString *fileName;
+ double samplingRate;
+ int channels;
+ int bitsPerSample;
+ SoundEncoding encoding;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/SplashOutputDev.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/SplashOutputDev.cc
new file mode 100644
index 00000000000..d9d5699a051
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/SplashOutputDev.cc
@@ -0,0 +1,4672 @@
+//========================================================================
+//
+// SplashOutputDev.cc
+//
+// Copyright 2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2006 Stefan Schweizer <genstef@gentoo.org>
+// Copyright (C) 2006-2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
+// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2009-2015 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009, 2014, 2015 William Bader <williambader@hotmail.com>
+// Copyright (C) 2010 Patrick Spendrin <ps_ml@gmx.de>
+// Copyright (C) 2010 Brian Cameron <brian.cameron@oracle.com>
+// Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
+// Copyright (C) 2011, 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Lu Wang <coolwanglu@gmail.com>
+// Copyright (C) 2013 Li Junling <lijunling@sina.com>
+// Copyright (C) 2014 Ed Porras <ed@moto-research.com>
+// Copyright (C) 2014 Richard PALO <richard@netbsd.org>
+// Copyright (C) 2015 Tamas Szekeres <szekerest@gmail.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include <math.h>
+#include "goo/gfile.h"
+#include "GlobalParams.h"
+#include "Error.h"
+#include "Object.h"
+#include "Gfx.h"
+#include "GfxFont.h"
+#include "Page.h"
+#include "PDFDoc.h"
+#include "Link.h"
+#include "FontEncodingTables.h"
+#include "fofi/FoFiTrueType.h"
+#include "splash/SplashBitmap.h"
+#include "splash/SplashGlyphBitmap.h"
+#include "splash/SplashPattern.h"
+#include "splash/SplashScreen.h"
+#include "splash/SplashPath.h"
+#include "splash/SplashState.h"
+#include "splash/SplashErrorCodes.h"
+#include "splash/SplashFontEngine.h"
+#include "splash/SplashFont.h"
+#include "splash/SplashFontFile.h"
+#include "splash/SplashFontFileID.h"
+#include "splash/Splash.h"
+#include "SplashOutputDev.h"
+#include <algorithm>
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+#ifdef _MSC_VER
+#include <float.h>
+#define isfinite(x) _finite(x)
+#endif
+
+#ifdef __sun
+#include <ieeefp.h>
+#ifndef isfinite
+#define isfinite(x) finite(x)
+#endif
+#endif
+
+static inline void convertGfxColor(SplashColorPtr dest,
+ SplashColorMode colorMode,
+ GfxColorSpace *colorSpace,
+ GfxColor *src) {
+ SplashColor color;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+
+ // make gcc happy
+ color[0] = color[1] = color[2] = 0;
+#if SPLASH_CMYK
+ color[3] = 0;
+#endif
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ colorSpace->getGray(src, &gray);
+ color[0] = colToByte(gray);
+ break;
+ case splashModeXBGR8:
+ color[3] = 255;
+ case splashModeBGR8:
+ case splashModeRGB8:
+ colorSpace->getRGB(src, &rgb);
+ color[0] = colToByte(rgb.r);
+ color[1] = colToByte(rgb.g);
+ color[2] = colToByte(rgb.b);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ colorSpace->getCMYK(src, &cmyk);
+ color[0] = colToByte(cmyk.c);
+ color[1] = colToByte(cmyk.m);
+ color[2] = colToByte(cmyk.y);
+ color[3] = colToByte(cmyk.k);
+ break;
+ case splashModeDeviceN8:
+ colorSpace->getDeviceN(src, &deviceN);
+ for (int i = 0; i < SPOT_NCOMPS + 4; i++)
+ color[i] = colToByte(deviceN.c[i]);
+ break;
+#endif
+ }
+ splashColorCopy(dest, color);
+}
+
+// Copy a color according to the color mode.
+// Use convertGfxShortColor() below when the destination is a bitmap
+// to avoid overwriting cells.
+// Calling this in SplashGouraudPattern::getParameterizedColor() fixes bug 90570.
+// Use convertGfxColor() above when the destination is an array of SPOT_NCOMPS+4 bytes,
+// to ensure that everything is initialized.
+
+static inline void convertGfxShortColor(SplashColorPtr dest,
+ SplashColorMode colorMode,
+ GfxColorSpace *colorSpace,
+ GfxColor *src) {
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ {
+ GfxGray gray;
+ colorSpace->getGray(src, &gray);
+ dest[0] = colToByte(gray);
+ }
+ break;
+ case splashModeXBGR8:
+ dest[3] = 255;
+ case splashModeBGR8:
+ case splashModeRGB8:
+ {
+ GfxRGB rgb;
+ colorSpace->getRGB(src, &rgb);
+ dest[0] = colToByte(rgb.r);
+ dest[1] = colToByte(rgb.g);
+ dest[2] = colToByte(rgb.b);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ {
+ GfxCMYK cmyk;
+ colorSpace->getCMYK(src, &cmyk);
+ dest[0] = colToByte(cmyk.c);
+ dest[1] = colToByte(cmyk.m);
+ dest[2] = colToByte(cmyk.y);
+ dest[3] = colToByte(cmyk.k);
+ }
+ break;
+ case splashModeDeviceN8:
+ {
+ GfxColor deviceN;
+ colorSpace->getDeviceN(src, &deviceN);
+ for (int i = 0; i < SPOT_NCOMPS + 4; i++)
+ dest[i] = colToByte(deviceN.c[i]);
+ }
+ break;
+#endif
+ }
+}
+
+//------------------------------------------------------------------------
+// SplashGouraudPattern
+//------------------------------------------------------------------------
+SplashGouraudPattern::SplashGouraudPattern(GBool bDirectColorTranslationA,
+ GfxState *stateA, GfxGouraudTriangleShading *shadingA, SplashColorMode modeA) {
+ SplashColor defaultColor;
+ GfxColor srcColor;
+ state = stateA;
+ shading = shadingA;
+ mode = modeA;
+ bDirectColorTranslation = bDirectColorTranslationA;
+ shadingA->getColorSpace()->getDefaultColor(&srcColor);
+ convertGfxColor(defaultColor, mode, shadingA->getColorSpace(), &srcColor);
+ gfxMode = shadingA->getColorSpace()->getMode();
+}
+
+SplashGouraudPattern::~SplashGouraudPattern() {
+}
+
+void SplashGouraudPattern::getParameterizedColor(double colorinterp, SplashColorMode mode, SplashColorPtr dest) {
+ GfxColor src;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ int colorComps = 3;
+#if SPLASH_CMYK
+ if (mode == splashModeCMYK8)
+ colorComps=4;
+ else if (mode == splashModeDeviceN8)
+ colorComps=4 + SPOT_NCOMPS;
+#endif
+
+ shading->getParameterizedColor(colorinterp, &src);
+
+ if (bDirectColorTranslation) {
+ for (int m = 0; m < colorComps; ++m)
+ dest[m] = colToByte(src.c[m]);
+ } else {
+ convertGfxShortColor(dest, mode, srcColorSpace, &src);
+ }
+}
+
+//------------------------------------------------------------------------
+// SplashUnivariatePattern
+//------------------------------------------------------------------------
+
+SplashUnivariatePattern::SplashUnivariatePattern(SplashColorMode colorModeA, GfxState *stateA, GfxUnivariateShading *shadingA) {
+ Matrix ctm;
+ double xMin, yMin, xMax, yMax;
+
+ shading = shadingA;
+ state = stateA;
+ colorMode = colorModeA;
+
+ state->getCTM(&ctm);
+ ctm.invertTo(&ictm);
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+ dt = t1 - t0;
+
+ stateA->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ shadingA->setupCache(&ctm, xMin, yMin, xMax, yMax);
+ gfxMode = shadingA->getColorSpace()->getMode();
+}
+
+SplashUnivariatePattern::~SplashUnivariatePattern() {
+}
+
+GBool SplashUnivariatePattern::getColor(int x, int y, SplashColorPtr c) {
+ GfxColor gfxColor;
+ double xc, yc, t;
+
+ ictm.transform(x, y, &xc, &yc);
+ if (! getParameter (xc, yc, &t))
+ return gFalse;
+
+ shading->getColor(t, &gfxColor);
+ convertGfxColor(c, colorMode, shading->getColorSpace(), &gfxColor);
+ return gTrue;
+}
+
+GBool SplashUnivariatePattern::testPosition(int x, int y) {
+ double xc, yc, t;
+
+ ictm.transform(x, y, &xc, &yc);
+ if (! getParameter (xc, yc, &t))
+ return gFalse;
+ return (t0 < t1) ? (t > t0 && t < t1) : (t > t1 && t < t0);
+}
+
+
+//------------------------------------------------------------------------
+// SplashRadialPattern
+//------------------------------------------------------------------------
+#define RADIAL_EPSILON (1. / 1024 / 1024)
+
+SplashRadialPattern::SplashRadialPattern(SplashColorMode colorModeA, GfxState *stateA, GfxRadialShading *shadingA):
+ SplashUnivariatePattern(colorModeA, stateA, shadingA)
+{
+ SplashColor defaultColor;
+ GfxColor srcColor;
+
+ shadingA->getCoords(&x0, &y0, &r0, &dx, &dy, &dr);
+ dx -= x0;
+ dy -= y0;
+ dr -= r0;
+ a = dx*dx + dy*dy - dr*dr;
+ if (fabs(a) > RADIAL_EPSILON)
+ inva = 1.0 / a;
+ shadingA->getColorSpace()->getDefaultColor(&srcColor);
+ convertGfxColor(defaultColor, colorModeA, shadingA->getColorSpace(), &srcColor);
+}
+
+SplashRadialPattern::~SplashRadialPattern() {
+}
+
+GBool SplashRadialPattern::getParameter(double xs, double ys, double *t) {
+ double b, c, s0, s1;
+
+ // We want to solve this system of equations:
+ //
+ // 1. (x - xc(s))^2 + (y -yc(s))^2 = rc(s)^2
+ // 2. xc(s) = x0 + s * (x1 - xo)
+ // 3. yc(s) = y0 + s * (y1 - yo)
+ // 4. rc(s) = r0 + s * (r1 - ro)
+ //
+ // To simplify the system a little, we translate
+ // our coordinates to have the origin in (x0,y0)
+
+ xs -= x0;
+ ys -= y0;
+
+ // Then we have to solve the equation:
+ // A*s^2 - 2*B*s + C = 0
+ // where
+ // A = dx^2 + dy^2 - dr^2
+ // B = xs*dx + ys*dy + r0*dr
+ // C = xs^2 + ys^2 - r0^2
+
+ b = xs*dx + ys*dy + r0*dr;
+ c = xs*xs + ys*ys - r0*r0;
+
+ if (fabs(a) <= RADIAL_EPSILON) {
+ // A is 0, thus the equation simplifies to:
+ // -2*B*s + C = 0
+ // If B is 0, we can either have no solution or an indeterminate
+ // equation, thus we behave as if we had an invalid solution
+ if (fabs(b) <= RADIAL_EPSILON)
+ return gFalse;
+
+ s0 = s1 = 0.5 * c / b;
+ } else {
+ double d;
+
+ d = b*b - a*c;
+ if (d < 0)
+ return gFalse;
+
+ d = sqrt (d);
+ s0 = b + d;
+ s1 = b - d;
+
+ // If A < 0, one of the two solutions will have negative radius,
+ // thus it will be ignored. Otherwise we know that s1 <= s0
+ // (because d >=0 implies b - d <= b + d), so if both are valid it
+ // will be the true solution.
+ s0 *= inva;
+ s1 *= inva;
+ }
+
+ if (r0 + s0 * dr >= 0) {
+ if (0 <= s0 && s0 <= 1) {
+ *t = t0 + dt * s0;
+ return gTrue;
+ } else if (s0 < 0 && shading->getExtend0()) {
+ *t = t0;
+ return gTrue;
+ } else if (s0 > 1 && shading->getExtend1()) {
+ *t = t1;
+ return gTrue;
+ }
+ }
+
+ if (r0 + s1 * dr >= 0) {
+ if (0 <= s1 && s1 <= 1) {
+ *t = t0 + dt * s1;
+ return gTrue;
+ } else if (s1 < 0 && shading->getExtend0()) {
+ *t = t0;
+ return gTrue;
+ } else if (s1 > 1 && shading->getExtend1()) {
+ *t = t1;
+ return gTrue;
+ }
+ }
+
+ return gFalse;
+}
+
+#undef RADIAL_EPSILON
+
+//------------------------------------------------------------------------
+// SplashAxialPattern
+//------------------------------------------------------------------------
+
+SplashAxialPattern::SplashAxialPattern(SplashColorMode colorModeA, GfxState *stateA, GfxAxialShading *shadingA):
+ SplashUnivariatePattern(colorModeA, stateA, shadingA)
+{
+ SplashColor defaultColor;
+ GfxColor srcColor;
+
+ shadingA->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ mul = 1 / (dx * dx + dy * dy);
+ shadingA->getColorSpace()->getDefaultColor(&srcColor);
+ convertGfxColor(defaultColor, colorModeA, shadingA->getColorSpace(), &srcColor);
+}
+
+SplashAxialPattern::~SplashAxialPattern() {
+}
+
+GBool SplashAxialPattern::getParameter(double xc, double yc, double *t) {
+ double s;
+
+ xc -= x0;
+ yc -= y0;
+
+ s = (xc * dx + yc * dy) * mul;
+ if (0 <= s && s <= 1) {
+ *t = t0 + dt * s;
+ } else if (s < 0 && shading->getExtend0()) {
+ *t = t0;
+ } else if (s > 1 && shading->getExtend1()) {
+ *t = t1;
+ } else {
+ return gFalse;
+ }
+
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// Type 3 font cache size parameters
+#define type3FontCacheAssoc 8
+#define type3FontCacheMaxSets 8
+#define type3FontCacheSize (128*1024)
+
+//------------------------------------------------------------------------
+// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
+static inline Guchar div255(int x) {
+ return (Guchar)((x + (x >> 8) + 0x80) >> 8);
+}
+
+#if SPLASH_CMYK
+
+#include "GfxState_helpers.h"
+
+//-------------------------------------------------------------------------
+// helper for Blend functions (convert CMYK to RGB, do blend, convert back)
+//-------------------------------------------------------------------------
+
+// based in GfxState.cc
+
+static void cmykToRGB(SplashColorPtr cmyk, SplashColor rgb) {
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+ c = colToDbl(byteToCol(cmyk[0]));
+ m = colToDbl(byteToCol(cmyk[1]));
+ y = colToDbl(byteToCol(cmyk[2]));
+ k = colToDbl(byteToCol(cmyk[3]));
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+ rgb[0] = colToByte(clip01(dblToCol(r)));
+ rgb[1] = colToByte(clip01(dblToCol(g)));
+ rgb[2] = colToByte(clip01(dblToCol(b)));
+}
+
+static void rgbToCMYK(SplashColor rgb, SplashColorPtr cmyk) {
+ GfxColorComp c, m, y, k;
+
+ c = clip01(gfxColorComp1 - byteToCol(rgb[0]));
+ m = clip01(gfxColorComp1 - byteToCol(rgb[1]));
+ y = clip01(gfxColorComp1 - byteToCol(rgb[2]));
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk[0] = colToByte(c - k);
+ cmyk[1] = colToByte(m - k);
+ cmyk[2] = colToByte(y - k);
+ cmyk[3] = colToByte(k);
+}
+
+#endif
+
+//------------------------------------------------------------------------
+// Blend functions
+//------------------------------------------------------------------------
+
+static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = (dest[i] * src[i]) / 255;
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255;
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] < 0x80
+ ? (src[i] * 2 * dest[i]) / 255
+ : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255;
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] < src[i] ? dest[i] : src[i];
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] > src[i] ? dest[i] : src[i];
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+ int i, x;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ if (src[i] == 255) {
+ blend[i] = 255;
+ } else {
+ x = (dest[i] * 255) / (255 - src[i]);
+ blend[i] = x <= 255 ? x : 255;
+ }
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i, x;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ if (src[i] == 0) {
+ blend[i] = 0;
+ } else {
+ x = ((255 - dest[i]) * 255) / src[i];
+ blend[i] = x <= 255 ? 255 - x : 0;
+ }
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = src[i] < 0x80
+ ? (dest[i] * 2 * src[i]) / 255
+ : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255;
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i, x;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ if (src[i] < 0x80) {
+ blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) / (255 * 255);
+ } else {
+ if (dest[i] < 0x40) {
+ x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255) + 4 * 255) * dest[i]) / 255;
+ } else {
+ x = (int)sqrt(255.0 * dest[i]);
+ }
+ blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255;
+ }
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+#endif
+}
+
+static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+ int i;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i];
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+ if (cm == splashModeDeviceN8) {
+ for (i = 4; i < splashColorModeNComps[cm]; ++i) {
+ if (dest[i] == 0 && src[i] == 0)
+ blend[i] = 0;
+ }
+ }
+#endif
+}
+
+static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ }
+ }
+#endif
+ {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255;
+ }
+ }
+#if SPLASH_CMYK
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ dest[i] = 255 - dest[i];
+ src[i] = 255 - src[i];
+ blend[i] = 255 - blend[i];
+ }
+ }
+ if (cm == splashModeDeviceN8) {
+ for (i = 4; i < splashColorModeNComps[cm]; ++i) {
+ if (dest[i] == 0 && src[i] == 0)
+ blend[i] = 0;
+ }
+ }
+#endif
+}
+
+static int getLum(int r, int g, int b) {
+ return (int)(0.3 * r + 0.59 * g + 0.11 * b);
+}
+
+static int getSat(int r, int g, int b) {
+ int rgbMin, rgbMax;
+
+ rgbMin = rgbMax = r;
+ if (g < rgbMin) {
+ rgbMin = g;
+ } else if (g > rgbMax) {
+ rgbMax = g;
+ }
+ if (b < rgbMin) {
+ rgbMin = b;
+ } else if (b > rgbMax) {
+ rgbMax = b;
+ }
+ return rgbMax - rgbMin;
+}
+
+static void clipColor(int rIn, int gIn, int bIn,
+ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
+ int lum, rgbMin, rgbMax;
+
+ lum = getLum(rIn, gIn, bIn);
+ rgbMin = rgbMax = rIn;
+ if (gIn < rgbMin) {
+ rgbMin = gIn;
+ } else if (gIn > rgbMax) {
+ rgbMax = gIn;
+ }
+ if (bIn < rgbMin) {
+ rgbMin = bIn;
+ } else if (bIn > rgbMax) {
+ rgbMax = bIn;
+ }
+ if (rgbMin < 0) {
+ *rOut = (Guchar)(lum + ((rIn - lum) * lum) / (lum - rgbMin));
+ *gOut = (Guchar)(lum + ((gIn - lum) * lum) / (lum - rgbMin));
+ *bOut = (Guchar)(lum + ((bIn - lum) * lum) / (lum - rgbMin));
+ } else if (rgbMax > 255) {
+ *rOut = (Guchar)(lum + ((rIn - lum) * (255 - lum)) / (rgbMax - lum));
+ *gOut = (Guchar)(lum + ((gIn - lum) * (255 - lum)) / (rgbMax - lum));
+ *bOut = (Guchar)(lum + ((bIn - lum) * (255 - lum)) / (rgbMax - lum));
+ } else {
+ *rOut = rIn;
+ *gOut = gIn;
+ *bOut = bIn;
+ }
+}
+
+static void setLum(Guchar rIn, Guchar gIn, Guchar bIn, int lum,
+ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
+ int d;
+
+ d = lum - getLum(rIn, gIn, bIn);
+ clipColor(rIn + d, gIn + d, bIn + d, rOut, gOut, bOut);
+}
+
+static void setSat(Guchar rIn, Guchar gIn, Guchar bIn, int sat,
+ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
+ int rgbMin, rgbMid, rgbMax;
+ Guchar *minOut, *midOut, *maxOut;
+
+ if (rIn < gIn) {
+ rgbMin = rIn; minOut = rOut;
+ rgbMid = gIn; midOut = gOut;
+ } else {
+ rgbMin = gIn; minOut = gOut;
+ rgbMid = rIn; midOut = rOut;
+ }
+ if (bIn > rgbMid) {
+ rgbMax = bIn; maxOut = bOut;
+ } else if (bIn > rgbMin) {
+ rgbMax = rgbMid; maxOut = midOut;
+ rgbMid = bIn; midOut = bOut;
+ } else {
+ rgbMax = rgbMid; maxOut = midOut;
+ rgbMid = rgbMin; midOut = minOut;
+ rgbMin = bIn; minOut = bOut;
+ }
+ if (rgbMax > rgbMin) {
+ *midOut = (Guchar)((rgbMid - rgbMin) * sat) / (rgbMax - rgbMin);
+ *maxOut = (Guchar)sat;
+ } else {
+ *midOut = *maxOut = 0;
+ }
+ *minOut = 0;
+}
+
+static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ Guchar r0, g0, b0;
+#if SPLASH_CMYK
+ Guchar r1, g1, b1;
+ int i;
+ SplashColor src2, dest2;
+#endif
+
+ switch (cm) {
+ case splashModeMono1:
+ case splashModeMono8:
+ blend[0] = dest[0];
+ break;
+ case splashModeXBGR8:
+ src[3] = 255;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]),
+ &r0, &g0, &b0);
+ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
+ &blend[0], &blend[1], &blend[2]);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ for (i = 0; i < 4; i++) {
+ // convert to additive
+ src2[i] = 0xff - src[i];
+ dest2[i] = 0xff - dest[i];
+ }
+ // NB: inputs have already been converted to additive mode
+ setSat(src2[0], src2[1], src2[2], getSat(dest2[0], dest2[1], dest2[2]),
+ &r0, &g0, &b0);
+ setLum(r0, g0, b0, getLum(dest2[0], dest2[1], dest2[2]),
+ &r1, &g1, &b1);
+ blend[0] = r1;
+ blend[1] = g1;
+ blend[2] = b1;
+ blend[3] = dest2[3];
+ for (i = 0; i < 4; i++) {
+ // convert back to subtractive
+ blend[i] = 0xff - blend[i];
+ }
+ break;
+#endif
+ }
+}
+
+static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+ Guchar r0, g0, b0;
+#if SPLASH_CMYK
+ Guchar r1, g1, b1;
+ int i;
+ SplashColor src2, dest2;
+#endif
+
+ switch (cm) {
+ case splashModeMono1:
+ case splashModeMono8:
+ blend[0] = dest[0];
+ break;
+ case splashModeXBGR8:
+ src[3] = 255;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]),
+ &r0, &g0, &b0);
+ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
+ &blend[0], &blend[1], &blend[2]);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ for (i = 0; i < 4; i++) {
+ // convert to additive
+ src2[i] = 0xff - src[i];
+ dest2[i] = 0xff - dest[i];
+ }
+ setSat(dest2[0], dest2[1], dest2[2], getSat(src2[0], src2[1], src2[2]),
+ &r0, &g0, &b0);
+ setLum(r0, g0, b0, getLum(dest2[0], dest2[1], dest2[2]),
+ &r1, &g1, &b1);
+ blend[0] = r1;
+ blend[1] = g1;
+ blend[2] = b1;
+ blend[3] = dest2[3];
+ for (i = 0; i < 4; i++) {
+ // convert back to subtractive
+ blend[i] = 0xff - blend[i];
+ }
+ break;
+#endif
+ }
+}
+
+static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+#if SPLASH_CMYK
+ Guchar r, g, b;
+ int i;
+ SplashColor src2, dest2;
+#endif
+
+ switch (cm) {
+ case splashModeMono1:
+ case splashModeMono8:
+ blend[0] = dest[0];
+ break;
+ case splashModeXBGR8:
+ src[3] = 255;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]),
+ &blend[0], &blend[1], &blend[2]);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ for (i = 0; i < 4; i++) {
+ // convert to additive
+ src2[i] = 0xff - src[i];
+ dest2[i] = 0xff - dest[i];
+ }
+ setLum(src2[0], src2[1], src2[2], getLum(dest2[0], dest2[1], dest2[2]),
+ &r, &g, &b);
+ blend[0] = r;
+ blend[1] = g;
+ blend[2] = b;
+ blend[3] = dest2[3];
+ for (i = 0; i < 4; i++) {
+ // convert back to subtractive
+ blend[i] = 0xff - blend[i];
+ }
+ break;
+#endif
+ }
+}
+
+static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+#if SPLASH_CMYK
+ Guchar r, g, b;
+ int i;
+ SplashColor src2, dest2;
+#endif
+
+ switch (cm) {
+ case splashModeMono1:
+ case splashModeMono8:
+ blend[0] = dest[0];
+ break;
+ case splashModeXBGR8:
+ src[3] = 255;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]),
+ &blend[0], &blend[1], &blend[2]);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ for (i = 0; i < 4; i++) {
+ // convert to additive
+ src2[i] = 0xff - src[i];
+ dest2[i] = 0xff - dest[i];
+ }
+ setLum(dest2[0], dest2[1], dest2[2], getLum(src2[0], src2[1], src2[2]),
+ &r, &g, &b);
+ blend[0] = r;
+ blend[1] = g;
+ blend[2] = b;
+ blend[3] = src2[3];
+ for (i = 0; i < 4; i++) {
+ // convert back to subtractive
+ blend[i] = 0xff - blend[i];
+ }
+ break;
+#endif
+ }
+}
+
+// NB: This must match the GfxBlendMode enum defined in GfxState.h.
+static const SplashBlendFunc splashOutBlendFuncs[] = {
+ NULL,
+ &splashOutBlendMultiply,
+ &splashOutBlendScreen,
+ &splashOutBlendOverlay,
+ &splashOutBlendDarken,
+ &splashOutBlendLighten,
+ &splashOutBlendColorDodge,
+ &splashOutBlendColorBurn,
+ &splashOutBlendHardLight,
+ &splashOutBlendSoftLight,
+ &splashOutBlendDifference,
+ &splashOutBlendExclusion,
+ &splashOutBlendHue,
+ &splashOutBlendSaturation,
+ &splashOutBlendColor,
+ &splashOutBlendLuminosity
+};
+
+//------------------------------------------------------------------------
+// SplashOutFontFileID
+//------------------------------------------------------------------------
+
+class SplashOutFontFileID: public SplashFontFileID {
+public:
+
+ SplashOutFontFileID(Ref *rA) { r = *rA; }
+
+ ~SplashOutFontFileID() {}
+
+ GBool matches(SplashFontFileID *id) {
+ return ((SplashOutFontFileID *)id)->r.num == r.num &&
+ ((SplashOutFontFileID *)id)->r.gen == r.gen;
+ }
+
+private:
+
+ Ref r;
+};
+
+//------------------------------------------------------------------------
+// T3FontCache
+//------------------------------------------------------------------------
+
+struct T3FontCacheTag {
+ Gushort code;
+ Gushort mru; // valid bit (0x8000) and MRU index
+};
+
+class T3FontCache {
+public:
+
+ T3FontCache(Ref *fontID, double m11A, double m12A,
+ double m21A, double m22A,
+ int glyphXA, int glyphYA, int glyphWA, int glyphHA,
+ GBool aa, GBool validBBoxA);
+ ~T3FontCache();
+ GBool matches(Ref *idA, double m11A, double m12A,
+ double m21A, double m22A)
+ { return fontID.num == idA->num && fontID.gen == idA->gen &&
+ m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
+
+ Ref fontID; // PDF font ID
+ double m11, m12, m21, m22; // transform matrix
+ int glyphX, glyphY; // pixel offset of glyph bitmaps
+ int glyphW, glyphH; // size of glyph bitmaps, in pixels
+ GBool validBBox; // false if the bbox was [0 0 0 0]
+ int glyphSize; // size of glyph bitmaps, in bytes
+ int cacheSets; // number of sets in cache
+ int cacheAssoc; // cache associativity (glyphs per set)
+ Guchar *cacheData; // glyph pixmap cache
+ T3FontCacheTag *cacheTags; // cache tags, i.e., char codes
+};
+
+T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
+ double m21A, double m22A,
+ int glyphXA, int glyphYA, int glyphWA, int glyphHA,
+ GBool validBBoxA, GBool aa) {
+ int i;
+
+ fontID = *fontIDA;
+ m11 = m11A;
+ m12 = m12A;
+ m21 = m21A;
+ m22 = m22A;
+ glyphX = glyphXA;
+ glyphY = glyphYA;
+ glyphW = glyphWA;
+ glyphH = glyphHA;
+ validBBox = validBBoxA;
+ // sanity check for excessively large glyphs (which most likely
+ // indicate an incorrect BBox)
+ i = glyphW * glyphH;
+ if (i > 100000 || glyphW > INT_MAX / glyphH || glyphW <= 0 || glyphH <= 0) {
+ glyphW = glyphH = 100;
+ validBBox = gFalse;
+ }
+ if (aa) {
+ glyphSize = glyphW * glyphH;
+ } else {
+ glyphSize = ((glyphW + 7) >> 3) * glyphH;
+ }
+ cacheAssoc = type3FontCacheAssoc;
+ for (cacheSets = type3FontCacheMaxSets;
+ cacheSets > 1 &&
+ cacheSets * cacheAssoc * glyphSize > type3FontCacheSize;
+ cacheSets >>= 1) ;
+ if (glyphSize < 10485760 / cacheAssoc / cacheSets) {
+ cacheData = (Guchar *)gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize);
+ } else {
+ error(errSyntaxWarning, -1, "Not creating cacheData for T3FontCache, it asked for too much memory.\n"
+ " This could teoretically result in wrong rendering,\n"
+ " but most probably the document is bogus.\n"
+ " Please report a bug if you think the rendering may be wrong because of this.");
+ cacheData = NULL;
+ }
+ if (cacheData != NULL)
+ {
+ cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc,
+ sizeof(T3FontCacheTag));
+ for (i = 0; i < cacheSets * cacheAssoc; ++i) {
+ cacheTags[i].mru = i & (cacheAssoc - 1);
+ }
+ }
+ else
+ {
+ cacheTags = NULL;
+ }
+}
+
+T3FontCache::~T3FontCache() {
+ gfree(cacheData);
+ gfree(cacheTags);
+}
+
+struct T3GlyphStack {
+ Gushort code; // character code
+
+ //----- cache info
+ T3FontCache *cache; // font cache for the current font
+ T3FontCacheTag *cacheTag; // pointer to cache tag for the glyph
+ Guchar *cacheData; // pointer to cache data for the glyph
+
+ //----- saved state
+ SplashBitmap *origBitmap;
+ Splash *origSplash;
+ double origCTM4, origCTM5;
+
+ T3GlyphStack *next; // next object on stack
+};
+
+//------------------------------------------------------------------------
+// SplashTransparencyGroup
+//------------------------------------------------------------------------
+
+struct SplashTransparencyGroup {
+ int tx, ty; // translation coordinates
+ SplashBitmap *tBitmap; // bitmap for transparency group
+ SplashBitmap *softmask; // bitmap for softmasks
+ GfxColorSpace *blendingColorSpace;
+ GBool isolated;
+
+ //----- for knockout
+ SplashBitmap *shape;
+ GBool knockout;
+ SplashCoord knockoutOpacity;
+ GBool fontAA;
+
+ //----- saved state
+ SplashBitmap *origBitmap;
+ Splash *origSplash;
+
+ SplashTransparencyGroup *next;
+};
+
+//------------------------------------------------------------------------
+// SplashOutputDev
+//------------------------------------------------------------------------
+
+SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
+ int bitmapRowPadA,
+ GBool reverseVideoA,
+ SplashColorPtr paperColorA,
+ GBool bitmapTopDownA,
+ SplashThinLineMode thinLineMode,
+ GBool overprintPreviewA) {
+ colorMode = colorModeA;
+ bitmapRowPad = bitmapRowPadA;
+ bitmapTopDown = bitmapTopDownA;
+ bitmapUpsideDown = gFalse;
+ fontAntialias = gTrue;
+ vectorAntialias = gTrue;
+ overprintPreview = overprintPreviewA;
+ enableFreeTypeHinting = gFalse;
+ enableSlightHinting = gFalse;
+ setupScreenParams(72.0, 72.0);
+ reverseVideo = reverseVideoA;
+ if (paperColorA != NULL) {
+ splashColorCopy(paperColor, paperColorA);
+ } else {
+ splashClearColor(paperColor);
+ }
+ skipHorizText = gFalse;
+ skipRotatedText = gFalse;
+ keepAlphaChannel = paperColorA == NULL;
+
+ doc = NULL;
+
+ bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ splash = new Splash(bitmap, vectorAntialias, &screenParams);
+ splash->setMinLineWidth(globalParams->getMinLineWidth());
+ splash->setThinLineMode(thinLineMode);
+ splash->clear(paperColor, 0);
+
+ fontEngine = NULL;
+
+ nT3Fonts = 0;
+ t3GlyphStack = NULL;
+
+ font = NULL;
+ needFontUpdate = gFalse;
+ textClipPath = NULL;
+ transpGroupStack = NULL;
+ nestCount = 0;
+ xref = NULL;
+}
+
+void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) {
+ screenParams.size = globalParams->getScreenSize();
+ screenParams.dotRadius = globalParams->getScreenDotRadius();
+ screenParams.gamma = (SplashCoord)globalParams->getScreenGamma();
+ screenParams.blackThreshold =
+ (SplashCoord)globalParams->getScreenBlackThreshold();
+ screenParams.whiteThreshold =
+ (SplashCoord)globalParams->getScreenWhiteThreshold();
+ switch (globalParams->getScreenType()) {
+ case screenDispersed:
+ screenParams.type = splashScreenDispersed;
+ if (screenParams.size < 0) {
+ screenParams.size = 4;
+ }
+ break;
+ case screenClustered:
+ screenParams.type = splashScreenClustered;
+ if (screenParams.size < 0) {
+ screenParams.size = 10;
+ }
+ break;
+ case screenStochasticClustered:
+ screenParams.type = splashScreenStochasticClustered;
+ if (screenParams.size < 0) {
+ screenParams.size = 64;
+ }
+ if (screenParams.dotRadius < 0) {
+ screenParams.dotRadius = 2;
+ }
+ break;
+ case screenUnset:
+ default:
+ // use clustered dithering for resolution >= 300 dpi
+ // (compare to 299.9 to avoid floating point issues)
+ if (hDPI > 299.9 && vDPI > 299.9) {
+ screenParams.type = splashScreenStochasticClustered;
+ if (screenParams.size < 0) {
+ screenParams.size = 64;
+ }
+ if (screenParams.dotRadius < 0) {
+ screenParams.dotRadius = 2;
+ }
+ } else {
+ screenParams.type = splashScreenDispersed;
+ if (screenParams.size < 0) {
+ screenParams.size = 4;
+ }
+ }
+ }
+}
+
+SplashOutputDev::~SplashOutputDev() {
+ int i;
+
+ for (i = 0; i < nT3Fonts; ++i) {
+ delete t3FontCache[i];
+ }
+ if (fontEngine) {
+ delete fontEngine;
+ }
+ if (splash) {
+ delete splash;
+ }
+ if (bitmap) {
+ delete bitmap;
+ }
+}
+
+void SplashOutputDev::startDoc(PDFDoc *docA) {
+ int i;
+
+ doc = docA;
+ if (fontEngine) {
+ delete fontEngine;
+ }
+ fontEngine = new SplashFontEngine(
+#if HAVE_T1LIB_H
+ globalParams->getEnableT1lib(),
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ globalParams->getEnableFreeType(),
+ enableFreeTypeHinting,
+ enableSlightHinting,
+#endif
+ getFontAntialias() &&
+ colorMode != splashModeMono1);
+ for (i = 0; i < nT3Fonts; ++i) {
+ delete t3FontCache[i];
+ }
+ nT3Fonts = 0;
+}
+
+void SplashOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) {
+ int w, h;
+ double *ctm;
+ SplashCoord mat[6];
+ SplashColor color;
+
+ xref = xrefA;
+ if (state) {
+ setupScreenParams(state->getHDPI(), state->getVDPI());
+ w = (int)(state->getPageWidth() + 0.5);
+ if (w <= 0) {
+ w = 1;
+ }
+ h = (int)(state->getPageHeight() + 0.5);
+ if (h <= 0) {
+ h = 1;
+ }
+ } else {
+ w = h = 1;
+ }
+ SplashThinLineMode thinLineMode = splashThinLineDefault;
+ if (splash) {
+ thinLineMode = splash->getThinLineMode();
+ delete splash;
+ splash = NULL;
+ }
+ if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) {
+ if (bitmap) {
+ delete bitmap;
+ bitmap = NULL;
+ }
+ bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ if (!bitmap->getDataPtr()) {
+ delete bitmap;
+ w = h = 1;
+ bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ }
+ }
+ splash = new Splash(bitmap, vectorAntialias, &screenParams);
+ splash->setThinLineMode(thinLineMode);
+ splash->setMinLineWidth(globalParams->getMinLineWidth());
+ if (state) {
+ ctm = state->getCTM();
+ mat[0] = (SplashCoord)ctm[0];
+ mat[1] = (SplashCoord)ctm[1];
+ mat[2] = (SplashCoord)ctm[2];
+ mat[3] = (SplashCoord)ctm[3];
+ mat[4] = (SplashCoord)ctm[4];
+ mat[5] = (SplashCoord)ctm[5];
+ splash->setMatrix(mat);
+ }
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ color[0] = 0;
+ break;
+ case splashModeXBGR8:
+ color[3] = 255;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ color[0] = color[1] = color[2] = 0;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ color[0] = color[1] = color[2] = color[3] = 0;
+ break;
+ case splashModeDeviceN8:
+ for (int i = 0; i < 4 + SPOT_NCOMPS; i++)
+ color[i] = 0;
+ break;
+#endif
+ }
+ splash->setStrokePattern(new SplashSolidColor(color));
+ splash->setFillPattern(new SplashSolidColor(color));
+ splash->setLineCap(splashLineCapButt);
+ splash->setLineJoin(splashLineJoinMiter);
+ splash->setLineDash(NULL, 0, 0);
+ splash->setMiterLimit(10);
+ splash->setFlatness(1);
+ // the SA parameter supposedly defaults to false, but Acrobat
+ // apparently hardwires it to true
+ splash->setStrokeAdjust(globalParams->getStrokeAdjust());
+ splash->clear(paperColor, 0);
+}
+
+void SplashOutputDev::endPage() {
+ if (colorMode != splashModeMono1 && !keepAlphaChannel) {
+ splash->compositeBackground(paperColor);
+ }
+}
+
+void SplashOutputDev::saveState(GfxState *state) {
+ splash->saveState();
+}
+
+void SplashOutputDev::restoreState(GfxState *state) {
+ splash->restoreState();
+ needFontUpdate = gTrue;
+}
+
+void SplashOutputDev::updateAll(GfxState *state) {
+ updateLineDash(state);
+ updateLineJoin(state);
+ updateLineCap(state);
+ updateLineWidth(state);
+ updateFlatness(state);
+ updateMiterLimit(state);
+ updateStrokeAdjust(state);
+ updateFillColorSpace(state);
+ updateFillColor(state);
+ updateStrokeColorSpace(state);
+ updateStrokeColor(state);
+ needFontUpdate = gTrue;
+}
+
+void SplashOutputDev::updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22,
+ double m31, double m32) {
+ double *ctm;
+ SplashCoord mat[6];
+
+ ctm = state->getCTM();
+ mat[0] = (SplashCoord)ctm[0];
+ mat[1] = (SplashCoord)ctm[1];
+ mat[2] = (SplashCoord)ctm[2];
+ mat[3] = (SplashCoord)ctm[3];
+ mat[4] = (SplashCoord)ctm[4];
+ mat[5] = (SplashCoord)ctm[5];
+ splash->setMatrix(mat);
+}
+
+void SplashOutputDev::updateLineDash(GfxState *state) {
+ double *dashPattern;
+ int dashLength;
+ double dashStart;
+ SplashCoord dash[20];
+ int i;
+
+ state->getLineDash(&dashPattern, &dashLength, &dashStart);
+ if (dashLength > 20) {
+ dashLength = 20;
+ }
+ for (i = 0; i < dashLength; ++i) {
+ dash[i] = (SplashCoord)dashPattern[i];
+ if (dash[i] < 0) {
+ dash[i] = 0;
+ }
+ }
+ splash->setLineDash(dash, dashLength, (SplashCoord)dashStart);
+}
+
+void SplashOutputDev::updateFlatness(GfxState *state) {
+#if 0 // Acrobat ignores the flatness setting, and always renders curves
+ // with a fairly small flatness value
+ splash->setFlatness(state->getFlatness());
+#endif
+}
+
+void SplashOutputDev::updateLineJoin(GfxState *state) {
+ splash->setLineJoin(state->getLineJoin());
+}
+
+void SplashOutputDev::updateLineCap(GfxState *state) {
+ splash->setLineCap(state->getLineCap());
+}
+
+void SplashOutputDev::updateMiterLimit(GfxState *state) {
+ splash->setMiterLimit(state->getMiterLimit());
+}
+
+void SplashOutputDev::updateLineWidth(GfxState *state) {
+ splash->setLineWidth(state->getLineWidth());
+}
+
+void SplashOutputDev::updateStrokeAdjust(GfxState * /*state*/) {
+#if 0 // the SA parameter supposedly defaults to false, but Acrobat
+ // apparently hardwires it to true
+ splash->setStrokeAdjust(state->getStrokeAdjust());
+#endif
+}
+
+void SplashOutputDev::updateFillColorSpace(GfxState *state) {
+#if SPLASH_CMYK
+ if (colorMode == splashModeDeviceN8)
+ state->getFillColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+}
+
+void SplashOutputDev::updateStrokeColorSpace(GfxState *state) {
+#if SPLASH_CMYK
+ if (colorMode == splashModeDeviceN8)
+ state->getStrokeColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+}
+
+void SplashOutputDev::updateFillColor(GfxState *state) {
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ state->getFillGray(&gray);
+ splash->setFillPattern(getColor(gray));
+ break;
+ case splashModeXBGR8:
+ case splashModeRGB8:
+ case splashModeBGR8:
+ state->getFillRGB(&rgb);
+ splash->setFillPattern(getColor(&rgb));
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ state->getFillCMYK(&cmyk);
+ splash->setFillPattern(getColor(&cmyk));
+ break;
+ case splashModeDeviceN8:
+ state->getFillDeviceN(&deviceN);
+ splash->setFillPattern(getColor(&deviceN));
+ break;
+#endif
+ }
+}
+
+void SplashOutputDev::updateStrokeColor(GfxState *state) {
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ state->getStrokeGray(&gray);
+ splash->setStrokePattern(getColor(gray));
+ break;
+ case splashModeXBGR8:
+ case splashModeRGB8:
+ case splashModeBGR8:
+ state->getStrokeRGB(&rgb);
+ splash->setStrokePattern(getColor(&rgb));
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ state->getStrokeCMYK(&cmyk);
+ splash->setStrokePattern(getColor(&cmyk));
+ break;
+ case splashModeDeviceN8:
+ state->getStrokeDeviceN(&deviceN);
+ splash->setStrokePattern(getColor(&deviceN));
+ break;
+#endif
+ }
+}
+
+SplashPattern *SplashOutputDev::getColor(GfxGray gray) {
+ SplashColor color;
+
+ if (reverseVideo) {
+ gray = gfxColorComp1 - gray;
+ }
+ color[0] = colToByte(gray);
+ return new SplashSolidColor(color);
+}
+
+SplashPattern *SplashOutputDev::getColor(GfxRGB *rgb) {
+ GfxColorComp r, g, b;
+ SplashColor color;
+
+ if (reverseVideo) {
+ r = gfxColorComp1 - rgb->r;
+ g = gfxColorComp1 - rgb->g;
+ b = gfxColorComp1 - rgb->b;
+ } else {
+ r = rgb->r;
+ g = rgb->g;
+ b = rgb->b;
+ }
+ color[0] = colToByte(r);
+ color[1] = colToByte(g);
+ color[2] = colToByte(b);
+ if (colorMode == splashModeXBGR8) color[3] = 255;
+ return new SplashSolidColor(color);
+}
+
+#if SPLASH_CMYK
+SplashPattern *SplashOutputDev::getColor(GfxCMYK *cmyk) {
+ SplashColor color;
+
+ color[0] = colToByte(cmyk->c);
+ color[1] = colToByte(cmyk->m);
+ color[2] = colToByte(cmyk->y);
+ color[3] = colToByte(cmyk->k);
+ return new SplashSolidColor(color);
+}
+
+SplashPattern *SplashOutputDev::getColor(GfxColor *deviceN) {
+ SplashColor color;
+
+ for (int i = 0; i < 4 + SPOT_NCOMPS; i++)
+ color[i] = colToByte(deviceN->c[i]);
+ return new SplashSolidColor(color);
+}
+#endif
+
+void SplashOutputDev::setOverprintMask(GfxColorSpace *colorSpace,
+ GBool overprintFlag,
+ int overprintMode,
+ GfxColor *singleColor,
+ GBool grayIndexed) {
+#if SPLASH_CMYK
+ Guint mask;
+ GfxCMYK cmyk;
+ GBool additive = gFalse;
+ int i;
+
+ if (colorSpace->getMode() == csIndexed) {
+ setOverprintMask(((GfxIndexedColorSpace *)colorSpace)->getBase(),
+ overprintFlag,
+ overprintMode,
+ singleColor,
+ grayIndexed);
+ return;
+ }
+ if (overprintFlag && overprintPreview) {
+ mask = colorSpace->getOverprintMask();
+ if (singleColor && overprintMode &&
+ colorSpace->getMode() == csDeviceCMYK) {
+ colorSpace->getCMYK(singleColor, &cmyk);
+ if (cmyk.c == 0) {
+ mask &= ~1;
+ }
+ if (cmyk.m == 0) {
+ mask &= ~2;
+ }
+ if (cmyk.y == 0) {
+ mask &= ~4;
+ }
+ if (cmyk.k == 0) {
+ mask &= ~8;
+ }
+ }
+ if (grayIndexed) {
+ mask &= ~7;
+ } else if (colorSpace->getMode() == csSeparation) {
+ GfxSeparationColorSpace *deviceSep = (GfxSeparationColorSpace *)colorSpace;
+ additive = deviceSep->getName()->cmp("All") != 0 && mask == 0x0f && !deviceSep->isNonMarking();
+ } else if (colorSpace->getMode() == csDeviceN) {
+ GfxDeviceNColorSpace *deviceNCS = (GfxDeviceNColorSpace *)colorSpace;
+ additive = mask == 0x0f && !deviceNCS->isNonMarking();
+ for (i = 0; i < deviceNCS->getNComps() && additive; i++) {
+ if (deviceNCS->getColorantName(i)->cmp("Cyan") == 0) {
+ additive = gFalse;
+ } else if (deviceNCS->getColorantName(i)->cmp("Magenta") == 0) {
+ additive = gFalse;
+ } else if (deviceNCS->getColorantName(i)->cmp("Yellow") == 0) {
+ additive = gFalse;
+ } else if (deviceNCS->getColorantName(i)->cmp("Black") == 0) {
+ additive = gFalse;
+ }
+ }
+ }
+ } else {
+ mask = 0xffffffff;
+ }
+ splash->setOverprintMask(mask, additive);
+#endif
+}
+
+void SplashOutputDev::updateBlendMode(GfxState *state) {
+ splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]);
+}
+
+void SplashOutputDev::updateFillOpacity(GfxState *state) {
+ splash->setFillAlpha((SplashCoord)state->getFillOpacity());
+ if (transpGroupStack != NULL && (SplashCoord)state->getFillOpacity() < transpGroupStack->knockoutOpacity) {
+ transpGroupStack->knockoutOpacity = (SplashCoord)state->getFillOpacity();
+ }
+}
+
+void SplashOutputDev::updateStrokeOpacity(GfxState *state) {
+ splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity());
+ if (transpGroupStack != NULL && (SplashCoord)state->getStrokeOpacity() < transpGroupStack->knockoutOpacity) {
+ transpGroupStack->knockoutOpacity = (SplashCoord)state->getStrokeOpacity();
+ }
+}
+
+void SplashOutputDev::updateFillOverprint(GfxState *state) {
+ splash->setFillOverprint(state->getFillOverprint());
+}
+
+void SplashOutputDev::updateStrokeOverprint(GfxState *state) {
+ splash->setStrokeOverprint(state->getStrokeOverprint());
+}
+
+void SplashOutputDev::updateOverprintMode(GfxState *state) {
+ splash->setOverprintMode(state->getOverprintMode());
+}
+
+void SplashOutputDev::updateTransfer(GfxState *state) {
+ Function **transfer;
+ Guchar red[256], green[256], blue[256], gray[256];
+ double x, y;
+ int i;
+
+ transfer = state->getTransfer();
+ if (transfer[0] &&
+ transfer[0]->getInputSize() == 1 &&
+ transfer[0]->getOutputSize() == 1) {
+ if (transfer[1] &&
+ transfer[1]->getInputSize() == 1 &&
+ transfer[1]->getOutputSize() == 1 &&
+ transfer[2] &&
+ transfer[2]->getInputSize() == 1 &&
+ transfer[2]->getOutputSize() == 1 &&
+ transfer[3] &&
+ transfer[3]->getInputSize() == 1 &&
+ transfer[3]->getOutputSize() == 1) {
+ for (i = 0; i < 256; ++i) {
+ x = i / 255.0;
+ transfer[0]->transform(&x, &y);
+ red[i] = (Guchar)(y * 255.0 + 0.5);
+ transfer[1]->transform(&x, &y);
+ green[i] = (Guchar)(y * 255.0 + 0.5);
+ transfer[2]->transform(&x, &y);
+ blue[i] = (Guchar)(y * 255.0 + 0.5);
+ transfer[3]->transform(&x, &y);
+ gray[i] = (Guchar)(y * 255.0 + 0.5);
+ }
+ } else {
+ for (i = 0; i < 256; ++i) {
+ x = i / 255.0;
+ transfer[0]->transform(&x, &y);
+ red[i] = green[i] = blue[i] = gray[i] = (Guchar)(y * 255.0 + 0.5);
+ }
+ }
+ } else {
+ for (i = 0; i < 256; ++i) {
+ red[i] = green[i] = blue[i] = gray[i] = (Guchar)i;
+ }
+ }
+ splash->setTransfer(red, green, blue, gray);
+}
+
+void SplashOutputDev::updateFont(GfxState * /*state*/) {
+ needFontUpdate = gTrue;
+}
+
+void SplashOutputDev::doUpdateFont(GfxState *state) {
+ GfxFont *gfxFont;
+ GfxFontLoc *fontLoc;
+ GfxFontType fontType;
+ SplashOutFontFileID *id;
+ SplashFontFile *fontFile;
+ SplashFontSrc *fontsrc = NULL;
+ FoFiTrueType *ff;
+ Object refObj, strObj;
+ GooString *fileName;
+ char *tmpBuf;
+ int tmpBufLen;
+ int *codeToGID;
+ double *textMat;
+ double m11, m12, m21, m22, fontSize;
+ int faceIndex = 0;
+ SplashCoord mat[4];
+ int n, i;
+ GBool recreateFont = gFalse;
+ GBool doAdjustFontMatrix = gFalse;
+
+ needFontUpdate = gFalse;
+ font = NULL;
+ fileName = NULL;
+ tmpBuf = NULL;
+ fontLoc = NULL;
+
+ if (!(gfxFont = state->getFont())) {
+ goto err1;
+ }
+ fontType = gfxFont->getType();
+ if (fontType == fontType3) {
+ goto err1;
+ }
+
+ // sanity-check the font size - skip anything larger than 10 inches
+ // (this avoids problems allocating memory for the font cache)
+ if (state->getTransformedFontSize()
+ > 10 * (state->getHDPI() + state->getVDPI())) {
+ goto err1;
+ }
+
+ // check the font file cache
+ id = new SplashOutFontFileID(gfxFont->getID());
+ if ((fontFile = fontEngine->getFontFile(id))) {
+ delete id;
+
+ } else {
+
+ if (!(fontLoc = gfxFont->locateFont((xref) ? xref : doc->getXRef(), NULL))) {
+ error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+
+ // embedded font
+ if (fontLoc->locType == gfxFontLocEmbedded) {
+ // if there is an embedded font, read it to memory
+ tmpBuf = gfxFont->readEmbFontFile((xref) ? xref : doc->getXRef(), &tmpBufLen);
+ if (! tmpBuf)
+ goto err2;
+
+ // external font
+ } else { // gfxFontLocExternal
+ fileName = fontLoc->path;
+ fontType = fontLoc->fontType;
+ doAdjustFontMatrix = gTrue;
+ }
+
+ fontsrc = new SplashFontSrc;
+ if (fileName)
+ fontsrc->setFile(fileName, gFalse);
+ else
+ fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue);
+
+ // load the font file
+ switch (fontType) {
+ case fontType1:
+ if (!(fontFile = fontEngine->loadType1Font(
+ id,
+ fontsrc,
+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontType1C:
+ if (!(fontFile = fontEngine->loadType1CFont(
+ id,
+ fontsrc,
+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontType1COT:
+ if (!(fontFile = fontEngine->loadOpenTypeT1CFont(
+ id,
+ fontsrc,
+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontTrueType:
+ case fontTrueTypeOT:
+ if (fileName)
+ ff = FoFiTrueType::load(fileName->getCString());
+ else
+ ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
+ if (ff) {
+ codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
+ n = 256;
+ delete ff;
+ // if we're substituting for a non-TrueType font, we need to mark
+ // all notdef codes as "do not draw" (rather than drawing TrueType
+ // notdef glyphs)
+ if (gfxFont->getType() != fontTrueType &&
+ gfxFont->getType() != fontTrueTypeOT) {
+ for (i = 0; i < 256; ++i) {
+ if (codeToGID[i] == 0) {
+ codeToGID[i] = -1;
+ }
+ }
+ }
+ } else {
+ codeToGID = NULL;
+ n = 0;
+ }
+ if (!(fontFile = fontEngine->loadTrueTypeFont(
+ id,
+ fontsrc,
+ codeToGID, n))) {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontCIDType0:
+ case fontCIDType0C:
+ if (!(fontFile = fontEngine->loadCIDFont(
+ id,
+ fontsrc))) {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontCIDType0COT:
+ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
+ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
+ codeToGID = (int *)gmallocn(n, sizeof(int));
+ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
+ n * sizeof(int));
+ } else {
+ codeToGID = NULL;
+ n = 0;
+ }
+ if (!(fontFile = fontEngine->loadOpenTypeCFFFont(
+ id,
+ fontsrc,
+ codeToGID, n))) {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontCIDType2:
+ case fontCIDType2OT:
+ codeToGID = NULL;
+ n = 0;
+ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
+ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
+ if (n) {
+ codeToGID = (int *)gmallocn(n, sizeof(int));
+ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
+ n * sizeof(int));
+ }
+ } else {
+ if (fileName)
+ ff = FoFiTrueType::load(fileName->getCString());
+ else
+ ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
+ if (! ff)
+ {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
+ delete ff;
+ }
+ if (!(fontFile = fontEngine->loadTrueTypeFont(
+ id,
+ fontsrc,
+ codeToGID, n, faceIndex))) {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ default:
+ // this shouldn't happen
+ goto err2;
+ }
+ fontFile->doAdjustMatrix = doAdjustFontMatrix;
+ }
+
+ // get the font matrix
+ textMat = state->getTextMat();
+ fontSize = state->getFontSize();
+ m11 = textMat[0] * fontSize * state->getHorizScaling();
+ m12 = textMat[1] * fontSize * state->getHorizScaling();
+ m21 = textMat[2] * fontSize;
+ m22 = textMat[3] * fontSize;
+
+ // create the scaled font
+ mat[0] = m11; mat[1] = m12;
+ mat[2] = m21; mat[3] = m22;
+ font = fontEngine->getFont(fontFile, mat, splash->getMatrix());
+
+ // for substituted fonts: adjust the font matrix -- compare the
+ // width of 'm' in the original font and the substituted font
+ if (fontFile->doAdjustMatrix && !gfxFont->isCIDFont()) {
+ double w1, w2;
+ CharCode code;
+ char *name;
+ for (code = 0; code < 256; ++code) {
+ if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
+ name[0] == 'm' && name[1] == '\0') {
+ break;
+ }
+ }
+ if (code < 256) {
+ w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
+ w2 = font->getGlyphAdvance(code);
+ if (!gfxFont->isSymbolic() && w2 > 0) {
+ // if real font is substantially narrower than substituted
+ // font, reduce the font size accordingly
+ if (w1 > 0.01 && w1 < 0.9 * w2) {
+ w1 /= w2;
+ m11 *= w1;
+ m21 *= w1;
+ recreateFont = gTrue;
+ }
+ }
+ }
+ }
+
+ if (recreateFont)
+ {
+ mat[0] = m11; mat[1] = m12;
+ mat[2] = m21; mat[3] = m22;
+ font = fontEngine->getFont(fontFile, mat, splash->getMatrix());
+ }
+
+ delete fontLoc;
+ if (fontsrc && !fontsrc->isFile)
+ fontsrc->unref();
+ return;
+
+ err2:
+ delete id;
+ delete fontLoc;
+ err1:
+ if (fontsrc && !fontsrc->isFile)
+ fontsrc->unref();
+ return;
+}
+
+void SplashOutputDev::stroke(GfxState *state) {
+ SplashPath *path;
+
+ if (state->getStrokeColorSpace()->isNonMarking()) {
+ return;
+ }
+ setOverprintMask(state->getStrokeColorSpace(), state->getStrokeOverprint(),
+ state->getOverprintMode(), state->getStrokeColor());
+ path = convertPath(state, state->getPath(), gFalse);
+ splash->stroke(path);
+ delete path;
+}
+
+void SplashOutputDev::fill(GfxState *state) {
+ SplashPath *path;
+
+ if (state->getFillColorSpace()->isNonMarking()) {
+ return;
+ }
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
+ path = convertPath(state, state->getPath(), gTrue);
+ splash->fill(path, gFalse);
+ delete path;
+}
+
+void SplashOutputDev::eoFill(GfxState *state) {
+ SplashPath *path;
+
+ if (state->getFillColorSpace()->isNonMarking()) {
+ return;
+ }
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
+ path = convertPath(state, state->getPath(), gTrue);
+ splash->fill(path, gTrue);
+ delete path;
+}
+
+void SplashOutputDev::clip(GfxState *state) {
+ SplashPath *path;
+
+ path = convertPath(state, state->getPath(), gTrue);
+ splash->clipToPath(path, gFalse);
+ delete path;
+}
+
+void SplashOutputDev::eoClip(GfxState *state) {
+ SplashPath *path;
+
+ path = convertPath(state, state->getPath(), gTrue);
+ splash->clipToPath(path, gTrue);
+ delete path;
+}
+
+void SplashOutputDev::clipToStrokePath(GfxState *state) {
+ SplashPath *path, *path2;
+
+ path = convertPath(state, state->getPath(), gFalse);
+ path2 = splash->makeStrokePath(path, state->getLineWidth());
+ delete path;
+ splash->clipToPath(path2, gFalse);
+ delete path2;
+}
+
+SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path,
+ GBool dropEmptySubpaths) {
+ SplashPath *sPath;
+ GfxSubpath *subpath;
+ int n, i, j;
+
+ n = dropEmptySubpaths ? 1 : 0;
+ sPath = new SplashPath();
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ if (subpath->getNumPoints() > n) {
+ sPath->moveTo((SplashCoord)subpath->getX(0),
+ (SplashCoord)subpath->getY(0));
+ j = 1;
+ while (j < subpath->getNumPoints()) {
+ if (subpath->getCurve(j)) {
+ sPath->curveTo((SplashCoord)subpath->getX(j),
+ (SplashCoord)subpath->getY(j),
+ (SplashCoord)subpath->getX(j+1),
+ (SplashCoord)subpath->getY(j+1),
+ (SplashCoord)subpath->getX(j+2),
+ (SplashCoord)subpath->getY(j+2));
+ j += 3;
+ } else {
+ sPath->lineTo((SplashCoord)subpath->getX(j),
+ (SplashCoord)subpath->getY(j));
+ ++j;
+ }
+ }
+ if (subpath->isClosed()) {
+ sPath->close();
+ }
+ }
+ }
+ return sPath;
+}
+
+void SplashOutputDev::drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode code, int nBytes,
+ Unicode *u, int uLen) {
+ SplashPath *path;
+ int render;
+ GBool doFill, doStroke, doClip, strokeAdjust;
+ double m[4];
+ GBool horiz;
+
+ if (skipHorizText || skipRotatedText) {
+ state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
+ horiz = m[0] > 0 && fabs(m[1]) < 0.001 &&
+ fabs(m[2]) < 0.001 && m[3] < 0;
+ if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) {
+ return;
+ }
+ }
+
+ // check for invisible text -- this is used by Acrobat Capture
+ render = state->getRender();
+ if (render == 3) {
+ return;
+ }
+
+ if (needFontUpdate) {
+ doUpdateFont(state);
+ }
+ if (!font) {
+ return;
+ }
+
+ x -= originX;
+ y -= originY;
+
+ doFill = !(render & 1) && !state->getFillColorSpace()->isNonMarking();
+ doStroke = ((render & 3) == 1 || (render & 3) == 2) &&
+ !state->getStrokeColorSpace()->isNonMarking();
+ doClip = render & 4;
+
+ path = NULL;
+ if (doStroke || doClip) {
+ if ((path = font->getGlyphPath(code))) {
+ path->offset((SplashCoord)x, (SplashCoord)y);
+ }
+ }
+
+ // don't use stroke adjustment when stroking text -- the results
+ // tend to be ugly (because characters with horizontal upper or
+ // lower edges get misaligned relative to the other characters)
+ strokeAdjust = gFalse; // make gcc happy
+ if (doStroke) {
+ strokeAdjust = splash->getStrokeAdjust();
+ splash->setStrokeAdjust(gFalse);
+ }
+
+ // fill and stroke
+ if (doFill && doStroke) {
+ if (path) {
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
+ splash->fill(path, gFalse);
+ setOverprintMask(state->getStrokeColorSpace(),
+ state->getStrokeOverprint(),
+ state->getOverprintMode(),
+ state->getStrokeColor());
+ splash->stroke(path);
+ }
+
+ // fill
+ } else if (doFill) {
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
+ splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
+
+ // stroke
+ } else if (doStroke) {
+ if (path) {
+ setOverprintMask(state->getStrokeColorSpace(),
+ state->getStrokeOverprint(),
+ state->getOverprintMode(),
+ state->getStrokeColor());
+ splash->stroke(path);
+ }
+ }
+
+ // clip
+ if (doClip) {
+ if (path) {
+ if (textClipPath) {
+ textClipPath->append(path);
+ } else {
+ textClipPath = path;
+ path = NULL;
+ }
+ }
+ }
+
+ if (doStroke) {
+ splash->setStrokeAdjust(strokeAdjust);
+ }
+
+ if (path) {
+ delete path;
+ }
+}
+
+GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen) {
+ GfxFont *gfxFont;
+ Ref *fontID;
+ double *ctm, *bbox;
+ T3FontCache *t3Font;
+ T3GlyphStack *t3gs;
+ GBool validBBox;
+ double m[4];
+ GBool horiz;
+ double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
+ int i, j;
+
+ if (skipHorizText || skipRotatedText) {
+ state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
+ horiz = m[0] > 0 && fabs(m[1]) < 0.001 &&
+ fabs(m[2]) < 0.001 && m[3] < 0;
+ if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) {
+ return gTrue;
+ }
+ }
+
+ if (!(gfxFont = state->getFont())) {
+ return gFalse;
+ }
+ fontID = gfxFont->getID();
+ ctm = state->getCTM();
+ state->transform(0, 0, &xt, &yt);
+
+ // is it the first (MRU) font in the cache?
+ if (!(nT3Fonts > 0 &&
+ t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
+
+ // is the font elsewhere in the cache?
+ for (i = 1; i < nT3Fonts; ++i) {
+ if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
+ t3Font = t3FontCache[i];
+ for (j = i; j > 0; --j) {
+ t3FontCache[j] = t3FontCache[j - 1];
+ }
+ t3FontCache[0] = t3Font;
+ break;
+ }
+ }
+ if (i >= nT3Fonts) {
+
+ // create new entry in the font cache
+ if (nT3Fonts == splashOutT3FontCacheSize) {
+ t3gs = t3GlyphStack;
+ while (t3gs != NULL) {
+ if (t3gs->cache == t3FontCache[nT3Fonts - 1]) {
+ error(errSyntaxWarning, -1, "t3FontCache reaches limit but font still on stack in SplashOutputDev::beginType3Char");
+ return gTrue;
+ }
+ t3gs = t3gs->next;
+ }
+ delete t3FontCache[nT3Fonts - 1];
+ --nT3Fonts;
+ }
+ for (j = nT3Fonts; j > 0; --j) {
+ t3FontCache[j] = t3FontCache[j - 1];
+ }
+ ++nT3Fonts;
+ bbox = gfxFont->getFontBBox();
+ if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
+ // unspecified bounding box -- just take a guess
+ xMin = xt - 5;
+ xMax = xMin + 30;
+ yMax = yt + 15;
+ yMin = yMax - 45;
+ validBBox = gFalse;
+ } else {
+ state->transform(bbox[0], bbox[1], &x1, &y1);
+ xMin = xMax = x1;
+ yMin = yMax = y1;
+ state->transform(bbox[0], bbox[3], &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ state->transform(bbox[2], bbox[1], &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ state->transform(bbox[2], bbox[3], &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ validBBox = gTrue;
+ }
+ t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
+ (int)floor(xMin - xt) - 2,
+ (int)floor(yMin - yt) - 2,
+ (int)ceil(xMax) - (int)floor(xMin) + 4,
+ (int)ceil(yMax) - (int)floor(yMin) + 4,
+ validBBox,
+ colorMode != splashModeMono1);
+ }
+ }
+ t3Font = t3FontCache[0];
+
+ // is the glyph in the cache?
+ i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
+ for (j = 0; j < t3Font->cacheAssoc; ++j) {
+ if (t3Font->cacheTags != NULL) {
+ if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
+ t3Font->cacheTags[i+j].code == code) {
+ drawType3Glyph(state, t3Font, &t3Font->cacheTags[i+j],
+ t3Font->cacheData + (i+j) * t3Font->glyphSize);
+ return gTrue;
+ }
+ }
+ }
+
+ // push a new Type 3 glyph record
+ t3gs = new T3GlyphStack();
+ t3gs->next = t3GlyphStack;
+ t3GlyphStack = t3gs;
+ t3GlyphStack->code = code;
+ t3GlyphStack->cache = t3Font;
+ t3GlyphStack->cacheTag = NULL;
+ t3GlyphStack->cacheData = NULL;
+
+ haveT3Dx = gFalse;
+
+ return gFalse;
+}
+
+void SplashOutputDev::endType3Char(GfxState *state) {
+ T3GlyphStack *t3gs;
+ double *ctm;
+
+ if (t3GlyphStack->cacheTag) {
+ --nestCount;
+ memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(),
+ t3GlyphStack->cache->glyphSize);
+ delete bitmap;
+ delete splash;
+ bitmap = t3GlyphStack->origBitmap;
+ splash = t3GlyphStack->origSplash;
+ ctm = state->getCTM();
+ state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
+ t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+ drawType3Glyph(state, t3GlyphStack->cache,
+ t3GlyphStack->cacheTag, t3GlyphStack->cacheData);
+ }
+ t3gs = t3GlyphStack;
+ t3GlyphStack = t3gs->next;
+ delete t3gs;
+}
+
+void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) {
+ haveT3Dx = gTrue;
+}
+
+void SplashOutputDev::type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury) {
+ double *ctm;
+ T3FontCache *t3Font;
+ SplashColor color;
+ double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
+ int i, j;
+
+ // ignore multiple d0/d1 operators
+ if (haveT3Dx) {
+ return;
+ }
+ haveT3Dx = gTrue;
+
+ if (unlikely(t3GlyphStack == NULL)) {
+ error(errSyntaxWarning, -1, "t3GlyphStack was null in SplashOutputDev::type3D1");
+ return;
+ }
+
+ if (unlikely(t3GlyphStack->origBitmap != NULL)) {
+ error(errSyntaxWarning, -1, "t3GlyphStack origBitmap was not null in SplashOutputDev::type3D1");
+ return;
+ }
+
+ if (unlikely(t3GlyphStack->origSplash != NULL)) {
+ error(errSyntaxWarning, -1, "t3GlyphStack origSplash was not null in SplashOutputDev::type3D1");
+ return;
+ }
+
+ t3Font = t3GlyphStack->cache;
+
+ // check for a valid bbox
+ state->transform(0, 0, &xt, &yt);
+ state->transform(llx, lly, &x1, &y1);
+ xMin = xMax = x1;
+ yMin = yMax = y1;
+ state->transform(llx, ury, &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ state->transform(urx, lly, &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ state->transform(urx, ury, &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ if (xMin - xt < t3Font->glyphX ||
+ yMin - yt < t3Font->glyphY ||
+ xMax - xt > t3Font->glyphX + t3Font->glyphW ||
+ yMax - yt > t3Font->glyphY + t3Font->glyphH) {
+ if (t3Font->validBBox) {
+ error(errSyntaxWarning, -1, "Bad bounding box in Type 3 glyph");
+ }
+ return;
+ }
+
+ if (t3Font->cacheTags == NULL)
+ return;
+
+ // allocate a cache entry
+ i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
+ for (j = 0; j < t3Font->cacheAssoc; ++j) {
+ if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
+ t3Font->cacheTags[i+j].mru = 0x8000;
+ t3Font->cacheTags[i+j].code = t3GlyphStack->code;
+ t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
+ t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
+ } else {
+ ++t3Font->cacheTags[i+j].mru;
+ }
+ }
+
+ // save state
+ t3GlyphStack->origBitmap = bitmap;
+ t3GlyphStack->origSplash = splash;
+ ctm = state->getCTM();
+ t3GlyphStack->origCTM4 = ctm[4];
+ t3GlyphStack->origCTM5 = ctm[5];
+
+ // create the temporary bitmap
+ if (colorMode == splashModeMono1) {
+ bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
+ splashModeMono1, gFalse);
+ splash = new Splash(bitmap, gFalse,
+ t3GlyphStack->origSplash->getScreen());
+ color[0] = 0;
+ splash->clear(color);
+ color[0] = 0xff;
+ } else {
+ bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
+ splashModeMono8, gFalse);
+ splash = new Splash(bitmap, vectorAntialias,
+ t3GlyphStack->origSplash->getScreen());
+ color[0] = 0x00;
+ splash->clear(color);
+ color[0] = 0xff;
+ }
+ splash->setMinLineWidth(globalParams->getMinLineWidth());
+ splash->setThinLineMode(splashThinLineDefault);
+ splash->setFillPattern(new SplashSolidColor(color));
+ splash->setStrokePattern(new SplashSolidColor(color));
+ //~ this should copy other state from t3GlyphStack->origSplash?
+ state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
+ -t3Font->glyphX, -t3Font->glyphY);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+ ++nestCount;
+}
+
+void SplashOutputDev::drawType3Glyph(GfxState *state, T3FontCache *t3Font,
+ T3FontCacheTag * /*tag*/, Guchar *data) {
+ SplashGlyphBitmap glyph;
+
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
+ glyph.x = -t3Font->glyphX;
+ glyph.y = -t3Font->glyphY;
+ glyph.w = t3Font->glyphW;
+ glyph.h = t3Font->glyphH;
+ glyph.aa = colorMode != splashModeMono1;
+ glyph.data = data;
+ glyph.freeData = gFalse;
+ splash->fillGlyph(0, 0, &glyph);
+}
+
+void SplashOutputDev::beginTextObject(GfxState *state) {
+}
+
+void SplashOutputDev::endTextObject(GfxState *state) {
+ if (textClipPath) {
+ splash->clipToPath(textClipPath, gFalse);
+ delete textClipPath;
+ textClipPath = NULL;
+ }
+}
+
+struct SplashOutImageMaskData {
+ ImageStream *imgStr;
+ GBool invert;
+ int width, height, y;
+};
+
+GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) {
+ SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data;
+ Guchar *p;
+ SplashColorPtr q;
+ int x;
+
+ if (imgMaskData->y == imgMaskData->height) {
+ return gFalse;
+ }
+ if (!(p = imgMaskData->imgStr->getLine())) {
+ return gFalse;
+ }
+ for (x = 0, q = line; x < imgMaskData->width; ++x) {
+ *q++ = *p++ ^ imgMaskData->invert;
+ }
+ ++imgMaskData->y;
+ return gTrue;
+}
+
+void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg) {
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutImageMaskData imgMaskData;
+
+ if (state->getFillColorSpace()->isNonMarking()) {
+ return;
+ }
+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), state->getFillColor());
+
+ ctm = state->getCTM();
+ for (int i = 0; i < 6; ++i) {
+ if (!isfinite(ctm[i])) return;
+ }
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+
+ imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
+ imgMaskData.imgStr->reset();
+ imgMaskData.invert = invert ? 0 : 1;
+ imgMaskData.width = width;
+ imgMaskData.height = height;
+ imgMaskData.y = 0;
+
+ splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, t3GlyphStack != NULL);
+ if (inlineImg) {
+ while (imgMaskData.y < height) {
+ imgMaskData.imgStr->getLine();
+ ++imgMaskData.y;
+ }
+ }
+
+ delete imgMaskData.imgStr;
+ str->close();
+}
+
+void SplashOutputDev::setSoftMaskFromImageMask(GfxState *state,
+ Object *ref, Stream *str,
+ int width, int height,
+ GBool invert,
+ GBool inlineImg, double *baseMatrix) {
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutImageMaskData imgMaskData;
+ Splash *maskSplash;
+ SplashColor maskColor;
+ double bbox[4] = {0, 0, 1, 1}; // default;
+
+ if (state->getFillColorSpace()->isNonMarking()) {
+ return;
+ }
+
+ ctm = state->getCTM();
+ for (int i = 0; i < 6; ++i) {
+ if (!isfinite(ctm[i])) return;
+ }
+
+ beginTransparencyGroup(state, bbox, NULL, gFalse, gFalse, gFalse);
+ baseMatrix[4] -= transpGroupStack->tx;
+ baseMatrix[5] -= transpGroupStack->ty;
+
+ ctm = state->getCTM();
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+ imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
+ imgMaskData.imgStr->reset();
+ imgMaskData.invert = invert ? 0 : 1;
+ imgMaskData.width = width;
+ imgMaskData.height = height;
+ imgMaskData.y = 0;
+
+ transpGroupStack->softmask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), 1, splashModeMono8, gFalse);
+ maskSplash = new Splash(transpGroupStack->softmask, vectorAntialias);
+ maskColor[0] = 0;
+ maskSplash->clear(maskColor);
+ maskColor[0] = 0xff;
+ maskSplash->setFillPattern(new SplashSolidColor(maskColor));
+ maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, t3GlyphStack != NULL);
+ delete maskSplash;
+ delete imgMaskData.imgStr;
+ str->close();
+}
+
+void SplashOutputDev::unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) {
+ double bbox[4] = {0,0,1,1}; // dummy
+
+ /* transfer mask to alpha channel! */
+ // memcpy(maskBitmap->getAlphaPtr(), maskBitmap->getDataPtr(), bitmap->getRowSize() * bitmap->getHeight());
+ // memset(maskBitmap->getDataPtr(), 0, bitmap->getRowSize() * bitmap->getHeight());
+ if (transpGroupStack->softmask != NULL) {
+ Guchar *dest = bitmap->getAlphaPtr();
+ Guchar *src = transpGroupStack->softmask->getDataPtr();
+ for (int c= 0; c < transpGroupStack->softmask->getRowSize() * transpGroupStack->softmask->getHeight(); c++) {
+ dest[c] = src[c];
+ }
+ delete transpGroupStack->softmask;
+ transpGroupStack->softmask = NULL;
+ }
+ endTransparencyGroup(state);
+ baseMatrix[4] += transpGroupStack->tx;
+ baseMatrix[5] += transpGroupStack->ty;
+ paintTransparencyGroup(state, bbox);
+}
+
+struct SplashOutImageData {
+ ImageStream *imgStr;
+ GfxImageColorMap *colorMap;
+ SplashColorPtr lookup;
+ int *maskColors;
+ SplashColorMode colorMode;
+ int width, height, y;
+};
+
+#ifdef USE_CMS
+GBool SplashOutputDev::useIccImageSrc(void *data) {
+ SplashOutImageData *imgData = (SplashOutImageData *)data;
+
+ if (!imgData->lookup && imgData->colorMap->getColorSpace()->getMode() == csICCBased) {
+ GfxICCBasedColorSpace *colorSpace = (GfxICCBasedColorSpace *) imgData->colorMap->getColorSpace();
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ if (colorSpace->getAlt() != NULL && colorSpace->getAlt()->getMode() == csDeviceGray)
+ return gTrue;
+ break;
+ case splashModeXBGR8:
+ case splashModeRGB8:
+ case splashModeBGR8:
+ if (colorSpace->getAlt() != NULL && colorSpace->getAlt()->getMode() == csDeviceRGB)
+ return gTrue;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ if (colorSpace->getAlt() != NULL && colorSpace->getAlt()->getMode() == csDeviceCMYK)
+ return gTrue;
+ break;
+#endif
+ }
+ }
+
+ return gFalse;
+}
+#endif
+
+GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine,
+ Guchar * /*alphaLine*/) {
+ SplashOutImageData *imgData = (SplashOutImageData *)data;
+ Guchar *p;
+ SplashColorPtr q, col;
+ GfxRGB rgb;
+ GfxGray gray;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+ int nComps, x;
+
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
+ if (!(p = imgData->imgStr->getLine())) {
+ int destComps = 1;
+ if (imgData->colorMode == splashModeRGB8 || imgData->colorMode == splashModeBGR8)
+ destComps = 3;
+ else if (imgData->colorMode == splashModeXBGR8)
+ destComps = 4;
+#if SPLASH_CMYK
+ else if (imgData->colorMode == splashModeCMYK8)
+ destComps = 4;
+ else if (imgData->colorMode == splashModeDeviceN8)
+ destComps = SPOT_NCOMPS + 4;
+#endif
+ memset(colorLine, 0, imgData->width * destComps);
+ return gFalse;
+ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+ if (imgData->lookup) {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ *q++ = imgData->lookup[*p];
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ col = &imgData->lookup[3 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ }
+ break;
+ case splashModeXBGR8:
+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+ }
+ break;
+ case splashModeDeviceN8:
+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = col[cp];
+ }
+ break;
+#endif
+ }
+ } else {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ if (imgData->colorMap->useRGBLine()) {
+ imgData->colorMap->getRGBLine(p, (Guchar *) colorLine, imgData->width);
+ } else {
+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getRGB(p, &rgb);
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+ }
+ }
+ break;
+ case splashModeXBGR8:
+ if (imgData->colorMap->useRGBLine()) {
+ imgData->colorMap->getRGBXLine(p, (Guchar *) colorLine, imgData->width);
+ } else {
+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getRGB(p, &rgb);
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+ *q++ = 255;
+ }
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ if (imgData->colorMap->useCMYKLine()) {
+ imgData->colorMap->getCMYKLine(p, (Guchar *) colorLine, imgData->width);
+ } else {
+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getCMYK(p, &cmyk);
+ *q++ = colToByte(cmyk.c);
+ *q++ = colToByte(cmyk.m);
+ *q++ = colToByte(cmyk.y);
+ *q++ = colToByte(cmyk.k);
+ }
+ }
+ break;
+ case splashModeDeviceN8:
+ if (imgData->colorMap->useDeviceNLine()) {
+ imgData->colorMap->getDeviceNLine(p, (Guchar *) colorLine, imgData->width);
+ } else {
+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getDeviceN(p, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = colToByte(deviceN.c[cp]);
+ }
+ }
+ break;
+#endif
+ }
+ }
+
+ ++imgData->y;
+ return gTrue;
+}
+
+#ifdef USE_CMS
+GBool SplashOutputDev::iccImageSrc(void *data, SplashColorPtr colorLine,
+ Guchar * /*alphaLine*/) {
+ SplashOutImageData *imgData = (SplashOutImageData *)data;
+ Guchar *p;
+ int nComps;
+
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
+ if (!(p = imgData->imgStr->getLine())) {
+ int destComps = 1;
+ if (imgData->colorMode == splashModeRGB8 || imgData->colorMode == splashModeBGR8)
+ destComps = 3;
+ else if (imgData->colorMode == splashModeXBGR8)
+ destComps = 4;
+#if SPLASH_CMYK
+ else if (imgData->colorMode == splashModeCMYK8)
+ destComps = 4;
+ else if (imgData->colorMode == splashModeDeviceN8)
+ destComps = SPOT_NCOMPS + 4;
+#endif
+ memset(colorLine, 0, imgData->width * destComps);
+ return gFalse;
+ }
+
+ if (imgData->colorMode == splashModeXBGR8) {
+ SplashColorPtr q;
+ int x;
+ for (x = 0, q = colorLine; x < imgData->width; ++x) {
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = 255;
+ }
+ } else {
+ nComps = imgData->colorMap->getNumPixelComps();
+ memcpy(colorLine, p, imgData->width * nComps);
+ }
+
+ ++imgData->y;
+ return gTrue;
+}
+
+void SplashOutputDev::iccTransform(void *data, SplashBitmap *bitmap) {
+ SplashOutImageData *imgData = (SplashOutImageData *)data;
+ int nComps = imgData->colorMap->getNumPixelComps();
+
+ Guchar *colorLine = (Guchar *) gmalloc(nComps * bitmap->getWidth());
+ Guchar *rgbxLine = (imgData->colorMode == splashModeXBGR8) ? (Guchar *) gmalloc(3 * bitmap->getWidth()) : NULL;
+ for (int i = 0; i < bitmap->getHeight(); i++) {
+ Guchar *p = bitmap->getDataPtr() + i * bitmap->getRowSize();
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData->colorMap->getGrayLine(p, colorLine, bitmap->getWidth());
+ memcpy(p, colorLine, nComps * bitmap->getWidth());
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData->colorMap->getRGBLine(p, colorLine, bitmap->getWidth());
+ memcpy(p, colorLine, nComps * bitmap->getWidth());
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData->colorMap->getCMYKLine(p, colorLine, bitmap->getWidth());
+ memcpy(p, colorLine, nComps * bitmap->getWidth());
+ break;
+#endif
+ case splashModeXBGR8:
+ Guchar *q;
+ Guchar *b = p;
+ int x;
+ for (x = 0, q = rgbxLine; x < bitmap->getWidth(); ++x, ++b) {
+ *q++ = *b++;
+ *q++ = *b++;
+ *q++ = *b++;
+ }
+ imgData->colorMap->getRGBLine(rgbxLine, colorLine, bitmap->getWidth());
+ b = p;
+ for (x = 0, q = colorLine; x < bitmap->getWidth(); ++x, ++b) {
+ *b++ = *q++;
+ *b++ = *q++;
+ *b++ = *q++;
+ }
+ break;
+ }
+ }
+ gfree(colorLine);
+ if (rgbxLine != NULL)
+ gfree(rgbxLine);
+}
+#endif
+
+GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine) {
+ SplashOutImageData *imgData = (SplashOutImageData *)data;
+ Guchar *p, *aq;
+ SplashColorPtr q, col;
+ GfxRGB rgb;
+ GfxGray gray;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+ Guchar alpha;
+ int nComps, x, i;
+
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
+ if (!(p = imgData->imgStr->getLine())) {
+ return gFalse;
+ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+ for (x = 0, q = colorLine, aq = alphaLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+ alpha = 0;
+ for (i = 0; i < nComps; ++i) {
+ if (p[i] < imgData->maskColors[2*i] ||
+ p[i] > imgData->maskColors[2*i+1]) {
+ alpha = 0xff;
+ break;
+ }
+ }
+ if (imgData->lookup) {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ *q++ = imgData->lookup[*p];
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ col = &imgData->lookup[3 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ break;
+ case splashModeXBGR8:
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = 255;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+ break;
+ case splashModeDeviceN8:
+ col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = col[cp];
+ break;
+#endif
+ }
+ *aq++ = alpha;
+ } else {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+ break;
+ case splashModeXBGR8:
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData->colorMap->getRGB(p, &rgb);
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+ if (imgData->colorMode == splashModeXBGR8) *q++ = 255;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData->colorMap->getCMYK(p, &cmyk);
+ *q++ = colToByte(cmyk.c);
+ *q++ = colToByte(cmyk.m);
+ *q++ = colToByte(cmyk.y);
+ *q++ = colToByte(cmyk.k);
+ break;
+ case splashModeDeviceN8:
+ imgData->colorMap->getDeviceN(p, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = colToByte(deviceN.c[cp]);
+ break;
+#endif
+ }
+ *aq++ = alpha;
+ }
+ }
+
+ ++imgData->y;
+ return gTrue;
+}
+
+struct TilingSplashOutBitmap {
+ SplashBitmap *bitmap;
+ SplashPattern *pattern;
+ SplashColorMode colorMode;
+ int paintType;
+ int repeatX;
+ int repeatY;
+ int y;
+};
+
+GBool SplashOutputDev::tilingBitmapSrc(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine) {
+ TilingSplashOutBitmap *imgData = (TilingSplashOutBitmap *)data;
+
+ if (imgData->y == imgData->bitmap->getHeight()) {
+ imgData->repeatY--;
+ if (imgData->repeatY == 0)
+ return gFalse;
+ imgData->y = 0;
+ }
+
+ if (imgData->paintType == 1) {
+ const SplashColorMode cMode = imgData->bitmap->getMode();
+ SplashColorPtr q = colorLine;
+ // For splashModeBGR8 and splashModeXBGR8 we need to use getPixel
+ // for the others we can use raw access
+ if (cMode == splashModeBGR8 || cMode == splashModeXBGR8) {
+ for (int m = 0; m < imgData->repeatX; m++) {
+ for (int x = 0; x < imgData->bitmap->getWidth(); x++) {
+ imgData->bitmap->getPixel(x, imgData->y, q);
+ q += splashColorModeNComps[cMode];
+ }
+ }
+ } else {
+ const int n = imgData->bitmap->getRowSize();
+ SplashColorPtr p;
+ for (int m = 0; m < imgData->repeatX; m++) {
+ p = imgData->bitmap->getDataPtr() + imgData->y * imgData->bitmap->getRowSize();
+ for (int x = 0; x < n; ++x) {
+ *q++ = *p++;
+ }
+ }
+ }
+ if (alphaLine != NULL) {
+ SplashColorPtr aq = alphaLine;
+ SplashColorPtr p;
+ const int n = imgData->bitmap->getWidth() - 1;
+ for (int m = 0; m < imgData->repeatX; m++) {
+ p = imgData->bitmap->getAlphaPtr() + imgData->y * imgData->bitmap->getWidth();
+ for (int x = 0; x < n; ++x) {
+ *aq++ = *p++;
+ }
+ // This is a hack, because of how Splash antialias works if we overwrite the
+ // last alpha pixel of the tile most/all of the files look much better
+ *aq++ = (n == 0) ? *p : *(p - 1);
+ }
+ }
+ } else {
+ SplashColor col, pat;
+ SplashColorPtr dest = colorLine;
+ for (int m = 0; m < imgData->repeatX; m++) {
+ for (int x = 0; x < imgData->bitmap->getWidth(); x++) {
+ imgData->bitmap->getPixel(x, imgData->y, col);
+ imgData->pattern->getColor(x, imgData->y, pat);
+ for (int i = 0; i < splashColorModeNComps[imgData->colorMode]; ++i) {
+#if SPLASH_CMYK
+ if (imgData->colorMode == splashModeCMYK8 || imgData->colorMode == splashModeDeviceN8)
+ dest[i] = div255(pat[i] * (255 - col[0]));
+ else
+#endif
+ dest[i] = 255 - div255((255 - pat[i]) * (255 - col[0]));
+ }
+ dest += splashColorModeNComps[imgData->colorMode];
+ }
+ }
+ if (alphaLine != NULL) {
+ const int y = (imgData->y == imgData->bitmap->getHeight() - 1 && imgData->y > 50) ? imgData->y - 1 : imgData->y;
+ SplashColorPtr aq = alphaLine;
+ SplashColorPtr p;
+ const int n = imgData->bitmap->getWidth();
+ for (int m = 0; m < imgData->repeatX; m++) {
+ p = imgData->bitmap->getAlphaPtr() + y * imgData->bitmap->getWidth();
+ for (int x = 0; x < n; ++x) {
+ *aq++ = *p++;
+ }
+ }
+ }
+ }
+ ++imgData->y;
+ return gTrue;
+}
+
+void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ int *maskColors, GBool inlineImg) {
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutImageData imgData;
+ SplashColorMode srcMode;
+ SplashImageSource src;
+ SplashICCTransform tf;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GBool grayIndexed = gFalse;
+ GfxColor deviceN;
+#endif
+ Guchar pix;
+ int n, i;
+
+ ctm = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ if (!isfinite(ctm[i])) return;
+ }
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+
+ imgData.imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgData.imgStr->reset();
+ imgData.colorMap = colorMap;
+ imgData.maskColors = maskColors;
+ imgData.colorMode = colorMode;
+ imgData.width = width;
+ imgData.height = height;
+ imgData.y = 0;
+
+ // special case for one-channel (monochrome/gray/separation) images:
+ // build a lookup table here
+ imgData.lookup = NULL;
+ if (colorMap->getNumPixelComps() == 1) {
+ n = 1 << colorMap->getBits();
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData.lookup = (SplashColorPtr)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getGray(&pix, &gray);
+ imgData.lookup[i] = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 3);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[3*i] = colToByte(rgb.r);
+ imgData.lookup[3*i+1] = colToByte(rgb.g);
+ imgData.lookup[3*i+2] = colToByte(rgb.b);
+ }
+ break;
+ case splashModeXBGR8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[4*i] = colToByte(rgb.r);
+ imgData.lookup[4*i+1] = colToByte(rgb.g);
+ imgData.lookup[4*i+2] = colToByte(rgb.b);
+ imgData.lookup[4*i+3] = 255;
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ grayIndexed = colorMap->getColorSpace()->getMode() != csDeviceGray;
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+ if (cmyk.c != 0 || cmyk.m != 0 || cmyk.y != 0) {
+ grayIndexed = gFalse;
+ }
+ imgData.lookup[4*i] = colToByte(cmyk.c);
+ imgData.lookup[4*i+1] = colToByte(cmyk.m);
+ imgData.lookup[4*i+2] = colToByte(cmyk.y);
+ imgData.lookup[4*i+3] = colToByte(cmyk.k);
+ }
+ break;
+ case splashModeDeviceN8:
+ colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+ grayIndexed = colorMap->getColorSpace()->getMode() != csDeviceGray;
+ imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+ if (cmyk.c != 0 || cmyk.m != 0 || cmyk.y != 0) {
+ grayIndexed = gFalse;
+ }
+ colorMap->getDeviceN(&pix, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ imgData.lookup[(SPOT_NCOMPS+4)*i +cp] = colToByte(deviceN.c[cp]);
+ }
+ break;
+#endif
+ }
+ }
+
+#if SPLASH_CMYK
+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), NULL, grayIndexed);
+#else
+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), NULL);
+#endif
+
+ if (colorMode == splashModeMono1) {
+ srcMode = splashModeMono8;
+ } else {
+ srcMode = colorMode;
+ }
+#ifdef USE_CMS
+ src = maskColors ? &alphaImageSrc : useIccImageSrc(&imgData) ? &iccImageSrc : &imageSrc;
+ tf = maskColors == NULL && useIccImageSrc(&imgData) ? &iccTransform : NULL;
+#else
+ src = maskColors ? &alphaImageSrc : &imageSrc;
+ tf = NULL;
+#endif
+ splash->drawImage(src, tf, &imgData, srcMode, maskColors ? gTrue : gFalse,
+ width, height, mat, interpolate);
+ if (inlineImg) {
+ while (imgData.y < height) {
+ imgData.imgStr->getLine();
+ ++imgData.y;
+ }
+ }
+
+ gfree(imgData.lookup);
+ delete imgData.imgStr;
+ str->close();
+}
+
+struct SplashOutMaskedImageData {
+ ImageStream *imgStr;
+ GfxImageColorMap *colorMap;
+ SplashBitmap *mask;
+ SplashColorPtr lookup;
+ SplashColorMode colorMode;
+ int width, height, y;
+};
+
+GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine) {
+ SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data;
+ Guchar *p, *aq;
+ SplashColorPtr q, col;
+ GfxRGB rgb;
+ GfxGray gray;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+ Guchar alpha;
+ Guchar *maskPtr;
+ int maskBit;
+ int nComps, x;
+
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
+ if (!(p = imgData->imgStr->getLine())) {
+ return gFalse;
+ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+ maskPtr = imgData->mask->getDataPtr() +
+ imgData->y * imgData->mask->getRowSize();
+ maskBit = 0x80;
+ for (x = 0, q = colorLine, aq = alphaLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+ alpha = (*maskPtr & maskBit) ? 0xff : 0x00;
+ if (!(maskBit >>= 1)) {
+ ++maskPtr;
+ maskBit = 0x80;
+ }
+ if (imgData->lookup) {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ *q++ = imgData->lookup[*p];
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ col = &imgData->lookup[3 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ break;
+ case splashModeXBGR8:
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = 255;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+ break;
+ case splashModeDeviceN8:
+ col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = col[cp];
+ break;
+#endif
+ }
+ *aq++ = alpha;
+ } else {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+ break;
+ case splashModeXBGR8:
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData->colorMap->getRGB(p, &rgb);
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+ if (imgData->colorMode == splashModeXBGR8) *q++ = 255;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData->colorMap->getCMYK(p, &cmyk);
+ *q++ = colToByte(cmyk.c);
+ *q++ = colToByte(cmyk.m);
+ *q++ = colToByte(cmyk.y);
+ *q++ = colToByte(cmyk.k);
+ break;
+ case splashModeDeviceN8:
+ imgData->colorMap->getDeviceN(p, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = colToByte(deviceN.c[cp]);
+ break;
+#endif
+ }
+ *aq++ = alpha;
+ }
+ }
+
+ ++imgData->y;
+ return gTrue;
+}
+
+void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
+ Stream *str, int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr, int maskWidth,
+ int maskHeight, GBool maskInvert,
+ GBool maskInterpolate) {
+ GfxImageColorMap *maskColorMap;
+ Object maskDecode, decodeLow, decodeHigh;
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutMaskedImageData imgData;
+ SplashOutImageMaskData imgMaskData;
+ SplashColorMode srcMode;
+ SplashBitmap *maskBitmap;
+ Splash *maskSplash;
+ SplashColor maskColor;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+ Guchar pix;
+ int n, i;
+
+#if SPLASH_CMYK
+ colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), NULL);
+
+ // If the mask is higher resolution than the image, use
+ // drawSoftMaskedImage() instead.
+ if (maskWidth > width || maskHeight > height) {
+ decodeLow.initInt(maskInvert ? 0 : 1);
+ decodeHigh.initInt(maskInvert ? 1 : 0);
+ maskDecode.initArray((xref) ? xref : doc->getXRef());
+ maskDecode.arrayAdd(&decodeLow);
+ maskDecode.arrayAdd(&decodeHigh);
+ maskColorMap = new GfxImageColorMap(1, &maskDecode,
+ new GfxDeviceGrayColorSpace());
+ maskDecode.free();
+ drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate,
+ maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate);
+ delete maskColorMap;
+
+ } else {
+ //----- scale the mask image to the same size as the source image
+
+ mat[0] = (SplashCoord)width;
+ mat[1] = 0;
+ mat[2] = 0;
+ mat[3] = (SplashCoord)height;
+ mat[4] = 0;
+ mat[5] = 0;
+ imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
+ imgMaskData.imgStr->reset();
+ imgMaskData.invert = maskInvert ? 0 : 1;
+ imgMaskData.width = maskWidth;
+ imgMaskData.height = maskHeight;
+ imgMaskData.y = 0;
+ maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse);
+ maskSplash = new Splash(maskBitmap, gFalse);
+ maskColor[0] = 0;
+ maskSplash->clear(maskColor);
+ maskColor[0] = 0xff;
+ maskSplash->setFillPattern(new SplashSolidColor(maskColor));
+ maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData,
+ maskWidth, maskHeight, mat, gFalse);
+ delete imgMaskData.imgStr;
+ maskStr->close();
+ delete maskSplash;
+
+ //----- draw the source image
+
+ ctm = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ if (!isfinite(ctm[i])) {
+ delete maskBitmap;
+ return;
+ }
+ }
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+
+ imgData.imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgData.imgStr->reset();
+ imgData.colorMap = colorMap;
+ imgData.mask = maskBitmap;
+ imgData.colorMode = colorMode;
+ imgData.width = width;
+ imgData.height = height;
+ imgData.y = 0;
+
+ // special case for one-channel (monochrome/gray/separation) images:
+ // build a lookup table here
+ imgData.lookup = NULL;
+ if (colorMap->getNumPixelComps() == 1) {
+ n = 1 << colorMap->getBits();
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData.lookup = (SplashColorPtr)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getGray(&pix, &gray);
+ imgData.lookup[i] = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 3);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[3*i] = colToByte(rgb.r);
+ imgData.lookup[3*i+1] = colToByte(rgb.g);
+ imgData.lookup[3*i+2] = colToByte(rgb.b);
+ }
+ break;
+ case splashModeXBGR8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[4*i] = colToByte(rgb.r);
+ imgData.lookup[4*i+1] = colToByte(rgb.g);
+ imgData.lookup[4*i+2] = colToByte(rgb.b);
+ imgData.lookup[4*i+3] = 255;
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+ imgData.lookup[4*i] = colToByte(cmyk.c);
+ imgData.lookup[4*i+1] = colToByte(cmyk.m);
+ imgData.lookup[4*i+2] = colToByte(cmyk.y);
+ imgData.lookup[4*i+3] = colToByte(cmyk.k);
+ }
+ break;
+ case splashModeDeviceN8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getDeviceN(&pix, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ imgData.lookup[(SPOT_NCOMPS+4)*i + cp] = colToByte(deviceN.c[cp]);
+ }
+ break;
+#endif
+ }
+ }
+
+ if (colorMode == splashModeMono1) {
+ srcMode = splashModeMono8;
+ } else {
+ srcMode = colorMode;
+ }
+ splash->drawImage(&maskedImageSrc, NULL, &imgData, srcMode, gTrue,
+ width, height, mat, interpolate);
+ delete maskBitmap;
+ gfree(imgData.lookup);
+ delete imgData.imgStr;
+ str->close();
+ }
+}
+
+void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
+ Stream *str, int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate) {
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutImageData imgData;
+ SplashOutImageData imgMaskData;
+ SplashColorMode srcMode;
+ SplashBitmap *maskBitmap;
+ Splash *maskSplash;
+ SplashColor maskColor;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+ Guchar pix;
+ int n, i;
+
+#if SPLASH_CMYK
+ colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), NULL);
+
+ ctm = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ if (!isfinite(ctm[i])) return;
+ }
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+
+ //----- set up the soft mask
+
+ imgMaskData.imgStr = new ImageStream(maskStr, maskWidth,
+ maskColorMap->getNumPixelComps(),
+ maskColorMap->getBits());
+ imgMaskData.imgStr->reset();
+ imgMaskData.colorMap = maskColorMap;
+ imgMaskData.maskColors = NULL;
+ imgMaskData.colorMode = splashModeMono8;
+ imgMaskData.width = maskWidth;
+ imgMaskData.height = maskHeight;
+ imgMaskData.y = 0;
+ n = 1 << maskColorMap->getBits();
+ imgMaskData.lookup = (SplashColorPtr)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ maskColorMap->getGray(&pix, &gray);
+ imgMaskData.lookup[i] = colToByte(gray);
+ }
+ maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
+ 1, splashModeMono8, gFalse);
+ maskSplash = new Splash(maskBitmap, vectorAntialias);
+ maskColor[0] = 0;
+ maskSplash->clear(maskColor);
+ maskSplash->drawImage(&imageSrc, NULL, &imgMaskData, splashModeMono8, gFalse,
+ maskWidth, maskHeight, mat, maskInterpolate);
+ delete imgMaskData.imgStr;
+ maskStr->close();
+ gfree(imgMaskData.lookup);
+ delete maskSplash;
+ splash->setSoftMask(maskBitmap);
+
+ //----- draw the source image
+
+ imgData.imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgData.imgStr->reset();
+ imgData.colorMap = colorMap;
+ imgData.maskColors = NULL;
+ imgData.colorMode = colorMode;
+ imgData.width = width;
+ imgData.height = height;
+ imgData.y = 0;
+
+ // special case for one-channel (monochrome/gray/separation) images:
+ // build a lookup table here
+ imgData.lookup = NULL;
+ if (colorMap->getNumPixelComps() == 1) {
+ n = 1 << colorMap->getBits();
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData.lookup = (SplashColorPtr)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getGray(&pix, &gray);
+ imgData.lookup[i] = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 3);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[3*i] = colToByte(rgb.r);
+ imgData.lookup[3*i+1] = colToByte(rgb.g);
+ imgData.lookup[3*i+2] = colToByte(rgb.b);
+ }
+ break;
+ case splashModeXBGR8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[4*i] = colToByte(rgb.r);
+ imgData.lookup[4*i+1] = colToByte(rgb.g);
+ imgData.lookup[4*i+2] = colToByte(rgb.b);
+ imgData.lookup[4*i+3] = 255;
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+ imgData.lookup[4*i] = colToByte(cmyk.c);
+ imgData.lookup[4*i+1] = colToByte(cmyk.m);
+ imgData.lookup[4*i+2] = colToByte(cmyk.y);
+ imgData.lookup[4*i+3] = colToByte(cmyk.k);
+ }
+ break;
+ case splashModeDeviceN8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getDeviceN(&pix, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ imgData.lookup[(SPOT_NCOMPS+4)*i + cp] = colToByte(deviceN.c[cp]);
+ }
+ break;
+#endif
+ }
+ }
+
+ if (colorMode == splashModeMono1) {
+ srcMode = splashModeMono8;
+ } else {
+ srcMode = colorMode;
+ }
+ splash->drawImage(&imageSrc, NULL, &imgData, srcMode, gFalse, width, height, mat, interpolate);
+ splash->setSoftMask(NULL);
+ gfree(imgData.lookup);
+ delete imgData.imgStr;
+ str->close();
+}
+
+GBool SplashOutputDev::checkTransparencyGroup(GfxState *state, GBool knockout) {
+ if (state->getFillOpacity() != 1 ||
+ state->getStrokeOpacity() != 1 ||
+ state->getAlphaIsShape() ||
+ state->getBlendMode() != gfxBlendNormal ||
+ splash->getSoftMask() != NULL ||
+ knockout)
+ return gTrue;
+ return transpGroupStack != NULL && transpGroupStack->shape != NULL;
+}
+
+void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ GBool forSoftMask) {
+ SplashTransparencyGroup *transpGroup;
+ SplashColor color;
+ double xMin, yMin, xMax, yMax, x, y;
+ int tx, ty, w, h, i;
+
+ // transform the bbox
+ state->transform(bbox[0], bbox[1], &x, &y);
+ xMin = xMax = x;
+ yMin = yMax = y;
+ state->transform(bbox[0], bbox[3], &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ state->transform(bbox[2], bbox[1], &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ state->transform(bbox[2], bbox[3], &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ tx = (int)floor(xMin);
+ if (tx < 0) {
+ tx = 0;
+ } else if (tx >= bitmap->getWidth()) {
+ tx = bitmap->getWidth() - 1;
+ }
+ ty = (int)floor(yMin);
+ if (ty < 0) {
+ ty = 0;
+ } else if (ty >= bitmap->getHeight()) {
+ ty = bitmap->getHeight() - 1;
+ }
+ w = (int)ceil(xMax) - tx + 1;
+ if (tx + w > bitmap->getWidth()) {
+ w = bitmap->getWidth() - tx;
+ }
+ if (w < 1) {
+ w = 1;
+ }
+ h = (int)ceil(yMax) - ty + 1;
+ if (ty + h > bitmap->getHeight()) {
+ h = bitmap->getHeight() - ty;
+ }
+ if (h < 1) {
+ h = 1;
+ }
+
+ // push a new stack entry
+ transpGroup = new SplashTransparencyGroup();
+ transpGroup->softmask = NULL;
+ transpGroup->tx = tx;
+ transpGroup->ty = ty;
+ transpGroup->blendingColorSpace = blendingColorSpace;
+ transpGroup->isolated = isolated;
+ transpGroup->shape = (knockout && !isolated) ? SplashBitmap::copy(bitmap) : NULL;
+ transpGroup->knockout = (knockout && isolated);
+ transpGroup->knockoutOpacity = 1.0;
+ transpGroup->next = transpGroupStack;
+ transpGroupStack = transpGroup;
+
+ // save state
+ transpGroup->origBitmap = bitmap;
+ transpGroup->origSplash = splash;
+ transpGroup->fontAA = fontEngine->getAA();
+
+ //~ this handles the blendingColorSpace arg for soft masks, but
+ //~ not yet for transparency groups
+
+ // switch to the blending color space
+ if (forSoftMask && isolated && blendingColorSpace) {
+ if (blendingColorSpace->getMode() == csDeviceGray ||
+ blendingColorSpace->getMode() == csCalGray ||
+ (blendingColorSpace->getMode() == csICCBased &&
+ blendingColorSpace->getNComps() == 1)) {
+ colorMode = splashModeMono8;
+ } else if (blendingColorSpace->getMode() == csDeviceRGB ||
+ blendingColorSpace->getMode() == csCalRGB ||
+ (blendingColorSpace->getMode() == csICCBased &&
+ blendingColorSpace->getNComps() == 3)) {
+ //~ does this need to use BGR8?
+ colorMode = splashModeRGB8;
+#if SPLASH_CMYK
+ } else if (blendingColorSpace->getMode() == csDeviceCMYK ||
+ (blendingColorSpace->getMode() == csICCBased &&
+ blendingColorSpace->getNComps() == 4)) {
+ colorMode = splashModeCMYK8;
+#endif
+ }
+ }
+
+ // create the temporary bitmap
+ bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
+ bitmapTopDown, bitmap->getSeparationList());
+ splash = new Splash(bitmap, vectorAntialias,
+ transpGroup->origSplash->getScreen());
+ if (transpGroup->next != NULL && transpGroup->next->knockout) {
+ fontEngine->setAA(gFalse);
+ }
+ splash->setThinLineMode(transpGroup->origSplash->getThinLineMode());
+ splash->setMinLineWidth(globalParams->getMinLineWidth());
+ //~ Acrobat apparently copies at least the fill and stroke colors, and
+ //~ maybe other state(?) -- but not the clipping path (and not sure
+ //~ what else)
+ //~ [this is likely the same situation as in type3D1()]
+ splash->setFillPattern(transpGroup->origSplash->getFillPattern()->copy());
+ splash->setStrokePattern(
+ transpGroup->origSplash->getStrokePattern()->copy());
+ if (isolated) {
+ for (i = 0; i < splashMaxColorComps; ++i) {
+ color[i] = 0;
+ }
+ if (colorMode == splashModeXBGR8) color[3] = 255;
+ splash->clear(color, 0);
+ } else {
+ SplashBitmap *shape = (knockout) ? transpGroup->shape :
+ (transpGroup->next != NULL && transpGroup->next->shape != NULL) ? transpGroup->next->shape : transpGroup->origBitmap;
+ int shapeTx = (knockout) ? tx :
+ (transpGroup->next != NULL && transpGroup->next->shape != NULL) ? transpGroup->next->tx + tx : tx;
+ int shapeTy = (knockout) ? ty :
+ (transpGroup->next != NULL && transpGroup->next->shape != NULL) ? transpGroup->next->ty + ty : ty;
+ splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h);
+ splash->setInNonIsolatedGroup(shape, shapeTx, shapeTy);
+ }
+ transpGroup->tBitmap = bitmap;
+ state->shiftCTMAndClip(-tx, -ty);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+ ++nestCount;
+}
+
+void SplashOutputDev::endTransparencyGroup(GfxState *state) {
+ // restore state
+ --nestCount;
+ delete splash;
+ bitmap = transpGroupStack->origBitmap;
+ colorMode = bitmap->getMode();
+ splash = transpGroupStack->origSplash;
+ state->shiftCTMAndClip(transpGroupStack->tx, transpGroupStack->ty);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+}
+
+void SplashOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) {
+ SplashBitmap *tBitmap;
+ SplashTransparencyGroup *transpGroup;
+ GBool isolated;
+ int tx, ty;
+
+ tx = transpGroupStack->tx;
+ ty = transpGroupStack->ty;
+ tBitmap = transpGroupStack->tBitmap;
+ isolated = transpGroupStack->isolated;
+
+ // paint the transparency group onto the parent bitmap
+ // - the clip path was set in the parent's state)
+ if (tx < bitmap->getWidth() && ty < bitmap->getHeight()) {
+ SplashCoord knockoutOpacity = (transpGroupStack->next != NULL) ? transpGroupStack->next->knockoutOpacity
+ : transpGroupStack->knockoutOpacity;
+ splash->setOverprintMask(0xffffffff, gFalse);
+ splash->composite(tBitmap, 0, 0, tx, ty,
+ tBitmap->getWidth(), tBitmap->getHeight(),
+ gFalse, !isolated, transpGroupStack->next != NULL && transpGroupStack->next->knockout, knockoutOpacity);
+ fontEngine->setAA(transpGroupStack->fontAA);
+ if (transpGroupStack->next != NULL && transpGroupStack->next->shape != NULL) {
+ transpGroupStack->next->knockout = gTrue;
+ }
+ }
+
+ // pop the stack
+ transpGroup = transpGroupStack;
+ transpGroupStack = transpGroup->next;
+ if (transpGroupStack != NULL && transpGroup->knockoutOpacity < transpGroupStack->knockoutOpacity) {
+ transpGroupStack->knockoutOpacity = transpGroup->knockoutOpacity;
+ }
+ delete transpGroup->shape;
+ delete transpGroup;
+
+ delete tBitmap;
+}
+
+void SplashOutputDev::setSoftMask(GfxState *state, double *bbox,
+ GBool alpha, Function *transferFunc,
+ GfxColor *backdropColor) {
+ SplashBitmap *softMask, *tBitmap;
+ Splash *tSplash;
+ SplashTransparencyGroup *transpGroup;
+ SplashColor color;
+ SplashColorPtr p;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+ GfxColor deviceN;
+#endif
+ double lum, lum2;
+ int tx, ty, x, y;
+
+ tx = transpGroupStack->tx;
+ ty = transpGroupStack->ty;
+ tBitmap = transpGroupStack->tBitmap;
+
+ // composite with backdrop color
+ if (!alpha && tBitmap->getMode() != splashModeMono1) {
+ //~ need to correctly handle the case where no blending color
+ //~ space is given
+ if (transpGroupStack->blendingColorSpace) {
+ tSplash = new Splash(tBitmap, vectorAntialias,
+ transpGroupStack->origSplash->getScreen());
+ switch (tBitmap->getMode()) {
+ case splashModeMono1:
+ // transparency is not supported in mono1 mode
+ break;
+ case splashModeMono8:
+ transpGroupStack->blendingColorSpace->getGray(backdropColor, &gray);
+ color[0] = colToByte(gray);
+ tSplash->compositeBackground(color);
+ break;
+ case splashModeXBGR8:
+ color[3] = 255;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ transpGroupStack->blendingColorSpace->getRGB(backdropColor, &rgb);
+ color[0] = colToByte(rgb.r);
+ color[1] = colToByte(rgb.g);
+ color[2] = colToByte(rgb.b);
+ tSplash->compositeBackground(color);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ transpGroupStack->blendingColorSpace->getCMYK(backdropColor, &cmyk);
+ color[0] = colToByte(cmyk.c);
+ color[1] = colToByte(cmyk.m);
+ color[2] = colToByte(cmyk.y);
+ color[3] = colToByte(cmyk.k);
+ tSplash->compositeBackground(color);
+ break;
+ case splashModeDeviceN8:
+ transpGroupStack->blendingColorSpace->getDeviceN(backdropColor, &deviceN);
+ for (int cp=0; cp < SPOT_NCOMPS+4; cp++)
+ color[cp] = colToByte(deviceN.c[cp]);
+ tSplash->compositeBackground(color);
+ break;
+#endif
+ }
+ delete tSplash;
+ }
+ }
+
+ softMask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
+ 1, splashModeMono8, gFalse);
+ unsigned char fill = 0;
+ if (transpGroupStack->blendingColorSpace) {
+ transpGroupStack->blendingColorSpace->getGray(backdropColor, &gray);
+ fill = colToByte(gray);
+ }
+ memset(softMask->getDataPtr(), fill,
+ softMask->getRowSize() * softMask->getHeight());
+ p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
+ int xMax = tBitmap->getWidth();
+ int yMax = tBitmap->getHeight();
+ if (xMax > bitmap->getWidth() - tx) xMax = bitmap->getWidth() - tx;
+ if (yMax > bitmap->getHeight() - ty) yMax = bitmap->getHeight() - ty;
+ for (y = 0; y < yMax; ++y) {
+ for (x = 0; x < xMax; ++x) {
+ if (alpha) {
+ if (transferFunc) {
+ lum = tBitmap->getAlpha(x, y) / 255.0;
+ transferFunc->transform(&lum, &lum2);
+ p[x] = (int)(lum2 * 255.0 + 0.5);
+ } else
+ p[x] = tBitmap->getAlpha(x, y);
+ } else {
+ tBitmap->getPixel(x, y, color);
+ // convert to luminosity
+ switch (tBitmap->getMode()) {
+ case splashModeMono1:
+ case splashModeMono8:
+ lum = color[0] / 255.0;
+ break;
+ case splashModeXBGR8:
+ case splashModeRGB8:
+ case splashModeBGR8:
+ lum = (0.3 / 255.0) * color[0] +
+ (0.59 / 255.0) * color[1] +
+ (0.11 / 255.0) * color[2];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ lum = (1 - color[3] / 255.0)
+ - (0.3 / 255.0) * color[0]
+ - (0.59 / 255.0) * color[1]
+ - (0.11 / 255.0) * color[2];
+ if (lum < 0) {
+ lum = 0;
+ }
+ break;
+#endif
+ }
+ if (transferFunc) {
+ transferFunc->transform(&lum, &lum2);
+ } else {
+ lum2 = lum;
+ }
+ p[x] = (int)(lum2 * 255.0 + 0.5);
+ }
+ }
+ p += softMask->getRowSize();
+ }
+ splash->setSoftMask(softMask);
+
+ // pop the stack
+ transpGroup = transpGroupStack;
+ transpGroupStack = transpGroup->next;
+ delete transpGroup;
+
+ delete tBitmap;
+}
+
+void SplashOutputDev::clearSoftMask(GfxState *state) {
+ splash->setSoftMask(NULL);
+}
+
+void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) {
+ splashColorCopy(paperColor, paperColorA);
+}
+
+int SplashOutputDev::getBitmapWidth() {
+ return bitmap->getWidth();
+}
+
+int SplashOutputDev::getBitmapHeight() {
+ return bitmap->getHeight();
+}
+
+SplashBitmap *SplashOutputDev::takeBitmap() {
+ SplashBitmap *ret;
+
+ ret = bitmap;
+ bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ return ret;
+}
+
+void SplashOutputDev::getModRegion(int *xMin, int *yMin,
+ int *xMax, int *yMax) {
+ splash->getModRegion(xMin, yMin, xMax, yMax);
+}
+
+void SplashOutputDev::clearModRegion() {
+ splash->clearModRegion();
+}
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+GBool SplashOutputDev::getVectorAntialias() {
+ return splash->getVectorAntialias();
+}
+
+void SplashOutputDev::setVectorAntialias(GBool vaa) {
+ vaa = vaa && colorMode != splashModeMono1;
+ vectorAntialias = vaa;
+ splash->setVectorAntialias(vaa);
+}
+#endif
+
+void SplashOutputDev::setFreeTypeHinting(GBool enable, GBool enableSlightHintingA)
+{
+ enableFreeTypeHinting = enable;
+ enableSlightHinting = enableSlightHintingA;
+}
+
+GBool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *catalog, Object *str,
+ double *ptm, int paintType, int /*tilingType*/, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep)
+{
+ PDFRectangle box;
+ Gfx *gfx;
+ Splash *formerSplash = splash;
+ SplashBitmap *formerBitmap = bitmap;
+ double width, height;
+ int surface_width, surface_height, result_width, result_height, i;
+ int repeatX, repeatY;
+ SplashCoord matc[6];
+ Matrix m1;
+ double *ctm, savedCTM[6];
+ double kx, ky, sx, sy;
+ GBool retValue = gFalse;
+
+ width = bbox[2] - bbox[0];
+ height = bbox[3] - bbox[1];
+
+ if (xStep != width || yStep != height)
+ return gFalse;
+
+ // calculate offsets
+ ctm = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ savedCTM[i] = ctm[i];
+ }
+ state->concatCTM(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ state->concatCTM(1, 0, 0, 1, bbox[0], bbox[1]);
+ ctm = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ if (!isfinite(ctm[i])) {
+ state->setCTM(savedCTM[0], savedCTM[1], savedCTM[2], savedCTM[3], savedCTM[4], savedCTM[5]);
+ return gFalse;
+ }
+ }
+ matc[4] = x0 * xStep * ctm[0] + y0 * yStep * ctm[2] + ctm[4];
+ matc[5] = x0 * xStep * ctm[1] + y0 * yStep * ctm[3] + ctm[5];
+ if (splashAbs(ctm[1]) > splashAbs(ctm[0])) {
+ kx = -ctm[1];
+ ky = ctm[2] - (ctm[0] * ctm[3]) / ctm[1];
+ } else {
+ kx = ctm[0];
+ ky = ctm[3] - (ctm[1] * ctm[2]) / ctm[0];
+ }
+ result_width = (int) ceil(fabs(kx * width * (x1 - x0)));
+ result_height = (int) ceil(fabs(ky * height * (y1 - y0)));
+ kx = state->getHDPI() / 72.0;
+ ky = state->getVDPI() / 72.0;
+ m1.m[0] = (ptm[0] == 0) ? fabs(ptm[2]) * kx : fabs(ptm[0]) * kx;
+ m1.m[1] = 0;
+ m1.m[2] = 0;
+ m1.m[3] = (ptm[3] == 0) ? fabs(ptm[1]) * ky : fabs(ptm[3]) * ky;
+ m1.m[4] = 0;
+ m1.m[5] = 0;
+ m1.transform(width, height, &kx, &ky);
+ surface_width = (int) ceil (fabs(kx));
+ surface_height = (int) ceil (fabs(ky));
+
+ sx = (double) result_width / (surface_width * (x1 - x0));
+ sy = (double) result_height / (surface_height * (y1 - y0));
+ m1.m[0] *= sx;
+ m1.m[3] *= sy;
+ m1.transform(width, height, &kx, &ky);
+
+ if(fabs(kx) < 1 && fabs(ky) < 1) {
+ kx = std::min<double>(kx, ky);
+ ky = 2 / kx;
+ m1.m[0] *= ky;
+ m1.m[3] *= ky;
+ m1.transform(width, height, &kx, &ky);
+ surface_width = (int) ceil (fabs(kx));
+ surface_height = (int) ceil (fabs(ky));
+ repeatX = x1 - x0;
+ repeatY = y1 - y0;
+ } else {
+ if ((unsigned long) result_width * result_height > 0x800000L) {
+ state->setCTM(savedCTM[0], savedCTM[1], savedCTM[2], savedCTM[3], savedCTM[4], savedCTM[5]);
+ return gFalse;
+ }
+ while(fabs(kx) > 16384 || fabs(ky) > 16384) {
+ // limit pattern bitmap size
+ m1.m[0] /= 2;
+ m1.m[3] /= 2;
+ m1.transform(width, height, &kx, &ky);
+ }
+ surface_width = (int) ceil (fabs(kx));
+ surface_height = (int) ceil (fabs(ky));
+ // adjust repeat values to completely fill region
+ repeatX = result_width / surface_width;
+ repeatY = result_height / surface_height;
+ if (surface_width * repeatX < result_width)
+ repeatX++;
+ if (surface_height * repeatY < result_height)
+ repeatY++;
+ if (x1 - x0 > repeatX)
+ repeatX = x1 - x0;
+ if (y1 - y0 > repeatY)
+ repeatY = y1 - y0;
+ }
+ // restore CTM and calculate rotate and scale with rounded matric
+ state->setCTM(savedCTM[0], savedCTM[1], savedCTM[2], savedCTM[3], savedCTM[4], savedCTM[5]);
+ state->concatCTM(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ state->concatCTM(width * repeatX, 0, 0, height * repeatY, bbox[0], bbox[1]);
+ ctm = state->getCTM();
+ matc[0] = ctm[0];
+ matc[1] = ctm[1];
+ matc[2] = ctm[2];
+ matc[3] = ctm[3];
+
+ if (surface_width == 0 || surface_height == 0) {
+ state->setCTM(savedCTM[0], savedCTM[1], savedCTM[2], savedCTM[3], savedCTM[4], savedCTM[5]);
+ return gFalse;
+ }
+ m1.transform(bbox[0], bbox[1], &kx, &ky);
+ m1.m[4] = -kx;
+ m1.m[5] = -ky;
+
+ bitmap = new SplashBitmap(surface_width, surface_height, 1,
+ (paintType == 1) ? colorMode : splashModeMono8, gTrue);
+ splash = new Splash(bitmap, gTrue);
+ if (paintType == 2) {
+ SplashColor clearColor;
+#if SPLASH_CMYK
+ clearColor[0] = (colorMode == splashModeCMYK8 || colorMode == splashModeDeviceN8) ? 0x00 : 0xFF;
+#else
+ clearColor[0] = 0xFF;
+#endif
+ splash->clear(clearColor, 0);
+ } else {
+ splash->clear(paperColor, 0);
+ }
+ splash->setThinLineMode(formerSplash->getThinLineMode());
+ splash->setMinLineWidth(globalParams->getMinLineWidth());
+
+ box.x1 = bbox[0]; box.y1 = bbox[1];
+ box.x2 = bbox[2]; box.y2 = bbox[3];
+ gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gfxA->getXRef());
+ // set pattern transformation matrix
+ gfx->getState()->setCTM(m1.m[0], m1.m[1], m1.m[2], m1.m[3], m1.m[4], m1.m[5]);
+ updateCTM(gfx->getState(), m1.m[0], m1.m[1], m1.m[2], m1.m[3], m1.m[4], m1.m[5]);
+ gfx->display(str);
+ delete splash;
+ splash = formerSplash;
+ TilingSplashOutBitmap imgData;
+ imgData.bitmap = bitmap;
+ imgData.paintType = paintType;
+ imgData.pattern = splash->getFillPattern();
+ imgData.colorMode = colorMode;
+ imgData.y = 0;
+ imgData.repeatX = repeatX;
+ imgData.repeatY = repeatY;
+ SplashBitmap *tBitmap = bitmap;
+ bitmap = formerBitmap;
+ result_width = tBitmap->getWidth() * imgData.repeatX;
+ result_height = tBitmap->getHeight() * imgData.repeatY;
+
+ if (splashAbs(matc[1]) > splashAbs(matc[0])) {
+ kx = -matc[1];
+ ky = matc[2] - (matc[0] * matc[3]) / matc[1];
+ } else {
+ kx = matc[0];
+ ky = matc[3] - (matc[1] * matc[2]) / matc[0];
+ }
+ kx = result_width / (fabs(kx) + 1);
+ ky = result_height / (fabs(ky) + 1);
+ state->concatCTM(kx, 0, 0, ky, 0, 0);
+ ctm = state->getCTM();
+ matc[0] = ctm[0];
+ matc[1] = ctm[1];
+ matc[2] = ctm[2];
+ matc[3] = ctm[3];
+ GBool minorAxisZero = matc[1] == 0 && matc[2] == 0;
+ if (matc[0] > 0 && minorAxisZero && matc[3] > 0) {
+ // draw the tiles
+ for (int y = 0; y < imgData.repeatY; ++y) {
+ for (int x = 0; x < imgData.repeatX; ++x) {
+ x0 = splashFloor(matc[4]) + x * tBitmap->getWidth();
+ y0 = splashFloor(matc[5]) + y * tBitmap->getHeight();
+ splash->blitImage(tBitmap, gTrue, x0, y0);
+ }
+ }
+ retValue = gTrue;
+ } else {
+ retValue = splash->drawImage(&tilingBitmapSrc, NULL, &imgData, colorMode, gTrue, result_width, result_height, matc, gFalse, gTrue) == splashOk;
+ }
+ delete tBitmap;
+ delete gfx;
+ return retValue;
+}
+
+GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+{
+ GfxColorSpaceMode shadingMode = shading->getColorSpace()->getMode();
+ GBool bDirectColorTranslation = gFalse; // triggers an optimization.
+ switch (colorMode) {
+ case splashModeRGB8:
+ bDirectColorTranslation = (shadingMode == csDeviceRGB);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ bDirectColorTranslation = (shadingMode == csDeviceCMYK);
+ break;
+#endif
+ default:
+ break;
+ }
+ SplashGouraudColor *splashShading = new SplashGouraudPattern(bDirectColorTranslation, state, shading, colorMode);
+ // restore vector antialias because we support it here
+ if (shading->isParameterized()) {
+ GBool vaa = getVectorAntialias();
+ GBool retVal = gFalse;
+ setVectorAntialias(gTrue);
+ retVal = splash->gouraudTriangleShadedFill(splashShading);
+ setVectorAntialias(vaa);
+ return retVal;
+ }
+ delete splashShading;
+ return gFalse;
+}
+
+GBool SplashOutputDev::univariateShadedFill(GfxState *state, SplashUnivariatePattern *pattern, double tMin, double tMax) {
+ double xMin, yMin, xMax, yMax;
+ SplashPath *path;
+ GBool vaa = getVectorAntialias();
+ // restore vector antialias because we support it here
+ setVectorAntialias(gTrue);
+
+ GBool retVal = gFalse;
+ // get the clip region bbox
+ if (pattern->getShading()->getHasBBox()) {
+ pattern->getShading()->getBBox(&xMin, &yMin, &xMax, &yMax);
+ } else {
+ state->getClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ xMin = floor (xMin);
+ yMin = floor (yMin);
+ xMax = ceil (xMax);
+ yMax = ceil (yMax);
+
+ {
+ Matrix ctm, ictm;
+ double x[4], y[4];
+ int i;
+
+ state->getCTM(&ctm);
+ ctm.invertTo(&ictm);
+
+ ictm.transform(xMin, yMin, &x[0], &y[0]);
+ ictm.transform(xMax, yMin, &x[1], &y[1]);
+ ictm.transform(xMin, yMax, &x[2], &y[2]);
+ ictm.transform(xMax, yMax, &x[3], &y[3]);
+
+ xMin = xMax = x[0];
+ yMin = yMax = y[0];
+ for (i = 1; i < 4; i++) {
+ xMin = std::min<double>(xMin, x[i]);
+ yMin = std::min<double>(yMin, y[i]);
+ xMax = std::max<double>(xMax, x[i]);
+ yMax = std::max<double>(yMax, y[i]);
+ }
+ }
+ }
+
+ // fill the region
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ path = convertPath(state, state->getPath(), gTrue);
+
+#if SPLASH_CMYK
+ pattern->getShading()->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+ setOverprintMask(pattern->getShading()->getColorSpace(), state->getFillOverprint(),
+ state->getOverprintMode(), NULL);
+ retVal = (splash->shadedFill(path, pattern->getShading()->getHasBBox(), pattern) == splashOk);
+ state->clearPath();
+ setVectorAntialias(vaa);
+ delete path;
+
+ return retVal;
+}
+
+GBool SplashOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) {
+ SplashAxialPattern *pattern = new SplashAxialPattern(colorMode, state, shading);
+ GBool retVal = univariateShadedFill(state, pattern, tMin, tMax);
+
+ delete pattern;
+
+ return retVal;
+}
+
+GBool SplashOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double tMin, double tMax) {
+ SplashRadialPattern *pattern = new SplashRadialPattern(colorMode, state, shading);
+ GBool retVal = univariateShadedFill(state, pattern, tMin, tMax);
+
+ delete pattern;
+
+ return retVal;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/SplashOutputDev.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/SplashOutputDev.h
new file mode 100644
index 00000000000..d34426c0f3c
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/SplashOutputDev.h
@@ -0,0 +1,442 @@
+//========================================================================
+//
+// SplashOutputDev.h
+//
+// Copyright 2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2009-2015 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
+// Copyright (C) 2011 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2015 William Bader <williambader@hotmail.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHOUTPUTDEV_H
+#define SPLASHOUTPUTDEV_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "splash/SplashTypes.h"
+#include "splash/SplashPattern.h"
+#include "poppler-config.h"
+#include "OutputDev.h"
+#include "GfxState.h"
+#include "GlobalParams.h"
+
+class PDFDoc;
+class Gfx8BitFont;
+class SplashBitmap;
+class Splash;
+class SplashPath;
+class SplashFontEngine;
+class SplashFont;
+class T3FontCache;
+struct T3FontCacheTag;
+struct T3GlyphStack;
+struct SplashTransparencyGroup;
+
+//------------------------------------------------------------------------
+// Splash dynamic pattern
+//------------------------------------------------------------------------
+
+class SplashUnivariatePattern: public SplashPattern {
+public:
+
+ SplashUnivariatePattern(SplashColorMode colorMode, GfxState *state, GfxUnivariateShading *shading);
+
+ virtual ~SplashUnivariatePattern();
+
+ virtual GBool getColor(int x, int y, SplashColorPtr c);
+
+ virtual GBool testPosition(int x, int y);
+
+ virtual GBool isStatic() { return gFalse; }
+
+ virtual GBool getParameter(double xs, double ys, double *t) = 0;
+
+ virtual GfxUnivariateShading *getShading() { return shading; }
+
+ virtual GBool isCMYK() { return gfxMode == csDeviceCMYK; }
+
+protected:
+ Matrix ictm;
+ double t0, t1, dt;
+ GfxUnivariateShading *shading;
+ GfxState *state;
+ SplashColorMode colorMode;
+ GfxColorSpaceMode gfxMode;
+};
+
+class SplashAxialPattern: public SplashUnivariatePattern {
+public:
+
+ SplashAxialPattern(SplashColorMode colorMode, GfxState *state, GfxAxialShading *shading);
+
+ virtual SplashPattern *copy() { return new SplashAxialPattern(colorMode, state, (GfxAxialShading *) shading); }
+
+ virtual ~SplashAxialPattern();
+
+ virtual GBool getParameter(double xs, double ys, double *t);
+
+private:
+ double x0, y0, x1, y1;
+ double dx, dy, mul;
+};
+
+// see GfxState.h, GfxGouraudTriangleShading
+class SplashGouraudPattern: public SplashGouraudColor {
+public:
+
+ SplashGouraudPattern(GBool bDirectColorTranslation, GfxState *state, GfxGouraudTriangleShading *shading, SplashColorMode mode);
+
+ virtual SplashPattern *copy() { return new SplashGouraudPattern(bDirectColorTranslation, state, shading, mode); }
+
+ virtual ~SplashGouraudPattern();
+
+ virtual GBool getColor(int x, int y, SplashColorPtr c) { return gFalse; }
+
+ virtual GBool testPosition(int x, int y) { return gFalse; }
+
+ virtual GBool isStatic() { return gFalse; }
+
+ virtual GBool isCMYK() { return gfxMode == csDeviceCMYK; }
+
+ virtual GBool isParameterized() { return shading->isParameterized(); }
+ virtual int getNTriangles() { return shading->getNTriangles(); }
+ virtual void getTriangle(int i, double *x0, double *y0, double *color0,
+ double *x1, double *y1, double *color1,
+ double *x2, double *y2, double *color2)
+ { return shading->getTriangle(i, x0, y0, color0, x1, y1, color1, x2, y2, color2); }
+
+ virtual void getParameterizedColor(double t, SplashColorMode mode, SplashColorPtr c);
+
+private:
+ GfxGouraudTriangleShading *shading;
+ GfxState *state;
+ GBool bDirectColorTranslation;
+ SplashColorMode mode;
+ GfxColorSpaceMode gfxMode;
+};
+
+// see GfxState.h, GfxRadialShading
+class SplashRadialPattern: public SplashUnivariatePattern {
+public:
+
+ SplashRadialPattern(SplashColorMode colorMode, GfxState *state, GfxRadialShading *shading);
+
+ virtual SplashPattern *copy() { return new SplashRadialPattern(colorMode, state, (GfxRadialShading *) shading); }
+
+ virtual ~SplashRadialPattern();
+
+ virtual GBool getParameter(double xs, double ys, double *t);
+
+private:
+ double x0, y0, r0, dx, dy, dr;
+ double a, inva;
+};
+
+//------------------------------------------------------------------------
+
+// number of Type 3 fonts to cache
+#define splashOutT3FontCacheSize 8
+
+//------------------------------------------------------------------------
+// SplashOutputDev
+//------------------------------------------------------------------------
+
+class SplashOutputDev: public OutputDev {
+public:
+
+ // Constructor.
+ SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA,
+ GBool reverseVideoA, SplashColorPtr paperColorA,
+ GBool bitmapTopDownA = gTrue,
+ SplashThinLineMode thinLineMode = splashThinLineDefault,
+ GBool overprintPreviewA = globalParams->getOverprintPreview());
+
+ // Destructor.
+ virtual ~SplashOutputDev();
+
+ //----- get info about output device
+
+ // Does this device use tilingPatternFill()? If this returns false,
+ // tiling pattern fills will be reduced to a series of other drawing
+ // operations.
+ virtual GBool useTilingPatternFill() { return gTrue; }
+
+ // Does this device use functionShadedFill(), axialShadedFill(), and
+ // radialShadedFill()? If this returns false, these shaded fills
+ // will be reduced to a series of other drawing operations.
+ virtual GBool useShadedFills(int type)
+ { return (type >= 2 && type <= 5) ? gTrue : gFalse; }
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return bitmapTopDown ^ bitmapUpsideDown; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gTrue; }
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state, XRef *xref);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state);
+ virtual void restoreState(GfxState *state);
+
+ //----- update graphics state
+ virtual void updateAll(GfxState *state);
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32);
+ virtual void updateLineDash(GfxState *state);
+ virtual void updateFlatness(GfxState *state);
+ virtual void updateLineJoin(GfxState *state);
+ virtual void updateLineCap(GfxState *state);
+ virtual void updateMiterLimit(GfxState *state);
+ virtual void updateLineWidth(GfxState *state);
+ virtual void updateStrokeAdjust(GfxState *state);
+ virtual void updateFillColorSpace(GfxState *state);
+ virtual void updateStrokeColorSpace(GfxState *state);
+ virtual void updateFillColor(GfxState *state);
+ virtual void updateStrokeColor(GfxState *state);
+ virtual void updateBlendMode(GfxState *state);
+ virtual void updateFillOpacity(GfxState *state);
+ virtual void updateStrokeOpacity(GfxState *state);
+ virtual void updateFillOverprint(GfxState *state);
+ virtual void updateStrokeOverprint(GfxState *state);
+ virtual void updateOverprintMode(GfxState *state);
+ virtual void updateTransfer(GfxState *state);
+
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+ virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *catalog, Object *str,
+ double *pmat, int paintType, int tilingType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep);
+ virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax);
+ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading, double tMin, double tMax);
+ virtual GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading);
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+ virtual void eoClip(GfxState *state);
+ virtual void clipToStrokePath(GfxState *state);
+
+ //----- text drawing
+ virtual void drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode code, int nBytes, Unicode *u, int uLen);
+ virtual GBool beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen);
+ virtual void endType3Char(GfxState *state);
+ virtual void beginTextObject(GfxState *state);
+ virtual void endTextObject(GfxState *state);
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool interpolate, GBool inlineImg);
+ virtual void setSoftMaskFromImageMask(GfxState *state,
+ Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg, double *baseMatrix);
+ virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ GBool interpolate, int *maskColors, GBool inlineImg);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ GBool maskInvert, GBool maskInterpolate);
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ GBool interpolate,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap,
+ GBool maskInterpolate);
+
+ //----- Type 3 font operators
+ virtual void type3D0(GfxState *state, double wx, double wy);
+ virtual void type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury);
+
+ //----- transparency groups and soft masks
+ virtual GBool checkTransparencyGroup(GfxState *state, GBool knockout);
+ virtual void beginTransparencyGroup(GfxState *state, double *bbox,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ GBool forSoftMask);
+ virtual void endTransparencyGroup(GfxState *state);
+ virtual void paintTransparencyGroup(GfxState *state, double *bbox);
+ virtual void setSoftMask(GfxState *state, double *bbox, GBool alpha,
+ Function *transferFunc, GfxColor *backdropColor);
+ virtual void clearSoftMask(GfxState *state);
+
+ //----- special access
+
+ // Called to indicate that a new PDF document has been loaded.
+ void startDoc(PDFDoc *docA);
+
+ void setPaperColor(SplashColorPtr paperColorA);
+
+ GBool isReverseVideo() { return reverseVideo; }
+ void setReverseVideo(GBool reverseVideoA) { reverseVideo = reverseVideoA; }
+
+ // Get the bitmap and its size.
+ SplashBitmap *getBitmap() { return bitmap; }
+ int getBitmapWidth();
+ int getBitmapHeight();
+
+ // Returns the last rasterized bitmap, transferring ownership to the
+ // caller.
+ SplashBitmap *takeBitmap();
+
+ // Set this flag to true to generate an upside-down bitmap (useful
+ // for Windows BMP files).
+ void setBitmapUpsideDown(GBool f) { bitmapUpsideDown = f; }
+
+ // Get the Splash object.
+ Splash *getSplash() { return splash; }
+
+ // Get the modified region.
+ void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax);
+
+ // Clear the modified region.
+ void clearModRegion();
+
+ SplashFont *getCurrentFont() { return font; }
+
+ // If <skipTextA> is true, don't draw horizontal text.
+ // If <skipRotatedTextA> is true, don't draw rotated (non-horizontal) text.
+ void setSkipText(GBool skipHorizTextA, GBool skipRotatedTextA)
+ { skipHorizText = skipHorizTextA; skipRotatedText = skipRotatedTextA; }
+
+ int getNestCount() { return nestCount; }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ virtual GBool getVectorAntialias();
+ virtual void setVectorAntialias(GBool vaa);
+#endif
+
+ GBool getFontAntialias() { return fontAntialias; }
+ void setFontAntialias(GBool anti) { fontAntialias = anti; }
+
+ void setFreeTypeHinting(GBool enable, GBool enableSlightHinting);
+
+protected:
+ void doUpdateFont(GfxState *state);
+
+private:
+ GBool univariateShadedFill(GfxState *state, SplashUnivariatePattern *pattern, double tMin, double tMax);
+
+ void setupScreenParams(double hDPI, double vDPI);
+ SplashPattern *getColor(GfxGray gray);
+ SplashPattern *getColor(GfxRGB *rgb);
+#if SPLASH_CMYK
+ SplashPattern *getColor(GfxCMYK *cmyk);
+ SplashPattern *getColor(GfxColor *deviceN);
+#endif
+ void setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag,
+ int overprintMode, GfxColor *singleColor, GBool grayIndexed = gFalse);
+ SplashPath *convertPath(GfxState *state, GfxPath *path,
+ GBool dropEmptySubpaths);
+ void drawType3Glyph(GfxState *state, T3FontCache *t3Font,
+ T3FontCacheTag *tag, Guchar *data);
+#ifdef USE_CMS
+ GBool useIccImageSrc(void *data);
+ static void iccTransform(void *data, SplashBitmap *bitmap);
+ static GBool iccImageSrc(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine);
+#endif
+ static GBool imageMaskSrc(void *data, SplashColorPtr line);
+ static GBool imageSrc(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine);
+ static GBool alphaImageSrc(void *data, SplashColorPtr line,
+ Guchar *alphaLine);
+ static GBool maskedImageSrc(void *data, SplashColorPtr line,
+ Guchar *alphaLine);
+ static GBool tilingBitmapSrc(void *data, SplashColorPtr line,
+ Guchar *alphaLine);
+
+ GBool keepAlphaChannel; // don't fill with paper color, keep alpha channel
+
+ SplashColorMode colorMode;
+ int bitmapRowPad;
+ GBool bitmapTopDown;
+ GBool bitmapUpsideDown;
+ GBool fontAntialias;
+ GBool vectorAntialias;
+ GBool overprintPreview;
+ GBool enableFreeTypeHinting;
+ GBool enableSlightHinting;
+ GBool reverseVideo; // reverse video mode
+ SplashColor paperColor; // paper color
+ SplashScreenParams screenParams;
+ GBool skipHorizText;
+ GBool skipRotatedText;
+
+ PDFDoc *doc; // the current document
+ XRef *xref; // the xref of the current document
+
+ SplashBitmap *bitmap;
+ Splash *splash;
+ SplashFontEngine *fontEngine;
+
+ T3FontCache * // Type 3 font cache
+ t3FontCache[splashOutT3FontCacheSize];
+ int nT3Fonts; // number of valid entries in t3FontCache
+ T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack
+ GBool haveT3Dx; // set after seeing a d0/d1 operator
+
+ SplashFont *font; // current font
+ GBool needFontUpdate; // set when the font needs to be updated
+ SplashPath *textClipPath; // clipping path built with text object
+
+ SplashTransparencyGroup * // transparency group stack
+ transpGroupStack;
+ SplashBitmap *maskBitmap; // for image masks in pattern colorspace
+ int nestCount;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinCachedFile.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinCachedFile.cc
new file mode 100644
index 00000000000..db966377bb0
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinCachedFile.cc
@@ -0,0 +1,47 @@
+//========================================================================
+//
+// StdinCachedFile.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright 2010 Jonathan Liu <net147@gmail.com>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "StdinCachedFile.h"
+
+#ifdef _WIN32
+#include <fcntl.h> // for O_BINARY
+#include <io.h> // for setmode
+#endif
+#include <stdio.h>
+
+size_t StdinCacheLoader::init(GooString *dummy, CachedFile *cachedFile)
+{
+ size_t read, size = 0;
+ char buf[CachedFileChunkSize];
+
+#ifdef _WIN32
+ setmode(fileno(stdin), O_BINARY);
+#endif
+
+ CachedFileWriter writer = CachedFileWriter (cachedFile, NULL);
+ do {
+ read = fread(buf, 1, CachedFileChunkSize, stdin);
+ (writer.write) (buf, CachedFileChunkSize);
+ size += read;
+ }
+ while (read == CachedFileChunkSize);
+
+ return size;
+}
+
+int StdinCacheLoader::load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer)
+{
+ return 0;
+}
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinCachedFile.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinCachedFile.h
new file mode 100644
index 00000000000..5be6fa841a3
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinCachedFile.h
@@ -0,0 +1,27 @@
+//========================================================================
+//
+// StdinCachedFile.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef STDINCACHELOADER_H
+#define STDINCACHELOADER_H
+
+#include "CachedFile.h"
+
+class StdinCacheLoader : public CachedFileLoader {
+
+public:
+
+ size_t init(GooString *dummy, CachedFile* cachedFile);
+ int load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer);
+
+};
+
+#endif
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinPDFDocBuilder.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinPDFDocBuilder.cc
new file mode 100644
index 00000000000..571ee46d7f6
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinPDFDocBuilder.cc
@@ -0,0 +1,43 @@
+//========================================================================
+//
+// StdinPDFDocBuilder.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "StdinPDFDocBuilder.h"
+#include "CachedFile.h"
+#include "StdinCachedFile.h"
+
+//------------------------------------------------------------------------
+// StdinPDFDocBuilder
+//------------------------------------------------------------------------
+
+PDFDoc *
+StdinPDFDocBuilder::buildPDFDoc(const GooString &uri, GooString *ownerPassword,
+ GooString *userPassword, void *guiDataA)
+{
+ Object obj;
+
+ obj.initNull();
+ CachedFile *cachedFile = new CachedFile(new StdinCacheLoader(), NULL);
+ return new PDFDoc(new CachedFileStream(cachedFile, 0, gFalse,
+ cachedFile->getLength(), &obj),
+ ownerPassword, userPassword);
+}
+
+GBool StdinPDFDocBuilder::supports(const GooString &uri)
+{
+ if (uri.cmpN("fd://0", 6) == 0) {
+ return gTrue;
+ } else {
+ return gFalse;
+ }
+}
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinPDFDocBuilder.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinPDFDocBuilder.h
new file mode 100644
index 00000000000..e9b2f47f636
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/StdinPDFDocBuilder.h
@@ -0,0 +1,33 @@
+//========================================================================
+//
+// StdinPDFDocBuilder.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2010 Hib Eris <hib@hiberis.nl>
+// Copyright 2010 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef STDINPDFDOCBUILDER_H
+#define STDINPDFDOCBUILDER_H
+
+#include "PDFDocBuilder.h"
+
+//------------------------------------------------------------------------
+// StdinPDFDocBuilder
+//
+// The StdinPDFDocBuilder implements a PDFDocBuilder that read from stdin.
+//------------------------------------------------------------------------
+
+class StdinPDFDocBuilder : public PDFDocBuilder {
+
+public:
+
+ PDFDoc *buildPDFDoc(const GooString &uri, GooString *ownerPassword = NULL,
+ GooString *userPassword = NULL, void *guiDataA = NULL);
+ GBool supports(const GooString &uri);
+
+};
+
+#endif /* STDINPDFDOCBUILDER_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream-CCITT.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream-CCITT.h
new file mode 100644
index 00000000000..7207729a4d1
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream-CCITT.h
@@ -0,0 +1,478 @@
+//========================================================================
+//
+// Stream-CCITT.h
+//
+// Tables for CCITT Fax decoding.
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef STREAM_CCITT_H
+#define STREAM_CCITT_H
+
+struct CCITTCode {
+ short bits;
+ short n;
+};
+
+#define ccittEOL -2
+
+//------------------------------------------------------------------------
+// 2D codes
+//------------------------------------------------------------------------
+
+#define twoDimPass 0
+#define twoDimHoriz 1
+#define twoDimVert0 2
+#define twoDimVertR1 3
+#define twoDimVertL1 4
+#define twoDimVertR2 5
+#define twoDimVertL2 6
+#define twoDimVertR3 7
+#define twoDimVertL3 8
+
+// 1-7 bit codes
+static const CCITTCode twoDimTab1[128] = {
+ {-1, -1}, {-1, -1}, // 000000x
+ {7, twoDimVertL3}, // 0000010
+ {7, twoDimVertR3}, // 0000011
+ {6, twoDimVertL2}, {6, twoDimVertL2}, // 000010x
+ {6, twoDimVertR2}, {6, twoDimVertR2}, // 000011x
+ {4, twoDimPass}, {4, twoDimPass}, // 0001xxx
+ {4, twoDimPass}, {4, twoDimPass},
+ {4, twoDimPass}, {4, twoDimPass},
+ {4, twoDimPass}, {4, twoDimPass},
+ {3, twoDimHoriz}, {3, twoDimHoriz}, // 001xxxx
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimVertL1}, {3, twoDimVertL1}, // 010xxxx
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertR1}, {3, twoDimVertR1}, // 011xxxx
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {1, twoDimVert0}, {1, twoDimVert0}, // 1xxxxxx
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0}
+};
+
+//------------------------------------------------------------------------
+// white run lengths
+//------------------------------------------------------------------------
+
+// 11-12 bit codes (upper 7 bits are 0)
+static const CCITTCode whiteTab1[32] = {
+ {-1, -1}, // 00000
+ {12, ccittEOL}, // 00001
+ {-1, -1}, {-1, -1}, // 0001x
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 001xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 010xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 011xx
+ {11, 1792}, {11, 1792}, // 1000x
+ {12, 1984}, // 10010
+ {12, 2048}, // 10011
+ {12, 2112}, // 10100
+ {12, 2176}, // 10101
+ {12, 2240}, // 10110
+ {12, 2304}, // 10111
+ {11, 1856}, {11, 1856}, // 1100x
+ {11, 1920}, {11, 1920}, // 1101x
+ {12, 2368}, // 11100
+ {12, 2432}, // 11101
+ {12, 2496}, // 11110
+ {12, 2560} // 11111
+};
+
+// 1-9 bit codes
+static const CCITTCode whiteTab2[512] = {
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000000xx
+ {8, 29}, {8, 29}, // 00000010x
+ {8, 30}, {8, 30}, // 00000011x
+ {8, 45}, {8, 45}, // 00000100x
+ {8, 46}, {8, 46}, // 00000101x
+ {7, 22}, {7, 22}, {7, 22}, {7, 22}, // 0000011xx
+ {7, 23}, {7, 23}, {7, 23}, {7, 23}, // 0000100xx
+ {8, 47}, {8, 47}, // 00001010x
+ {8, 48}, {8, 48}, // 00001011x
+ {6, 13}, {6, 13}, {6, 13}, {6, 13}, // 000011xxx
+ {6, 13}, {6, 13}, {6, 13}, {6, 13},
+ {7, 20}, {7, 20}, {7, 20}, {7, 20}, // 0001000xx
+ {8, 33}, {8, 33}, // 00010010x
+ {8, 34}, {8, 34}, // 00010011x
+ {8, 35}, {8, 35}, // 00010100x
+ {8, 36}, {8, 36}, // 00010101x
+ {8, 37}, {8, 37}, // 00010110x
+ {8, 38}, {8, 38}, // 00010111x
+ {7, 19}, {7, 19}, {7, 19}, {7, 19}, // 0001100xx
+ {8, 31}, {8, 31}, // 00011010x
+ {8, 32}, {8, 32}, // 00011011x
+ {6, 1}, {6, 1}, {6, 1}, {6, 1}, // 000111xxx
+ {6, 1}, {6, 1}, {6, 1}, {6, 1},
+ {6, 12}, {6, 12}, {6, 12}, {6, 12}, // 001000xxx
+ {6, 12}, {6, 12}, {6, 12}, {6, 12},
+ {8, 53}, {8, 53}, // 00100100x
+ {8, 54}, {8, 54}, // 00100101x
+ {7, 26}, {7, 26}, {7, 26}, {7, 26}, // 0010011xx
+ {8, 39}, {8, 39}, // 00101000x
+ {8, 40}, {8, 40}, // 00101001x
+ {8, 41}, {8, 41}, // 00101010x
+ {8, 42}, {8, 42}, // 00101011x
+ {8, 43}, {8, 43}, // 00101100x
+ {8, 44}, {8, 44}, // 00101101x
+ {7, 21}, {7, 21}, {7, 21}, {7, 21}, // 0010111xx
+ {7, 28}, {7, 28}, {7, 28}, {7, 28}, // 0011000xx
+ {8, 61}, {8, 61}, // 00110010x
+ {8, 62}, {8, 62}, // 00110011x
+ {8, 63}, {8, 63}, // 00110100x
+ {8, 0}, {8, 0}, // 00110101x
+ {8, 320}, {8, 320}, // 00110110x
+ {8, 384}, {8, 384}, // 00110111x
+ {5, 10}, {5, 10}, {5, 10}, {5, 10}, // 00111xxxx
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11}, // 01000xxxx
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {7, 27}, {7, 27}, {7, 27}, {7, 27}, // 0100100xx
+ {8, 59}, {8, 59}, // 01001010x
+ {8, 60}, {8, 60}, // 01001011x
+ {9, 1472}, // 010011000
+ {9, 1536}, // 010011001
+ {9, 1600}, // 010011010
+ {9, 1728}, // 010011011
+ {7, 18}, {7, 18}, {7, 18}, {7, 18}, // 0100111xx
+ {7, 24}, {7, 24}, {7, 24}, {7, 24}, // 0101000xx
+ {8, 49}, {8, 49}, // 01010010x
+ {8, 50}, {8, 50}, // 01010011x
+ {8, 51}, {8, 51}, // 01010100x
+ {8, 52}, {8, 52}, // 01010101x
+ {7, 25}, {7, 25}, {7, 25}, {7, 25}, // 0101011xx
+ {8, 55}, {8, 55}, // 01011000x
+ {8, 56}, {8, 56}, // 01011001x
+ {8, 57}, {8, 57}, // 01011010x
+ {8, 58}, {8, 58}, // 01011011x
+ {6, 192}, {6, 192}, {6, 192}, {6, 192}, // 010111xxx
+ {6, 192}, {6, 192}, {6, 192}, {6, 192},
+ {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, // 011000xxx
+ {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664},
+ {8, 448}, {8, 448}, // 01100100x
+ {8, 512}, {8, 512}, // 01100101x
+ {9, 704}, // 011001100
+ {9, 768}, // 011001101
+ {8, 640}, {8, 640}, // 01100111x
+ {8, 576}, {8, 576}, // 01101000x
+ {9, 832}, // 011010010
+ {9, 896}, // 011010011
+ {9, 960}, // 011010100
+ {9, 1024}, // 011010101
+ {9, 1088}, // 011010110
+ {9, 1152}, // 011010111
+ {9, 1216}, // 011011000
+ {9, 1280}, // 011011001
+ {9, 1344}, // 011011010
+ {9, 1408}, // 011011011
+ {7, 256}, {7, 256}, {7, 256}, {7, 256}, // 0110111xx
+ {4, 2}, {4, 2}, {4, 2}, {4, 2}, // 0111xxxxx
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3}, // 1000xxxxx
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128}, // 10010xxxx
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8}, // 10011xxxx
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9}, // 10100xxxx
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {6, 16}, {6, 16}, {6, 16}, {6, 16}, // 101010xxx
+ {6, 16}, {6, 16}, {6, 16}, {6, 16},
+ {6, 17}, {6, 17}, {6, 17}, {6, 17}, // 101011xxx
+ {6, 17}, {6, 17}, {6, 17}, {6, 17},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4}, // 1011xxxxx
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 1100xxxxx
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {6, 14}, {6, 14}, {6, 14}, {6, 14}, // 110100xxx
+ {6, 14}, {6, 14}, {6, 14}, {6, 14},
+ {6, 15}, {6, 15}, {6, 15}, {6, 15}, // 110101xxx
+ {6, 15}, {6, 15}, {6, 15}, {6, 15},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64}, // 11011xxxx
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 1110xxxxx
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7}, // 1111xxxxx
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7}
+};
+
+//------------------------------------------------------------------------
+// black run lengths
+//------------------------------------------------------------------------
+
+// 10-13 bit codes (upper 6 bits are 0)
+static const CCITTCode blackTab1[128] = {
+ {-1, -1}, {-1, -1}, // 000000000000x
+ {12, ccittEOL}, {12, ccittEOL}, // 000000000001x
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000001xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000010xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000011xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000100xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000101xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000110xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000111xx
+ {11, 1792}, {11, 1792}, {11, 1792}, {11, 1792}, // 00000001000xx
+ {12, 1984}, {12, 1984}, // 000000010010x
+ {12, 2048}, {12, 2048}, // 000000010011x
+ {12, 2112}, {12, 2112}, // 000000010100x
+ {12, 2176}, {12, 2176}, // 000000010101x
+ {12, 2240}, {12, 2240}, // 000000010110x
+ {12, 2304}, {12, 2304}, // 000000010111x
+ {11, 1856}, {11, 1856}, {11, 1856}, {11, 1856}, // 00000001100xx
+ {11, 1920}, {11, 1920}, {11, 1920}, {11, 1920}, // 00000001101xx
+ {12, 2368}, {12, 2368}, // 000000011100x
+ {12, 2432}, {12, 2432}, // 000000011101x
+ {12, 2496}, {12, 2496}, // 000000011110x
+ {12, 2560}, {12, 2560}, // 000000011111x
+ {10, 18}, {10, 18}, {10, 18}, {10, 18}, // 0000001000xxx
+ {10, 18}, {10, 18}, {10, 18}, {10, 18},
+ {12, 52}, {12, 52}, // 000000100100x
+ {13, 640}, // 0000001001010
+ {13, 704}, // 0000001001011
+ {13, 768}, // 0000001001100
+ {13, 832}, // 0000001001101
+ {12, 55}, {12, 55}, // 000000100111x
+ {12, 56}, {12, 56}, // 000000101000x
+ {13, 1280}, // 0000001010010
+ {13, 1344}, // 0000001010011
+ {13, 1408}, // 0000001010100
+ {13, 1472}, // 0000001010101
+ {12, 59}, {12, 59}, // 000000101011x
+ {12, 60}, {12, 60}, // 000000101100x
+ {13, 1536}, // 0000001011010
+ {13, 1600}, // 0000001011011
+ {11, 24}, {11, 24}, {11, 24}, {11, 24}, // 00000010111xx
+ {11, 25}, {11, 25}, {11, 25}, {11, 25}, // 00000011000xx
+ {13, 1664}, // 0000001100100
+ {13, 1728}, // 0000001100101
+ {12, 320}, {12, 320}, // 000000110011x
+ {12, 384}, {12, 384}, // 000000110100x
+ {12, 448}, {12, 448}, // 000000110101x
+ {13, 512}, // 0000001101100
+ {13, 576}, // 0000001101101
+ {12, 53}, {12, 53}, // 000000110111x
+ {12, 54}, {12, 54}, // 000000111000x
+ {13, 896}, // 0000001110010
+ {13, 960}, // 0000001110011
+ {13, 1024}, // 0000001110100
+ {13, 1088}, // 0000001110101
+ {13, 1152}, // 0000001110110
+ {13, 1216}, // 0000001110111
+ {10, 64}, {10, 64}, {10, 64}, {10, 64}, // 0000001111xxx
+ {10, 64}, {10, 64}, {10, 64}, {10, 64}
+};
+
+// 7-12 bit codes (upper 4 bits are 0)
+static const CCITTCode blackTab2[192] = {
+ {8, 13}, {8, 13}, {8, 13}, {8, 13}, // 00000100xxxx
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {11, 23}, {11, 23}, // 00000101000x
+ {12, 50}, // 000001010010
+ {12, 51}, // 000001010011
+ {12, 44}, // 000001010100
+ {12, 45}, // 000001010101
+ {12, 46}, // 000001010110
+ {12, 47}, // 000001010111
+ {12, 57}, // 000001011000
+ {12, 58}, // 000001011001
+ {12, 61}, // 000001011010
+ {12, 256}, // 000001011011
+ {10, 16}, {10, 16}, {10, 16}, {10, 16}, // 0000010111xx
+ {10, 17}, {10, 17}, {10, 17}, {10, 17}, // 0000011000xx
+ {12, 48}, // 000001100100
+ {12, 49}, // 000001100101
+ {12, 62}, // 000001100110
+ {12, 63}, // 000001100111
+ {12, 30}, // 000001101000
+ {12, 31}, // 000001101001
+ {12, 32}, // 000001101010
+ {12, 33}, // 000001101011
+ {12, 40}, // 000001101100
+ {12, 41}, // 000001101101
+ {11, 22}, {11, 22}, // 00000110111x
+ {8, 14}, {8, 14}, {8, 14}, {8, 14}, // 00000111xxxx
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10}, // 0000100xxxxx
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11}, // 0000101xxxxx
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {9, 15}, {9, 15}, {9, 15}, {9, 15}, // 000011000xxx
+ {9, 15}, {9, 15}, {9, 15}, {9, 15},
+ {12, 128}, // 000011001000
+ {12, 192}, // 000011001001
+ {12, 26}, // 000011001010
+ {12, 27}, // 000011001011
+ {12, 28}, // 000011001100
+ {12, 29}, // 000011001101
+ {11, 19}, {11, 19}, // 00001100111x
+ {11, 20}, {11, 20}, // 00001101000x
+ {12, 34}, // 000011010010
+ {12, 35}, // 000011010011
+ {12, 36}, // 000011010100
+ {12, 37}, // 000011010101
+ {12, 38}, // 000011010110
+ {12, 39}, // 000011010111
+ {11, 21}, {11, 21}, // 00001101100x
+ {12, 42}, // 000011011010
+ {12, 43}, // 000011011011
+ {10, 0}, {10, 0}, {10, 0}, {10, 0}, // 0000110111xx
+ {7, 12}, {7, 12}, {7, 12}, {7, 12}, // 0000111xxxxx
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12}
+};
+
+// 2-6 bit codes
+static const CCITTCode blackTab3[64] = {
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000xx
+ {6, 9}, // 000100
+ {6, 8}, // 000101
+ {5, 7}, {5, 7}, // 00011x
+ {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 0010xx
+ {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 0011xx
+ {3, 1}, {3, 1}, {3, 1}, {3, 1}, // 010xxx
+ {3, 1}, {3, 1}, {3, 1}, {3, 1},
+ {3, 4}, {3, 4}, {3, 4}, {3, 4}, // 011xxx
+ {3, 4}, {3, 4}, {3, 4}, {3, 4},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3}, // 10xxxx
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2}, // 11xxxx
+ {2, 2}, {2, 2}, {2, 2}, {2, 2},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2}
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream.cc
new file mode 100644
index 00000000000..961767896c2
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream.cc
@@ -0,0 +1,5388 @@
+//========================================================================
+//
+// Stream.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2006-2010, 2012-2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+// Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009 Glenn Ganz <glenn.ganz@uptime.ch>
+// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2010 Tomas Hoger <thoger@redhat.com>
+// Copyright (C) 2011, 2012 William Bader <williambader@hotmail.com>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Oliver Sander <sander@mi.fu-berlin.de>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012 Even Rouault <even.rouault@mines-paris.org>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Adam Reichold <adamreichold@myopera.com>
+// Copyright (C) 2013 Pino Toscano <pino@kde.org>
+// Copyright (C) 2015 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+// Copyright (C) 2015 Jason Crain <jason@aquaticape.us>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#include "goo/gmem.h"
+#include "goo/gfile.h"
+#include "poppler-config.h"
+#include "Error.h"
+#include "Object.h"
+#include "Lexer.h"
+#include "GfxState.h"
+#include "Stream.h"
+#include "XRef.h"
+#include "JBIG2Stream.h"
+#include "Stream-CCITT.h"
+#include "CachedFile.h"
+
+#ifdef ENABLE_LIBJPEG
+#include "DCTStream.h"
+#endif
+
+#ifdef ENABLE_ZLIB
+#include "FlateStream.h"
+#endif
+
+#ifdef ENABLE_LIBOPENJPEG
+#include "JPEG2000Stream.h"
+#else
+#include "JPXStream.h"
+#endif
+
+#ifdef __DJGPP__
+static GBool setDJSYSFLAGS = gFalse;
+#endif
+
+#ifdef VMS
+#ifdef __GNUC__
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+#endif
+
+#if MULTITHREADED
+# define streamLocker() MutexLocker locker(&mutex)
+#else
+# define streamLocker()
+#endif
+//------------------------------------------------------------------------
+// Stream (base class)
+//------------------------------------------------------------------------
+
+Stream::Stream() {
+ ref = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+Stream::~Stream() {
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+int Stream::incRef() {
+ streamLocker();
+ ++ref;
+ return ref;
+}
+
+int Stream::decRef() {
+ streamLocker();
+ --ref;
+ return ref;
+}
+
+void Stream::close() {
+}
+
+int Stream::getRawChar() {
+ error(errInternal, -1, "Internal: called getRawChar() on non-predictor stream");
+ return EOF;
+}
+
+int Stream::getChars(int nChars, Guchar *buffer) {
+ error(errInternal, -1, "Internal: called getChars() on non-predictor stream");
+ return 0;
+}
+
+void Stream::getRawChars(int nChars, int *buffer) {
+ error(errInternal, -1, "Internal: called getRawChars() on non-predictor stream");
+}
+
+char *Stream::getLine(char *buf, int size) {
+ int i;
+ int c;
+
+ if (lookChar() == EOF || size < 0)
+ return NULL;
+ for (i = 0; i < size - 1; ++i) {
+ c = getChar();
+ if (c == EOF || c == '\n')
+ break;
+ if (c == '\r') {
+ if ((c = lookChar()) == '\n')
+ getChar();
+ break;
+ }
+ buf[i] = c;
+ }
+ buf[i] = '\0';
+ return buf;
+}
+
+GooString *Stream::getPSFilter(int psLevel, const char *indent) {
+ return new GooString();
+}
+
+Stream *Stream::addFilters(Object *dict, int recursion) {
+ Object obj, obj2;
+ Object params, params2;
+ Stream *str;
+ int i;
+
+ str = this;
+ dict->dictLookup("Filter", &obj, recursion);
+ if (obj.isNull()) {
+ obj.free();
+ dict->dictLookup("F", &obj);
+ }
+ dict->dictLookup("DecodeParms", &params, recursion);
+ if (params.isNull()) {
+ params.free();
+ dict->dictLookup("DP", &params);
+ }
+ if (obj.isName()) {
+ str = makeFilter(obj.getName(), str, &params, recursion, dict);
+ } else if (obj.isArray()) {
+ for (i = 0; i < obj.arrayGetLength(); ++i) {
+ obj.arrayGet(i, &obj2, recursion);
+ if (params.isArray())
+ params.arrayGet(i, &params2, recursion);
+ else
+ params2.initNull();
+ if (obj2.isName()) {
+ str = makeFilter(obj2.getName(), str, &params2, recursion);
+ } else {
+ error(errSyntaxError, getPos(), "Bad filter name");
+ str = new EOFStream(str);
+ }
+ obj2.free();
+ params2.free();
+ }
+ } else if (!obj.isNull()) {
+ error(errSyntaxError, getPos(), "Bad 'Filter' attribute in stream");
+ }
+ obj.free();
+ params.free();
+
+ return str;
+}
+
+Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursion, Object *dict) {
+ int pred; // parameters
+ int colors;
+ int bits;
+ int early;
+ int encoding;
+ GBool endOfLine, byteAlign, endOfBlock, black;
+ int columns, rows;
+ int colorXform;
+ Object globals, obj;
+
+ if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) {
+ str = new ASCIIHexStream(str);
+ } else if (!strcmp(name, "ASCII85Decode") || !strcmp(name, "A85")) {
+ str = new ASCII85Stream(str);
+ } else if (!strcmp(name, "LZWDecode") || !strcmp(name, "LZW")) {
+ pred = 1;
+ columns = 1;
+ colors = 1;
+ bits = 8;
+ early = 1;
+ if (params->isDict()) {
+ params->dictLookup("Predictor", &obj, recursion);
+ if (obj.isInt())
+ pred = obj.getInt();
+ obj.free();
+ params->dictLookup("Columns", &obj, recursion);
+ if (obj.isInt())
+ columns = obj.getInt();
+ obj.free();
+ params->dictLookup("Colors", &obj, recursion);
+ if (obj.isInt())
+ colors = obj.getInt();
+ obj.free();
+ params->dictLookup("BitsPerComponent", &obj, recursion);
+ if (obj.isInt())
+ bits = obj.getInt();
+ obj.free();
+ params->dictLookup("EarlyChange", &obj, recursion);
+ if (obj.isInt())
+ early = obj.getInt();
+ obj.free();
+ }
+ str = new LZWStream(str, pred, columns, colors, bits, early);
+ } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) {
+ str = new RunLengthStream(str);
+ } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) {
+ encoding = 0;
+ endOfLine = gFalse;
+ byteAlign = gFalse;
+ columns = 1728;
+ rows = 0;
+ endOfBlock = gTrue;
+ black = gFalse;
+ if (params->isDict()) {
+ params->dictLookup("K", &obj, recursion);
+ if (obj.isInt()) {
+ encoding = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("EndOfLine", &obj, recursion);
+ if (obj.isBool()) {
+ endOfLine = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("EncodedByteAlign", &obj, recursion);
+ if (obj.isBool()) {
+ byteAlign = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("Columns", &obj, recursion);
+ if (obj.isInt()) {
+ columns = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("Rows", &obj, recursion);
+ if (obj.isInt()) {
+ rows = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("EndOfBlock", &obj, recursion);
+ if (obj.isBool()) {
+ endOfBlock = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("BlackIs1", &obj, recursion);
+ if (obj.isBool()) {
+ black = obj.getBool();
+ }
+ obj.free();
+ }
+ str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign,
+ columns, rows, endOfBlock, black);
+ } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) {
+ colorXform = -1;
+ if (params->isDict()) {
+ if (params->dictLookup("ColorTransform", &obj, recursion)->isInt()) {
+ colorXform = obj.getInt();
+ }
+ obj.free();
+ }
+ str = new DCTStream(str, colorXform, dict, recursion);
+ } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) {
+ pred = 1;
+ columns = 1;
+ colors = 1;
+ bits = 8;
+ if (params->isDict()) {
+ params->dictLookup("Predictor", &obj, recursion);
+ if (obj.isInt())
+ pred = obj.getInt();
+ obj.free();
+ params->dictLookup("Columns", &obj, recursion);
+ if (obj.isInt())
+ columns = obj.getInt();
+ obj.free();
+ params->dictLookup("Colors", &obj, recursion);
+ if (obj.isInt())
+ colors = obj.getInt();
+ obj.free();
+ params->dictLookup("BitsPerComponent", &obj, recursion);
+ if (obj.isInt())
+ bits = obj.getInt();
+ obj.free();
+ }
+ str = new FlateStream(str, pred, columns, colors, bits);
+ } else if (!strcmp(name, "JBIG2Decode")) {
+ if (params->isDict()) {
+ XRef *xref = params->getDict()->getXRef();
+ params->dictLookupNF("JBIG2Globals", &obj);
+ obj.fetch(xref, &globals, recursion);
+ }
+ str = new JBIG2Stream(str, &globals, &obj);
+ globals.free();
+ obj.free();
+ } else if (!strcmp(name, "JPXDecode")) {
+ str = new JPXStream(str);
+ } else if (!strcmp(name, "Crypt")) {
+ if (str->getKind() == strCrypt) {
+ str = str->getBaseStream();
+ } else {
+ error(errSyntaxError, getPos(), "Can't revert non decrypt streams");
+ }
+ } else {
+ error(errSyntaxError, getPos(), "Unknown filter '{0:s}'", name);
+ str = new EOFStream(str);
+ }
+ return str;
+}
+
+//------------------------------------------------------------------------
+// OutStream
+//------------------------------------------------------------------------
+OutStream::OutStream ()
+{
+ ref = 1;
+}
+
+OutStream::~OutStream ()
+{
+}
+
+//------------------------------------------------------------------------
+// FileOutStream
+//------------------------------------------------------------------------
+FileOutStream::FileOutStream (FILE* fa, Goffset startA)
+{
+ f = fa;
+ start = startA;
+}
+
+FileOutStream::~FileOutStream ()
+{
+ close ();
+}
+
+void FileOutStream::close ()
+{
+
+}
+
+Goffset FileOutStream::getPos ()
+{
+ return Gftell(f);
+}
+
+void FileOutStream::put (char c)
+{
+ fputc(c,f);
+}
+
+void FileOutStream::printf(const char *format, ...)
+{
+ va_list argptr;
+ va_start (argptr, format);
+ vfprintf(f, format, argptr);
+ va_end (argptr);
+}
+
+
+//------------------------------------------------------------------------
+// BaseStream
+//------------------------------------------------------------------------
+
+BaseStream::BaseStream(Object *dictA, Goffset lengthA) {
+ dict = *dictA;
+ length = lengthA;
+}
+
+BaseStream::~BaseStream() {
+ dict.free();
+}
+
+//------------------------------------------------------------------------
+// FilterStream
+//------------------------------------------------------------------------
+
+FilterStream::FilterStream(Stream *strA) {
+ str = strA;
+}
+
+FilterStream::~FilterStream() {
+}
+
+void FilterStream::close() {
+ str->close();
+}
+
+void FilterStream::setPos(Goffset pos, int dir) {
+ error(errInternal, -1, "Internal: called setPos() on FilterStream");
+}
+
+//------------------------------------------------------------------------
+// ImageStream
+//------------------------------------------------------------------------
+
+ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) {
+ int imgLineSize;
+
+ str = strA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
+
+ nVals = width * nComps;
+ inputLineSize = (nVals * nBits + 7) >> 3;
+ if (nBits <= 0 || nVals > INT_MAX / nBits - 7 || width > INT_MAX / nComps) {
+ inputLineSize = -1;
+ }
+ inputLine = (Guchar *)gmallocn_checkoverflow(inputLineSize, sizeof(char));
+ if (nBits == 8) {
+ imgLine = (Guchar *)inputLine;
+ } else {
+ if (nBits == 1) {
+ imgLineSize = (nVals + 7) & ~7;
+ } else {
+ imgLineSize = nVals;
+ }
+ if (width > INT_MAX / nComps) {
+ // force a call to gmallocn(-1,...), which will throw an exception
+ imgLineSize = -1;
+ }
+ imgLine = (Guchar *)gmallocn(imgLineSize, sizeof(Guchar));
+ }
+ imgIdx = nVals;
+}
+
+ImageStream::~ImageStream() {
+ if (imgLine != (Guchar *)inputLine) {
+ gfree(imgLine);
+ }
+ gfree(inputLine);
+}
+
+void ImageStream::reset() {
+ str->reset();
+}
+
+void ImageStream::close() {
+ str->close();
+}
+
+GBool ImageStream::getPixel(Guchar *pix) {
+ int i;
+
+ if (imgIdx >= nVals) {
+ if (!getLine()) {
+ return gFalse;
+ }
+ imgIdx = 0;
+ }
+ for (i = 0; i < nComps; ++i) {
+ pix[i] = imgLine[imgIdx++];
+ }
+ return gTrue;
+}
+
+Guchar *ImageStream::getLine() {
+ Gulong buf, bitMask;
+ int bits;
+ int c;
+ int i;
+ Guchar *p;
+
+ if (unlikely(inputLine == NULL)) {
+ return NULL;
+ }
+
+ int readChars = str->doGetChars(inputLineSize, inputLine);
+ for ( ; readChars < inputLineSize; readChars++) inputLine[readChars] = EOF;
+ if (nBits == 1) {
+ p = inputLine;
+ for (i = 0; i < nVals; i += 8) {
+ c = *p++;
+ imgLine[i+0] = (Guchar)((c >> 7) & 1);
+ imgLine[i+1] = (Guchar)((c >> 6) & 1);
+ imgLine[i+2] = (Guchar)((c >> 5) & 1);
+ imgLine[i+3] = (Guchar)((c >> 4) & 1);
+ imgLine[i+4] = (Guchar)((c >> 3) & 1);
+ imgLine[i+5] = (Guchar)((c >> 2) & 1);
+ imgLine[i+6] = (Guchar)((c >> 1) & 1);
+ imgLine[i+7] = (Guchar)(c & 1);
+ }
+ } else if (nBits == 8) {
+ // special case: imgLine == inputLine
+ } else if (nBits == 16) {
+ // this is a hack to support 16 bits images, everywhere
+ // we assume a component fits in 8 bits, with this hack
+ // we treat 16 bit images as 8 bit ones until it's fixed correctly.
+ // The hack has another part on GfxImageColorMap::GfxImageColorMap
+ p = inputLine;
+ for (i = 0; i < nVals; ++i) {
+ imgLine[i] = *p++;
+ p++;
+ }
+ } else {
+ bitMask = (1 << nBits) - 1;
+ buf = 0;
+ bits = 0;
+ p = inputLine;
+ for (i = 0; i < nVals; ++i) {
+ if (bits < nBits) {
+ buf = (buf << 8) | (*p++ & 0xff);
+ bits += 8;
+ }
+ imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask);
+ bits -= nBits;
+ }
+ }
+ return imgLine;
+}
+
+void ImageStream::skipLine() {
+ str->doGetChars(inputLineSize, inputLine);
+}
+
+//------------------------------------------------------------------------
+// StreamPredictor
+//------------------------------------------------------------------------
+
+StreamPredictor::StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA) {
+ str = strA;
+ predictor = predictorA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
+ predLine = NULL;
+ ok = gFalse;
+
+ nVals = width * nComps;
+ pixBytes = (nComps * nBits + 7) >> 3;
+ rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes;
+ if (width <= 0 || nComps <= 0 || nBits <= 0 ||
+ nComps > gfxColorMaxComps ||
+ nBits > 16 ||
+ width >= INT_MAX / nComps || // check for overflow in nVals
+ nVals >= (INT_MAX - 7) / nBits) { // check for overflow in rowBytes
+ return;
+ }
+ predLine = (Guchar *)gmalloc(rowBytes);
+ memset(predLine, 0, rowBytes);
+ predIdx = rowBytes;
+
+ ok = gTrue;
+}
+
+StreamPredictor::~StreamPredictor() {
+ gfree(predLine);
+}
+
+int StreamPredictor::lookChar() {
+ if (predIdx >= rowBytes) {
+ if (!getNextLine()) {
+ return EOF;
+ }
+ }
+ return predLine[predIdx];
+}
+
+int StreamPredictor::getChar() {
+ if (predIdx >= rowBytes) {
+ if (!getNextLine()) {
+ return EOF;
+ }
+ }
+ return predLine[predIdx++];
+}
+
+int StreamPredictor::getChars(int nChars, Guchar *buffer) {
+ int n, m;
+
+ n = 0;
+ while (n < nChars) {
+ if (predIdx >= rowBytes) {
+ if (!getNextLine()) {
+ break;
+ }
+ }
+ m = rowBytes - predIdx;
+ if (m > nChars - n) {
+ m = nChars - n;
+ }
+ memcpy(buffer + n, predLine + predIdx, m);
+ predIdx += m;
+ n += m;
+ }
+ return n;
+}
+
+GBool StreamPredictor::getNextLine() {
+ int curPred;
+ Guchar upLeftBuf[gfxColorMaxComps * 2 + 1];
+ int left, up, upLeft, p, pa, pb, pc;
+ int c;
+ Gulong inBuf, outBuf, bitMask;
+ int inBits, outBits;
+ int i, j, k, kk;
+
+ // get PNG optimum predictor number
+ if (predictor >= 10) {
+ if ((curPred = str->getRawChar()) == EOF) {
+ return gFalse;
+ }
+ curPred += 10;
+ } else {
+ curPred = predictor;
+ }
+
+ // read the raw line, apply PNG (byte) predictor
+ int *rawCharLine = new int[rowBytes - pixBytes];
+ str->getRawChars(rowBytes - pixBytes, rawCharLine);
+ memset(upLeftBuf, 0, pixBytes + 1);
+ for (i = pixBytes; i < rowBytes; ++i) {
+ for (j = pixBytes; j > 0; --j) {
+ upLeftBuf[j] = upLeftBuf[j-1];
+ }
+ upLeftBuf[0] = predLine[i];
+ if ((c = rawCharLine[i - pixBytes]) == EOF) {
+ if (i > pixBytes) {
+ // this ought to return false, but some (broken) PDF files
+ // contain truncated image data, and Adobe apparently reads the
+ // last partial line
+ break;
+ }
+ delete[] rawCharLine;
+ return gFalse;
+ }
+ switch (curPred) {
+ case 11: // PNG sub
+ predLine[i] = predLine[i - pixBytes] + (Guchar)c;
+ break;
+ case 12: // PNG up
+ predLine[i] = predLine[i] + (Guchar)c;
+ break;
+ case 13: // PNG average
+ predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) +
+ (Guchar)c;
+ break;
+ case 14: // PNG Paeth
+ left = predLine[i - pixBytes];
+ up = predLine[i];
+ upLeft = upLeftBuf[pixBytes];
+ p = left + up - upLeft;
+ if ((pa = p - left) < 0)
+ pa = -pa;
+ if ((pb = p - up) < 0)
+ pb = -pb;
+ if ((pc = p - upLeft) < 0)
+ pc = -pc;
+ if (pa <= pb && pa <= pc)
+ predLine[i] = left + (Guchar)c;
+ else if (pb <= pc)
+ predLine[i] = up + (Guchar)c;
+ else
+ predLine[i] = upLeft + (Guchar)c;
+ break;
+ case 10: // PNG none
+ default: // no predictor or TIFF predictor
+ predLine[i] = (Guchar)c;
+ break;
+ }
+ }
+ delete[] rawCharLine;
+
+ // apply TIFF (component) predictor
+ if (predictor == 2) {
+ if (nBits == 1) {
+ inBuf = predLine[pixBytes - 1];
+ for (i = pixBytes; i < rowBytes; i += 8) {
+ // 1-bit add is just xor
+ inBuf = (inBuf << 8) | predLine[i];
+ predLine[i] ^= inBuf >> nComps;
+ }
+ } else if (nBits == 8) {
+ for (i = pixBytes; i < rowBytes; ++i) {
+ predLine[i] += predLine[i - nComps];
+ }
+ } else {
+ memset(upLeftBuf, 0, nComps + 1);
+ bitMask = (1 << nBits) - 1;
+ inBuf = outBuf = 0;
+ inBits = outBits = 0;
+ j = k = pixBytes;
+ for (i = 0; i < width; ++i) {
+ for (kk = 0; kk < nComps; ++kk) {
+ if (inBits < nBits) {
+ inBuf = (inBuf << 8) | (predLine[j++] & 0xff);
+ inBits += 8;
+ }
+ upLeftBuf[kk] = (Guchar)((upLeftBuf[kk] +
+ (inBuf >> (inBits - nBits))) & bitMask);
+ inBits -= nBits;
+ outBuf = (outBuf << nBits) | upLeftBuf[kk];
+ outBits += nBits;
+ if (outBits >= 8) {
+ predLine[k++] = (Guchar)(outBuf >> (outBits - 8));
+ outBits -= 8;
+ }
+ }
+ }
+ if (outBits > 0) {
+ predLine[k++] = (Guchar)((outBuf << (8 - outBits)) +
+ (inBuf & ((1 << (8 - outBits)) - 1)));
+ }
+ }
+ }
+
+ // reset to start of line
+ predIdx = pixBytes;
+
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// FileStream
+//------------------------------------------------------------------------
+
+FileStream::FileStream(GooFile* fileA, Goffset startA, GBool limitedA,
+ Goffset lengthA, Object *dictA):
+ BaseStream(dictA, lengthA) {
+ file = fileA;
+ offset = start = startA;
+ limited = limitedA;
+ length = lengthA;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+ savePos = 0;
+ saved = gFalse;
+}
+
+FileStream::~FileStream() {
+ close();
+}
+
+BaseStream *FileStream::copy() {
+ return new FileStream(file, start, limited, length, &dict);
+}
+
+Stream *FileStream::makeSubStream(Goffset startA, GBool limitedA,
+ Goffset lengthA, Object *dictA) {
+ return new FileStream(file, startA, limitedA, lengthA, dictA);
+}
+
+void FileStream::reset() {
+ savePos = offset;
+ offset = start;
+ saved = gTrue;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+void FileStream::close() {
+ if (saved) {
+ offset = savePos;
+ saved = gFalse;
+ }
+}
+
+GBool FileStream::fillBuf() {
+ int n;
+
+ bufPos += bufEnd - buf;
+ bufPtr = bufEnd = buf;
+ if (limited && bufPos >= start + length) {
+ return gFalse;
+ }
+ if (limited && bufPos + fileStreamBufSize > start + length) {
+ n = start + length - bufPos;
+ } else {
+ n = fileStreamBufSize;
+ }
+ n = file->read(buf, n, offset);
+ if (n == -1) {
+ return gFalse;
+ }
+ offset += n;
+ bufEnd = buf + n;
+ if (bufPtr >= bufEnd) {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+void FileStream::setPos(Goffset pos, int dir) {
+ Goffset size;
+
+ if (dir >= 0) {
+ offset = bufPos = pos;
+ } else {
+ size = file->size();
+ if (pos > size)
+ pos = size;
+ offset = size - pos;
+ bufPos = offset;
+ }
+ bufPtr = bufEnd = buf;
+}
+
+void FileStream::moveStart(Goffset delta) {
+ start += delta;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+//------------------------------------------------------------------------
+// CachedFileStream
+//------------------------------------------------------------------------
+
+CachedFileStream::CachedFileStream(CachedFile *ccA, Goffset startA,
+ GBool limitedA, Goffset lengthA, Object *dictA)
+ : BaseStream(dictA, lengthA)
+{
+ cc = ccA;
+ start = startA;
+ limited = limitedA;
+ length = lengthA;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+ savePos = 0;
+ saved = gFalse;
+}
+
+CachedFileStream::~CachedFileStream()
+{
+ close();
+ cc->decRefCnt();
+}
+
+BaseStream *CachedFileStream::copy() {
+ cc->incRefCnt();
+ return new CachedFileStream(cc, start, limited, length, &dict);
+}
+
+Stream *CachedFileStream::makeSubStream(Goffset startA, GBool limitedA,
+ Goffset lengthA, Object *dictA)
+{
+ cc->incRefCnt();
+ return new CachedFileStream(cc, startA, limitedA, lengthA, dictA);
+}
+
+void CachedFileStream::reset()
+{
+ savePos = (Guint)cc->tell();
+ cc->seek(start, SEEK_SET);
+
+ saved = gTrue;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+void CachedFileStream::close()
+{
+ if (saved) {
+ cc->seek(savePos, SEEK_SET);
+ saved = gFalse;
+ }
+}
+
+GBool CachedFileStream::fillBuf()
+{
+ int n;
+
+ bufPos += bufEnd - buf;
+ bufPtr = bufEnd = buf;
+ if (limited && bufPos >= start + length) {
+ return gFalse;
+ }
+ if (limited && bufPos + cachedStreamBufSize > start + length) {
+ n = start + length - bufPos;
+ } else {
+ n = cachedStreamBufSize - (bufPos % cachedStreamBufSize);
+ }
+ n = cc->read(buf, 1, n);
+ bufEnd = buf + n;
+ if (bufPtr >= bufEnd) {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+void CachedFileStream::setPos(Goffset pos, int dir)
+{
+ Guint size;
+
+ if (dir >= 0) {
+ cc->seek(pos, SEEK_SET);
+ bufPos = pos;
+ } else {
+ cc->seek(0, SEEK_END);
+ size = (Guint)cc->tell();
+
+ if (pos > size)
+ pos = (Guint)size;
+
+ cc->seek(-(int)pos, SEEK_END);
+ bufPos = (Guint)cc->tell();
+ }
+
+ bufPtr = bufEnd = buf;
+}
+
+void CachedFileStream::moveStart(Goffset delta)
+{
+ start += delta;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+//------------------------------------------------------------------------
+// MemStream
+//------------------------------------------------------------------------
+
+MemStream::MemStream(char *bufA, Goffset startA, Goffset lengthA, Object *dictA):
+ BaseStream(dictA, lengthA) {
+ buf = bufA;
+ start = startA;
+ length = lengthA;
+ bufEnd = buf + start + length;
+ bufPtr = buf + start;
+ needFree = gFalse;
+}
+
+MemStream::~MemStream() {
+ if (needFree) {
+ gfree(buf);
+ }
+}
+
+BaseStream *MemStream::copy() {
+ return new MemStream(buf, start, length, &dict);
+}
+
+Stream *MemStream::makeSubStream(Goffset startA, GBool limited,
+ Goffset lengthA, Object *dictA) {
+ MemStream *subStr;
+ Goffset newLength;
+
+ if (!limited || startA + lengthA > start + length) {
+ newLength = start + length - startA;
+ } else {
+ newLength = lengthA;
+ }
+ subStr = new MemStream(buf, startA, newLength, dictA);
+ return subStr;
+}
+
+void MemStream::reset() {
+ bufPtr = buf + start;
+}
+
+void MemStream::close() {
+}
+
+int MemStream::getChars(int nChars, Guchar *buffer) {
+ int n;
+
+ if (nChars <= 0) {
+ return 0;
+ }
+ if (bufEnd - bufPtr < nChars) {
+ n = (int)(bufEnd - bufPtr);
+ } else {
+ n = nChars;
+ }
+ memcpy(buffer, bufPtr, n);
+ bufPtr += n;
+ return n;
+}
+
+void MemStream::setPos(Goffset pos, int dir) {
+ Guint i;
+
+ if (dir >= 0) {
+ i = pos;
+ } else {
+ i = start + length - pos;
+ }
+ if (i < start) {
+ i = start;
+ } else if (i > start + length) {
+ i = start + length;
+ }
+ bufPtr = buf + i;
+}
+
+void MemStream::moveStart(Goffset delta) {
+ start += delta;
+ length -= delta;
+ bufPtr = buf + start;
+}
+
+//------------------------------------------------------------------------
+// EmbedStream
+//------------------------------------------------------------------------
+
+EmbedStream::EmbedStream(Stream *strA, Object *dictA,
+ GBool limitedA, Goffset lengthA):
+ BaseStream(dictA, lengthA) {
+ str = strA;
+ limited = limitedA;
+ length = lengthA;
+}
+
+EmbedStream::~EmbedStream() {
+}
+
+BaseStream *EmbedStream::copy() {
+ error(errInternal, -1, "Called copy() on EmbedStream");
+ return NULL;
+}
+
+Stream *EmbedStream::makeSubStream(Goffset start, GBool limitedA,
+ Goffset lengthA, Object *dictA) {
+ error(errInternal, -1, "Called makeSubStream() on EmbedStream");
+ return NULL;
+}
+
+int EmbedStream::getChar() {
+ if (limited && !length) {
+ return EOF;
+ }
+ --length;
+ return str->getChar();
+}
+
+int EmbedStream::lookChar() {
+ if (limited && !length) {
+ return EOF;
+ }
+ return str->lookChar();
+}
+
+int EmbedStream::getChars(int nChars, Guchar *buffer) {
+ if (nChars <= 0) {
+ return 0;
+ }
+ if (limited && length < nChars) {
+ nChars = length;
+ }
+ return str->doGetChars(nChars, buffer);
+}
+
+void EmbedStream::setPos(Goffset pos, int dir) {
+ error(errInternal, -1, "Internal: called setPos() on EmbedStream");
+}
+
+Goffset EmbedStream::getStart() {
+ error(errInternal, -1, "Internal: called getStart() on EmbedStream");
+ return 0;
+}
+
+void EmbedStream::moveStart(Goffset delta) {
+ error(errInternal, -1, "Internal: called moveStart() on EmbedStream");
+}
+
+//------------------------------------------------------------------------
+// ASCIIHexStream
+//------------------------------------------------------------------------
+
+ASCIIHexStream::ASCIIHexStream(Stream *strA):
+ FilterStream(strA) {
+ buf = EOF;
+ eof = gFalse;
+}
+
+ASCIIHexStream::~ASCIIHexStream() {
+ delete str;
+}
+
+void ASCIIHexStream::reset() {
+ str->reset();
+ buf = EOF;
+ eof = gFalse;
+}
+
+int ASCIIHexStream::lookChar() {
+ int c1, c2, x;
+
+ if (buf != EOF)
+ return buf;
+ if (eof) {
+ buf = EOF;
+ return EOF;
+ }
+ do {
+ c1 = str->getChar();
+ } while (isspace(c1));
+ if (c1 == '>') {
+ eof = gTrue;
+ buf = EOF;
+ return buf;
+ }
+ do {
+ c2 = str->getChar();
+ } while (isspace(c2));
+ if (c2 == '>') {
+ eof = gTrue;
+ c2 = '0';
+ }
+ if (c1 >= '0' && c1 <= '9') {
+ x = (c1 - '0') << 4;
+ } else if (c1 >= 'A' && c1 <= 'F') {
+ x = (c1 - 'A' + 10) << 4;
+ } else if (c1 >= 'a' && c1 <= 'f') {
+ x = (c1 - 'a' + 10) << 4;
+ } else if (c1 == EOF) {
+ eof = gTrue;
+ x = 0;
+ } else {
+ error(errSyntaxError, getPos(),
+ "Illegal character <{0:02x}> in ASCIIHex stream", c1);
+ x = 0;
+ }
+ if (c2 >= '0' && c2 <= '9') {
+ x += c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ x += c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ x += c2 - 'a' + 10;
+ } else if (c2 == EOF) {
+ eof = gTrue;
+ x = 0;
+ } else {
+ error(errSyntaxError, getPos(),
+ "Illegal character <{0:02x}> in ASCIIHex stream", c2);
+ }
+ buf = x & 0xff;
+ return buf;
+}
+
+GooString *ASCIIHexStream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/ASCIIHexDecode filter\n");
+ return s;
+}
+
+GBool ASCIIHexStream::isBinary(GBool last) {
+ return str->isBinary(gFalse);
+}
+
+//------------------------------------------------------------------------
+// ASCII85Stream
+//------------------------------------------------------------------------
+
+ASCII85Stream::ASCII85Stream(Stream *strA):
+ FilterStream(strA) {
+ index = n = 0;
+ eof = gFalse;
+}
+
+ASCII85Stream::~ASCII85Stream() {
+ delete str;
+}
+
+void ASCII85Stream::reset() {
+ str->reset();
+ index = n = 0;
+ eof = gFalse;
+}
+
+int ASCII85Stream::lookChar() {
+ int k;
+ Gulong t;
+
+ if (index >= n) {
+ if (eof)
+ return EOF;
+ index = 0;
+ do {
+ c[0] = str->getChar();
+ } while (Lexer::isSpace(c[0]));
+ if (c[0] == '~' || c[0] == EOF) {
+ eof = gTrue;
+ n = 0;
+ return EOF;
+ } else if (c[0] == 'z') {
+ b[0] = b[1] = b[2] = b[3] = 0;
+ n = 4;
+ } else {
+ for (k = 1; k < 5; ++k) {
+ do {
+ c[k] = str->getChar();
+ } while (Lexer::isSpace(c[k]));
+ if (c[k] == '~' || c[k] == EOF)
+ break;
+ }
+ n = k - 1;
+ if (k < 5 && (c[k] == '~' || c[k] == EOF)) {
+ for (++k; k < 5; ++k)
+ c[k] = 0x21 + 84;
+ eof = gTrue;
+ }
+ t = 0;
+ for (k = 0; k < 5; ++k)
+ t = t * 85 + (c[k] - 0x21);
+ for (k = 3; k >= 0; --k) {
+ b[k] = (int)(t & 0xff);
+ t >>= 8;
+ }
+ }
+ }
+ return b[index];
+}
+
+GooString *ASCII85Stream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/ASCII85Decode filter\n");
+ return s;
+}
+
+GBool ASCII85Stream::isBinary(GBool last) {
+ return str->isBinary(gFalse);
+}
+
+//------------------------------------------------------------------------
+// LZWStream
+//------------------------------------------------------------------------
+
+LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
+ if (!pred->isOk()) {
+ delete pred;
+ pred = NULL;
+ }
+ } else {
+ pred = NULL;
+ }
+ early = earlyA;
+ eof = gFalse;
+ inputBits = 0;
+ clearTable();
+}
+
+LZWStream::~LZWStream() {
+ if (pred) {
+ delete pred;
+ }
+ delete str;
+}
+
+int LZWStream::getChar() {
+ if (pred) {
+ return pred->getChar();
+ }
+ if (eof) {
+ return EOF;
+ }
+ if (seqIndex >= seqLength) {
+ if (!processNextCode()) {
+ return EOF;
+ }
+ }
+ return seqBuf[seqIndex++];
+}
+
+int LZWStream::lookChar() {
+ if (pred) {
+ return pred->lookChar();
+ }
+ if (eof) {
+ return EOF;
+ }
+ if (seqIndex >= seqLength) {
+ if (!processNextCode()) {
+ return EOF;
+ }
+ }
+ return seqBuf[seqIndex];
+}
+
+void LZWStream::getRawChars(int nChars, int *buffer) {
+ for (int i = 0; i < nChars; ++i)
+ buffer[i] = doGetRawChar();
+}
+
+int LZWStream::getRawChar() {
+ return doGetRawChar();
+}
+
+int LZWStream::getChars(int nChars, Guchar *buffer) {
+ int n, m;
+
+ if (pred) {
+ return pred->getChars(nChars, buffer);
+ }
+ if (eof) {
+ return 0;
+ }
+ n = 0;
+ while (n < nChars) {
+ if (seqIndex >= seqLength) {
+ if (!processNextCode()) {
+ break;
+ }
+ }
+ m = seqLength - seqIndex;
+ if (m > nChars - n) {
+ m = nChars - n;
+ }
+ memcpy(buffer + n, seqBuf + seqIndex, m);
+ seqIndex += m;
+ n += m;
+ }
+ return n;
+}
+
+void LZWStream::reset() {
+ str->reset();
+ eof = gFalse;
+ inputBits = 0;
+ clearTable();
+}
+
+GBool LZWStream::processNextCode() {
+ int code;
+ int nextLength;
+ int i, j;
+
+ // check for EOF
+ if (eof) {
+ return gFalse;
+ }
+
+ // check for eod and clear-table codes
+ start:
+ code = getCode();
+ if (code == EOF || code == 257) {
+ eof = gTrue;
+ return gFalse;
+ }
+ if (code == 256) {
+ clearTable();
+ goto start;
+ }
+ if (nextCode >= 4097) {
+ error(errSyntaxError, getPos(),
+ "Bad LZW stream - expected clear-table code");
+ clearTable();
+ }
+
+ // process the next code
+ nextLength = seqLength + 1;
+ if (code < 256) {
+ seqBuf[0] = code;
+ seqLength = 1;
+ } else if (code < nextCode) {
+ seqLength = table[code].length;
+ for (i = seqLength - 1, j = code; i > 0; --i) {
+ seqBuf[i] = table[j].tail;
+ j = table[j].head;
+ }
+ seqBuf[0] = j;
+ } else if (code == nextCode) {
+ seqBuf[seqLength] = newChar;
+ ++seqLength;
+ } else {
+ error(errSyntaxError, getPos(), "Bad LZW stream - unexpected code");
+ eof = gTrue;
+ return gFalse;
+ }
+ newChar = seqBuf[0];
+ if (first) {
+ first = gFalse;
+ } else {
+ table[nextCode].length = nextLength;
+ table[nextCode].head = prevCode;
+ table[nextCode].tail = newChar;
+ ++nextCode;
+ if (nextCode + early == 512)
+ nextBits = 10;
+ else if (nextCode + early == 1024)
+ nextBits = 11;
+ else if (nextCode + early == 2048)
+ nextBits = 12;
+ }
+ prevCode = code;
+
+ // reset buffer
+ seqIndex = 0;
+
+ return gTrue;
+}
+
+void LZWStream::clearTable() {
+ nextCode = 258;
+ nextBits = 9;
+ seqIndex = seqLength = 0;
+ first = gTrue;
+}
+
+int LZWStream::getCode() {
+ int c;
+ int code;
+
+ while (inputBits < nextBits) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ inputBuf = (inputBuf << 8) | (c & 0xff);
+ inputBits += 8;
+ }
+ code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1);
+ inputBits -= nextBits;
+ return code;
+}
+
+GooString *LZWStream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+
+ if (psLevel < 2 || pred) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< ");
+ if (!early) {
+ s->append("/EarlyChange 0 ");
+ }
+ s->append(">> /LZWDecode filter\n");
+ return s;
+}
+
+GBool LZWStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// RunLengthStream
+//------------------------------------------------------------------------
+
+RunLengthStream::RunLengthStream(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+RunLengthStream::~RunLengthStream() {
+ delete str;
+}
+
+void RunLengthStream::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+int RunLengthStream::getChars(int nChars, Guchar *buffer) {
+ int n, m;
+
+ n = 0;
+ while (n < nChars) {
+ if (bufPtr >= bufEnd) {
+ if (!fillBuf()) {
+ break;
+ }
+ }
+ m = (int)(bufEnd - bufPtr);
+ if (m > nChars - n) {
+ m = nChars - n;
+ }
+ memcpy(buffer + n, bufPtr, m);
+ bufPtr += m;
+ n += m;
+ }
+ return n;
+}
+
+GooString *RunLengthStream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/RunLengthDecode filter\n");
+ return s;
+}
+
+GBool RunLengthStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+GBool RunLengthStream::fillBuf() {
+ int c;
+ int n, i;
+
+ if (eof)
+ return gFalse;
+ c = str->getChar();
+ if (c == 0x80 || c == EOF) {
+ eof = gTrue;
+ return gFalse;
+ }
+ if (c < 0x80) {
+ n = c + 1;
+ for (i = 0; i < n; ++i)
+ buf[i] = (char)str->getChar();
+ } else {
+ n = 0x101 - c;
+ c = str->getChar();
+ for (i = 0; i < n; ++i)
+ buf[i] = (char)c;
+ }
+ bufPtr = buf;
+ bufEnd = buf + n;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// CCITTFaxStream
+//------------------------------------------------------------------------
+
+CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA):
+ FilterStream(strA) {
+ encoding = encodingA;
+ endOfLine = endOfLineA;
+ byteAlign = byteAlignA;
+ columns = columnsA;
+ if (columns < 1) {
+ columns = 1;
+ } else if (columns > INT_MAX - 2) {
+ columns = INT_MAX - 2;
+ }
+ rows = rowsA;
+ endOfBlock = endOfBlockA;
+ black = blackA;
+ // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = columns
+ // ---> max codingLine size = columns + 1
+ // refLine has one extra guard entry at the end
+ // ---> max refLine size = columns + 2
+ codingLine = (int *)gmallocn_checkoverflow(columns + 1, sizeof(int));
+ refLine = (int *)gmallocn_checkoverflow(columns + 2, sizeof(int));
+
+ if (codingLine != NULL && refLine != NULL) {
+ eof = gFalse;
+ codingLine[0] = columns;
+ } else {
+ eof = gTrue;
+ }
+ row = 0;
+ nextLine2D = encoding < 0;
+ inputBits = 0;
+ a0i = 0;
+ outputBits = 0;
+
+ buf = EOF;
+}
+
+CCITTFaxStream::~CCITTFaxStream() {
+ delete str;
+ gfree(refLine);
+ gfree(codingLine);
+}
+
+void CCITTFaxStream::ccittReset(GBool unfiltered) {
+ if (unfiltered)
+ str->unfilteredReset();
+ else
+ str->reset();
+
+ row = 0;
+ nextLine2D = encoding < 0;
+ inputBits = 0;
+ a0i = 0;
+ outputBits = 0;
+ buf = EOF;
+}
+
+void CCITTFaxStream::unfilteredReset() {
+ ccittReset(gTrue);
+}
+
+void CCITTFaxStream::reset() {
+ int code1;
+
+ ccittReset(gFalse);
+
+ if (codingLine != NULL && refLine != NULL) {
+ eof = gFalse;
+ codingLine[0] = columns;
+ } else {
+ eof = gTrue;
+ }
+
+ // skip any initial zero bits and end-of-line marker, and get the 2D
+ // encoding tag
+ while ((code1 = lookBits(12)) == 0) {
+ eatBits(1);
+ }
+ if (code1 == 0x001) {
+ eatBits(12);
+ endOfLine = gTrue;
+ }
+ if (encoding > 0) {
+ nextLine2D = !lookBits(1);
+ eatBits(1);
+ }
+}
+
+inline void CCITTFaxStream::addPixels(int a1, int blackPixels) {
+ if (a1 > codingLine[a0i]) {
+ if (a1 > columns) {
+ error(errSyntaxError, getPos(),
+ "CCITTFax row is wrong length ({0:d})", a1);
+ err = gTrue;
+ a1 = columns;
+ }
+ if ((a0i & 1) ^ blackPixels) {
+ ++a0i;
+ }
+ codingLine[a0i] = a1;
+ }
+}
+
+inline void CCITTFaxStream::addPixelsNeg(int a1, int blackPixels) {
+ if (a1 > codingLine[a0i]) {
+ if (a1 > columns) {
+ error(errSyntaxError, getPos(),
+ "CCITTFax row is wrong length ({0:d})", a1);
+ err = gTrue;
+ a1 = columns;
+ }
+ if ((a0i & 1) ^ blackPixels) {
+ ++a0i;
+ }
+ codingLine[a0i] = a1;
+ } else if (a1 < codingLine[a0i]) {
+ if (a1 < 0) {
+ error(errSyntaxError, getPos(), "Invalid CCITTFax code");
+ err = gTrue;
+ a1 = 0;
+ }
+ while (a0i > 0 && a1 <= codingLine[a0i - 1]) {
+ --a0i;
+ }
+ codingLine[a0i] = a1;
+ }
+}
+
+int CCITTFaxStream::lookChar() {
+ int code1, code2, code3;
+ int b1i, blackPixels, i, bits;
+ GBool gotEOL;
+
+ if (buf != EOF) {
+ return buf;
+ }
+
+ // read the next row
+ if (outputBits == 0) {
+
+ // if at eof just return EOF
+ if (eof) {
+ return EOF;
+ }
+
+ err = gFalse;
+
+ // 2-D encoding
+ if (nextLine2D) {
+ for (i = 0; i < columns && codingLine[i] < columns; ++i) {
+ refLine[i] = codingLine[i];
+ }
+ for (; i < columns + 2; ++i) {
+ refLine[i] = columns;
+ }
+ codingLine[0] = 0;
+ a0i = 0;
+ b1i = 0;
+ blackPixels = 0;
+ // invariant:
+ // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1]
+ // <= columns
+ // exception at left edge:
+ // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible
+ // exception at right edge:
+ // refLine[b1i] = refLine[b1i+1] = columns is possible
+ while (codingLine[a0i] < columns && !err) {
+ code1 = getTwoDimCode();
+ switch (code1) {
+ case twoDimPass:
+ if (likely(b1i + 1 < columns + 2)) {
+ addPixels(refLine[b1i + 1], blackPixels);
+ if (refLine[b1i + 1] < columns) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimHoriz:
+ code1 = code2 = 0;
+ if (blackPixels) {
+ do {
+ code1 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ } else {
+ do {
+ code1 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ }
+ addPixels(codingLine[a0i] + code1, blackPixels);
+ if (codingLine[a0i] < columns) {
+ addPixels(codingLine[a0i] + code2, blackPixels ^ 1);
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ }
+ break;
+ case twoDimVertR3:
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ addPixels(refLine[b1i] + 3, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ }
+ }
+ break;
+ case twoDimVertR2:
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ addPixels(refLine[b1i] + 2, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ }
+ }
+ break;
+ case twoDimVertR1:
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ addPixels(refLine[b1i] + 1, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ }
+ }
+ break;
+ case twoDimVert0:
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ addPixels(refLine[b1i], blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ }
+ }
+ break;
+ case twoDimVertL3:
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ addPixelsNeg(refLine[b1i] - 3, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ }
+ }
+ break;
+ case twoDimVertL2:
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ addPixelsNeg(refLine[b1i] - 2, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ }
+ }
+ break;
+ case twoDimVertL1:
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ addPixelsNeg(refLine[b1i] - 1, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ if (unlikely(b1i > columns + 1)) {
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ err = gTrue;
+ break;
+ }
+ }
+ }
+ break;
+ case EOF:
+ addPixels(columns, 0);
+ eof = gTrue;
+ break;
+ default:
+ error(errSyntaxError, getPos(),
+ "Bad 2D code {0:04x} in CCITTFax stream", code1);
+ addPixels(columns, 0);
+ err = gTrue;
+ break;
+ }
+ }
+
+ // 1-D encoding
+ } else {
+ codingLine[0] = 0;
+ a0i = 0;
+ blackPixels = 0;
+ while (codingLine[a0i] < columns) {
+ code1 = 0;
+ if (blackPixels) {
+ do {
+ code1 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ } else {
+ do {
+ code1 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ }
+ addPixels(codingLine[a0i] + code1, blackPixels);
+ blackPixels ^= 1;
+ }
+ }
+
+ // check for end-of-line marker, skipping over any extra zero bits
+ // (if EncodedByteAlign is true and EndOfLine is false, there can
+ // be "false" EOL markers -- i.e., if the last n unused bits in
+ // row i are set to zero, and the first 11-n bits in row i+1
+ // happen to be zero -- so we don't look for EOL markers in this
+ // case)
+ gotEOL = gFalse;
+ if (!endOfBlock && row == rows - 1) {
+ eof = gTrue;
+ } else if (endOfLine || !byteAlign) {
+ code1 = lookBits(12);
+ if (endOfLine) {
+ while (code1 != EOF && code1 != 0x001) {
+ eatBits(1);
+ code1 = lookBits(12);
+ }
+ } else {
+ while (code1 == 0) {
+ eatBits(1);
+ code1 = lookBits(12);
+ }
+ }
+ if (code1 == 0x001) {
+ eatBits(12);
+ gotEOL = gTrue;
+ }
+ }
+
+ // byte-align the row
+ // (Adobe apparently doesn't do byte alignment after EOL markers
+ // -- I've seen CCITT image data streams in two different formats,
+ // both with the byteAlign flag set:
+ // 1. xx:x0:01:yy:yy
+ // 2. xx:00:1y:yy:yy
+ // where xx is the previous line, yy is the next line, and colons
+ // separate bytes.)
+ if (byteAlign && !gotEOL) {
+ inputBits &= ~7;
+ }
+
+ // check for end of stream
+ if (lookBits(1) == EOF) {
+ eof = gTrue;
+ }
+
+ // get 2D encoding tag
+ if (!eof && encoding > 0) {
+ nextLine2D = !lookBits(1);
+ eatBits(1);
+ }
+
+ // check for end-of-block marker
+ if (endOfBlock && !endOfLine && byteAlign) {
+ // in this case, we didn't check for an EOL code above, so we
+ // need to check here
+ code1 = lookBits(24);
+ if (code1 == 0x001001) {
+ eatBits(12);
+ gotEOL = gTrue;
+ }
+ }
+ if (endOfBlock && gotEOL) {
+ code1 = lookBits(12);
+ if (code1 == 0x001) {
+ eatBits(12);
+ if (encoding > 0) {
+ lookBits(1);
+ eatBits(1);
+ }
+ if (encoding >= 0) {
+ for (i = 0; i < 4; ++i) {
+ code1 = lookBits(12);
+ if (code1 != 0x001) {
+ error(errSyntaxError, getPos(),
+ "Bad RTC code in CCITTFax stream");
+ }
+ eatBits(12);
+ if (encoding > 0) {
+ lookBits(1);
+ eatBits(1);
+ }
+ }
+ }
+ eof = gTrue;
+ }
+
+ // look for an end-of-line marker after an error -- we only do
+ // this if we know the stream contains end-of-line markers because
+ // the "just plow on" technique tends to work better otherwise
+ } else if (err && endOfLine) {
+ while (1) {
+ code1 = lookBits(13);
+ if (code1 == EOF) {
+ eof = gTrue;
+ return EOF;
+ }
+ if ((code1 >> 1) == 0x001) {
+ break;
+ }
+ eatBits(1);
+ }
+ eatBits(12);
+ if (encoding > 0) {
+ eatBits(1);
+ nextLine2D = !(code1 & 1);
+ }
+ }
+
+ // set up for output
+ if (codingLine[0] > 0) {
+ outputBits = codingLine[a0i = 0];
+ } else {
+ outputBits = codingLine[a0i = 1];
+ }
+
+ ++row;
+ }
+
+ // get a byte
+ if (outputBits >= 8) {
+ buf = (a0i & 1) ? 0x00 : 0xff;
+ outputBits -= 8;
+ if (outputBits == 0 && codingLine[a0i] < columns) {
+ ++a0i;
+ outputBits = codingLine[a0i] - codingLine[a0i - 1];
+ }
+ } else {
+ bits = 8;
+ buf = 0;
+ do {
+ if (outputBits > bits) {
+ buf <<= bits;
+ if (!(a0i & 1)) {
+ buf |= 0xff >> (8 - bits);
+ }
+ outputBits -= bits;
+ bits = 0;
+ } else {
+ buf <<= outputBits;
+ if (!(a0i & 1)) {
+ buf |= 0xff >> (8 - outputBits);
+ }
+ bits -= outputBits;
+ outputBits = 0;
+ if (codingLine[a0i] < columns) {
+ ++a0i;
+ if (unlikely(a0i > columns)) {
+ error(errSyntaxError, getPos(),
+ "Bad bits {0:04x} in CCITTFax stream", bits);
+ err = gTrue;
+ break;
+ }
+ outputBits = codingLine[a0i] - codingLine[a0i - 1];
+ } else if (bits > 0) {
+ buf <<= bits;
+ bits = 0;
+ }
+ }
+ } while (bits);
+ }
+ if (black) {
+ buf ^= 0xff;
+ }
+ return buf;
+}
+
+short CCITTFaxStream::getTwoDimCode() {
+ int code;
+ const CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ if ((code = lookBits(7)) != EOF) {
+ p = &twoDimTab1[code];
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ }
+ } else {
+ for (n = 1; n <= 7; ++n) {
+ if ((code = lookBits(n)) == EOF) {
+ break;
+ }
+ if (n < 7) {
+ code <<= 7 - n;
+ }
+ p = &twoDimTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(errSyntaxError, getPos(),
+ "Bad two dim code ({0:04x}) in CCITTFax stream", code);
+ return EOF;
+}
+
+short CCITTFaxStream::getWhiteCode() {
+ short code;
+ const CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ code = lookBits(12);
+ if (code == EOF) {
+ return 1;
+ }
+ if ((code >> 5) == 0) {
+ p = &whiteTab1[code];
+ } else {
+ p = &whiteTab2[code >> 3];
+ }
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ } else {
+ for (n = 1; n <= 9; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 9) {
+ code <<= 9 - n;
+ }
+ p = &whiteTab2[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ for (n = 11; n <= 12; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 12) {
+ code <<= 12 - n;
+ }
+ p = &whiteTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(errSyntaxError, getPos(),
+ "Bad white code ({0:04x}) in CCITTFax stream", code);
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ eatBits(1);
+ return 1;
+}
+
+short CCITTFaxStream::getBlackCode() {
+ short code;
+ const CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ code = lookBits(13);
+ if (code == EOF) {
+ return 1;
+ }
+ if ((code >> 7) == 0) {
+ p = &blackTab1[code];
+ } else if ((code >> 9) == 0 && (code >> 7) != 0) {
+ p = &blackTab2[(code >> 1) - 64];
+ } else {
+ p = &blackTab3[code >> 7];
+ }
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ } else {
+ for (n = 2; n <= 6; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 6) {
+ code <<= 6 - n;
+ }
+ p = &blackTab3[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ for (n = 7; n <= 12; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 12) {
+ code <<= 12 - n;
+ }
+ if (code >= 64) {
+ p = &blackTab2[code - 64];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ for (n = 10; n <= 13; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 13) {
+ code <<= 13 - n;
+ }
+ p = &blackTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(errSyntaxError, getPos(),
+ "Bad black code ({0:04x}) in CCITTFax stream", code);
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ eatBits(1);
+ return 1;
+}
+
+short CCITTFaxStream::lookBits(int n) {
+ int c;
+
+ while (inputBits < n) {
+ if ((c = str->getChar()) == EOF) {
+ if (inputBits == 0) {
+ return EOF;
+ }
+ // near the end of the stream, the caller may ask for more bits
+ // than are available, but there may still be a valid code in
+ // however many bits are available -- we need to return correct
+ // data in this case
+ return (inputBuf << (n - inputBits)) & (0xffffffff >> (32 - n));
+ }
+ inputBuf = (inputBuf << 8) + c;
+ inputBits += 8;
+ }
+ return (inputBuf >> (inputBits - n)) & (0xffffffff >> (32 - n));
+}
+
+GooString *CCITTFaxStream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+ char s1[50];
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< ");
+ if (encoding != 0) {
+ sprintf(s1, "/K %d ", encoding);
+ s->append(s1);
+ }
+ if (endOfLine) {
+ s->append("/EndOfLine true ");
+ }
+ if (byteAlign) {
+ s->append("/EncodedByteAlign true ");
+ }
+ sprintf(s1, "/Columns %d ", columns);
+ s->append(s1);
+ if (rows != 0) {
+ sprintf(s1, "/Rows %d ", rows);
+ s->append(s1);
+ }
+ if (!endOfBlock) {
+ s->append("/EndOfBlock false ");
+ }
+ if (black) {
+ s->append("/BlackIs1 true ");
+ }
+ s->append(">> /CCITTFaxDecode filter\n");
+ return s;
+}
+
+GBool CCITTFaxStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+#ifndef ENABLE_LIBJPEG
+
+//------------------------------------------------------------------------
+// DCTStream
+//------------------------------------------------------------------------
+
+// IDCT constants (20.12 fixed point format)
+#define dctCos1 4017 // cos(pi/16)
+#define dctSin1 799 // sin(pi/16)
+#define dctCos3 3406 // cos(3*pi/16)
+#define dctSin3 2276 // sin(3*pi/16)
+#define dctCos6 1567 // cos(6*pi/16)
+#define dctSin6 3784 // sin(6*pi/16)
+#define dctSqrt2 5793 // sqrt(2)
+#define dctSqrt1d2 2896 // sqrt(2) / 2
+
+// color conversion parameters (16.16 fixed point format)
+#define dctCrToR 91881 // 1.4020
+#define dctCbToG -22553 // -0.3441363
+#define dctCrToG -46802 // -0.71413636
+#define dctCbToB 116130 // 1.772
+
+// clip [-256,511] --> [0,255]
+#define dctClipOffset 256
+#define dctClipLength 768
+static Guchar dctClip[dctClipLength];
+static int dctClipInit = 0;
+
+// zig zag decode map
+static const int dctZigZag[64] = {
+ 0,
+ 1, 8,
+ 16, 9, 2,
+ 3, 10, 17, 24,
+ 32, 25, 18, 11, 4,
+ 5, 12, 19, 26, 33, 40,
+ 48, 41, 34, 27, 20, 13, 6,
+ 7, 14, 21, 28, 35, 42, 49, 56,
+ 57, 50, 43, 36, 29, 22, 15,
+ 23, 30, 37, 44, 51, 58,
+ 59, 52, 45, 38, 31,
+ 39, 46, 53, 60,
+ 61, 54, 47,
+ 55, 62,
+ 63
+};
+
+DCTStream::DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion):
+ FilterStream(strA) {
+ int i, j;
+
+ colorXform = colorXformA;
+ progressive = interleaved = gFalse;
+ width = height = 0;
+ mcuWidth = mcuHeight = 0;
+ numComps = 0;
+ comp = 0;
+ x = y = dy = 0;
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 32; ++j) {
+ rowBuf[i][j] = NULL;
+ }
+ frameBuf[i] = NULL;
+ }
+
+ if (!dctClipInit) {
+ for (i = -256; i < 0; ++i)
+ dctClip[dctClipOffset + i] = 0;
+ for (i = 0; i < 256; ++i)
+ dctClip[dctClipOffset + i] = i;
+ for (i = 256; i < 512; ++i)
+ dctClip[dctClipOffset + i] = 255;
+ dctClipInit = 1;
+ }
+}
+
+DCTStream::~DCTStream() {
+ close();
+ delete str;
+}
+
+void DCTStream::dctReset(GBool unfiltered) {
+ if (unfiltered)
+ str->unfilteredReset();
+ else
+ str->reset();
+
+ progressive = interleaved = gFalse;
+ width = height = 0;
+ numComps = 0;
+ numQuantTables = 0;
+ numDCHuffTables = 0;
+ numACHuffTables = 0;
+ gotJFIFMarker = gFalse;
+ gotAdobeMarker = gFalse;
+ restartInterval = 0;
+}
+
+void DCTStream::unfilteredReset() {
+ dctReset(gTrue);
+}
+
+void DCTStream::reset() {
+ int i, j;
+
+ dctReset(gFalse);
+
+ if (!readHeader()) {
+ y = height;
+ return;
+ }
+
+ // compute MCU size
+ if (numComps == 1) {
+ compInfo[0].hSample = compInfo[0].vSample = 1;
+ }
+ mcuWidth = compInfo[0].hSample;
+ mcuHeight = compInfo[0].vSample;
+ for (i = 1; i < numComps; ++i) {
+ if (compInfo[i].hSample > mcuWidth) {
+ mcuWidth = compInfo[i].hSample;
+ }
+ if (compInfo[i].vSample > mcuHeight) {
+ mcuHeight = compInfo[i].vSample;
+ }
+ }
+ mcuWidth *= 8;
+ mcuHeight *= 8;
+
+ // figure out color transform
+ if (colorXform == -1) {
+ if (numComps == 3) {
+ if (gotJFIFMarker) {
+ colorXform = 1;
+ } else if (compInfo[0].id == 82 && compInfo[1].id == 71 &&
+ compInfo[2].id == 66) { // ASCII "RGB"
+ colorXform = 0;
+ } else {
+ colorXform = 1;
+ }
+ } else {
+ colorXform = 0;
+ }
+ }
+
+ if (progressive || !interleaved) {
+
+ // allocate a buffer for the whole image
+ bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth;
+ bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight;
+ if (bufWidth <= 0 || bufHeight <= 0 ||
+ bufWidth > INT_MAX / bufWidth / (int)sizeof(int)) {
+ error(errSyntaxError, getPos(), "Invalid image size in DCT stream");
+ y = height;
+ return;
+ }
+ for (i = 0; i < numComps; ++i) {
+ frameBuf[i] = (int *)gmallocn(bufWidth * bufHeight, sizeof(int));
+ memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int));
+ }
+
+ // read the image data
+ do {
+ restartMarker = 0xd0;
+ restart();
+ readScan();
+ } while (readHeader());
+
+ // decode
+ decodeImage();
+
+ // initialize counters
+ comp = 0;
+ x = 0;
+ y = 0;
+
+ } else {
+
+ // allocate a buffer for one row of MCUs
+ bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth;
+ for (i = 0; i < numComps; ++i) {
+ for (j = 0; j < mcuHeight; ++j) {
+ rowBuf[i][j] = (Guchar *)gmallocn(bufWidth, sizeof(Guchar));
+ }
+ }
+
+ // initialize counters
+ comp = 0;
+ x = 0;
+ y = 0;
+ dy = mcuHeight;
+
+ restartMarker = 0xd0;
+ restart();
+ }
+}
+
+void DCTStream::close() {
+ int i, j;
+
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 32; ++j) {
+ gfree(rowBuf[i][j]);
+ rowBuf[i][j] = NULL;
+ }
+ gfree(frameBuf[i]);
+ frameBuf[i] = NULL;
+ }
+ FilterStream::close();
+}
+
+int DCTStream::getChar() {
+ int c;
+
+ if (y >= height) {
+ return EOF;
+ }
+ if (progressive || !interleaved) {
+ c = frameBuf[comp][y * bufWidth + x];
+ if (++comp == numComps) {
+ comp = 0;
+ if (++x == width) {
+ x = 0;
+ ++y;
+ }
+ }
+ } else {
+ if (dy >= mcuHeight) {
+ if (!readMCURow()) {
+ y = height;
+ return EOF;
+ }
+ comp = 0;
+ x = 0;
+ dy = 0;
+ }
+ c = rowBuf[comp][dy][x];
+ if (++comp == numComps) {
+ comp = 0;
+ if (++x == width) {
+ x = 0;
+ ++y;
+ ++dy;
+ if (y == height) {
+ readTrailer();
+ }
+ }
+ }
+ }
+ return c;
+}
+
+int DCTStream::lookChar() {
+ if (y >= height) {
+ return EOF;
+ }
+ if (progressive || !interleaved) {
+ return frameBuf[comp][y * bufWidth + x];
+ } else {
+ if (dy >= mcuHeight) {
+ if (!readMCURow()) {
+ y = height;
+ return EOF;
+ }
+ comp = 0;
+ x = 0;
+ dy = 0;
+ }
+ return rowBuf[comp][dy][x];
+ }
+}
+
+void DCTStream::restart() {
+ int i;
+
+ inputBits = 0;
+ restartCtr = restartInterval;
+ for (i = 0; i < numComps; ++i) {
+ compInfo[i].prevDC = 0;
+ }
+ eobRun = 0;
+}
+
+// Read one row of MCUs from a sequential JPEG stream.
+GBool DCTStream::readMCURow() {
+ int data1[64];
+ Guchar data2[64];
+ Guchar *p1, *p2;
+ int pY, pCb, pCr, pR, pG, pB;
+ int h, v, horiz, vert, hSub, vSub;
+ int x1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i;
+ int c;
+
+ for (x1 = 0; x1 < width; x1 += mcuWidth) {
+
+ // deal with restart marker
+ if (restartInterval > 0 && restartCtr == 0) {
+ c = readMarker();
+ if (c != restartMarker) {
+ error(errSyntaxError, getPos(),
+ "Bad DCT data: incorrect restart marker");
+ return gFalse;
+ }
+ if (++restartMarker == 0xd8)
+ restartMarker = 0xd0;
+ restart();
+ }
+
+ // read one MCU
+ for (cc = 0; cc < numComps; ++cc) {
+ h = compInfo[cc].hSample;
+ v = compInfo[cc].vSample;
+ horiz = mcuWidth / h;
+ vert = mcuHeight / v;
+ hSub = horiz / 8;
+ vSub = vert / 8;
+ for (y2 = 0; y2 < mcuHeight; y2 += vert) {
+ for (x2 = 0; x2 < mcuWidth; x2 += horiz) {
+ if (unlikely(scanInfo.dcHuffTable[cc] >= 4) || unlikely(scanInfo.acHuffTable[cc] >= 4)) {
+ return gFalse;
+ }
+ if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]],
+ &acHuffTables[scanInfo.acHuffTable[cc]],
+ &compInfo[cc].prevDC,
+ data1)) {
+ return gFalse;
+ }
+ transformDataUnit(quantTables[compInfo[cc].quantTable],
+ data1, data2);
+ if (hSub == 1 && vSub == 1) {
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ p1 = &rowBuf[cc][y2+y3][x1+x2];
+ p1[0] = data2[i];
+ p1[1] = data2[i+1];
+ p1[2] = data2[i+2];
+ p1[3] = data2[i+3];
+ p1[4] = data2[i+4];
+ p1[5] = data2[i+5];
+ p1[6] = data2[i+6];
+ p1[7] = data2[i+7];
+ }
+ } else if (hSub == 2 && vSub == 2) {
+ for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) {
+ p1 = &rowBuf[cc][y2+y3][x1+x2];
+ p2 = &rowBuf[cc][y2+y3+1][x1+x2];
+ p1[0] = p1[1] = p2[0] = p2[1] = data2[i];
+ p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1];
+ p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2];
+ p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3];
+ p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4];
+ p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5];
+ p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6];
+ p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7];
+ }
+ } else {
+ i = 0;
+ for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) {
+ for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) {
+ for (y5 = 0; y5 < vSub; ++y5)
+ for (x5 = 0; x5 < hSub; ++x5)
+ rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i];
+ ++i;
+ }
+ }
+ }
+ }
+ }
+ }
+ --restartCtr;
+
+ // color space conversion
+ if (colorXform) {
+ // convert YCbCr to RGB
+ if (numComps == 3) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = rowBuf[0][y2][x1+x2];
+ pCb = rowBuf[1][y2][x1+x2] - 128;
+ pCr = rowBuf[2][y2][x1+x2] - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ rowBuf[0][y2][x1+x2] = dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16;
+ rowBuf[1][y2][x1+x2] = dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB];
+ }
+ }
+ // convert YCbCrK to CMYK (K is passed through unchanged)
+ } else if (numComps == 4) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = rowBuf[0][y2][x1+x2];
+ pCb = rowBuf[1][y2][x1+x2] - 128;
+ pCr = rowBuf[2][y2][x1+x2] - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16;
+ rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB];
+ }
+ }
+ }
+ }
+ }
+ return gTrue;
+}
+
+// Read one scan from a progressive or non-interleaved JPEG stream.
+void DCTStream::readScan() {
+ int data[64];
+ int x1, y1, dx1, dy1, x2, y2, y3, cc, i;
+ int h, v, horiz, vert, vSub;
+ int *p1;
+ int c;
+
+ if (scanInfo.numComps == 1) {
+ for (cc = 0; cc < numComps; ++cc) {
+ if (scanInfo.comp[cc]) {
+ break;
+ }
+ }
+ dx1 = mcuWidth / compInfo[cc].hSample;
+ dy1 = mcuHeight / compInfo[cc].vSample;
+ } else {
+ dx1 = mcuWidth;
+ dy1 = mcuHeight;
+ }
+
+ for (y1 = 0; y1 < height; y1 += dy1) {
+ for (x1 = 0; x1 < width; x1 += dx1) {
+
+ // deal with restart marker
+ if (restartInterval > 0 && restartCtr == 0) {
+ c = readMarker();
+ if (c != restartMarker) {
+ error(errSyntaxError, getPos(),
+ "Bad DCT data: incorrect restart marker");
+ return;
+ }
+ if (++restartMarker == 0xd8) {
+ restartMarker = 0xd0;
+ }
+ restart();
+ }
+
+ // read one MCU
+ for (cc = 0; cc < numComps; ++cc) {
+ if (!scanInfo.comp[cc]) {
+ continue;
+ }
+
+ h = compInfo[cc].hSample;
+ v = compInfo[cc].vSample;
+ horiz = mcuWidth / h;
+ vert = mcuHeight / v;
+ vSub = vert / 8;
+ for (y2 = 0; y2 < dy1; y2 += vert) {
+ for (x2 = 0; x2 < dx1; x2 += horiz) {
+
+ // pull out the current values
+ p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ data[i] = p1[0];
+ data[i+1] = p1[1];
+ data[i+2] = p1[2];
+ data[i+3] = p1[3];
+ data[i+4] = p1[4];
+ data[i+5] = p1[5];
+ data[i+6] = p1[6];
+ data[i+7] = p1[7];
+ p1 += bufWidth * vSub;
+ }
+
+ // read one data unit
+ if (progressive) {
+ if (!readProgressiveDataUnit(
+ &dcHuffTables[scanInfo.dcHuffTable[cc]],
+ &acHuffTables[scanInfo.acHuffTable[cc]],
+ &compInfo[cc].prevDC,
+ data)) {
+ return;
+ }
+ } else {
+ if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]],
+ &acHuffTables[scanInfo.acHuffTable[cc]],
+ &compInfo[cc].prevDC,
+ data)) {
+ return;
+ }
+ }
+
+ // add the data unit into frameBuf
+ p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ p1[0] = data[i];
+ p1[1] = data[i+1];
+ p1[2] = data[i+2];
+ p1[3] = data[i+3];
+ p1[4] = data[i+4];
+ p1[5] = data[i+5];
+ p1[6] = data[i+6];
+ p1[7] = data[i+7];
+ p1 += bufWidth * vSub;
+ }
+ }
+ }
+ }
+ --restartCtr;
+ }
+ }
+}
+
+// Read one data unit from a sequential JPEG stream.
+GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ int *prevDC, int data[64]) {
+ int run, size, amp;
+ int c;
+ int i, j;
+
+ if ((size = readHuffSym(dcHuffTable)) == 9999) {
+ return gFalse;
+ }
+ if (size > 0) {
+ if ((amp = readAmp(size)) == 9999) {
+ return gFalse;
+ }
+ } else {
+ amp = 0;
+ }
+ data[0] = *prevDC += amp;
+ for (i = 1; i < 64; ++i) {
+ data[i] = 0;
+ }
+ i = 1;
+ while (i < 64) {
+ run = 0;
+ while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) {
+ run += 0x10;
+ }
+ if (c == 9999) {
+ return gFalse;
+ }
+ if (c == 0x00) {
+ break;
+ } else {
+ run += (c >> 4) & 0x0f;
+ size = c & 0x0f;
+ amp = readAmp(size);
+ if (amp == 9999) {
+ return gFalse;
+ }
+ i += run;
+ if (i < 64) {
+ j = dctZigZag[i++];
+ data[j] = amp;
+ }
+ }
+ }
+ return gTrue;
+}
+
+// Read one data unit from a sequential JPEG stream.
+GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ int *prevDC, int data[64]) {
+ int run, size, amp, bit, c;
+ int i, j, k;
+
+ // get the DC coefficient
+ i = scanInfo.firstCoeff;
+ if (i == 0) {
+ if (scanInfo.ah == 0) {
+ if ((size = readHuffSym(dcHuffTable)) == 9999) {
+ return gFalse;
+ }
+ if (size > 0) {
+ if ((amp = readAmp(size)) == 9999) {
+ return gFalse;
+ }
+ } else {
+ amp = 0;
+ }
+ data[0] += (*prevDC += amp) << scanInfo.al;
+ } else {
+ if ((bit = readBit()) == 9999) {
+ return gFalse;
+ }
+ data[0] += bit << scanInfo.al;
+ }
+ ++i;
+ }
+ if (scanInfo.lastCoeff == 0) {
+ return gTrue;
+ }
+
+ // check for an EOB run
+ if (eobRun > 0) {
+ while (i <= scanInfo.lastCoeff) {
+ j = dctZigZag[i++];
+ if (data[j] != 0) {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ if (bit) {
+ data[j] += 1 << scanInfo.al;
+ }
+ }
+ }
+ --eobRun;
+ return gTrue;
+ }
+
+ // read the AC coefficients
+ while (i <= scanInfo.lastCoeff) {
+ if ((c = readHuffSym(acHuffTable)) == 9999) {
+ return gFalse;
+ }
+
+ // ZRL
+ if (c == 0xf0) {
+ k = 0;
+ while (k < 16 && i <= scanInfo.lastCoeff) {
+ j = dctZigZag[i++];
+ if (data[j] == 0) {
+ ++k;
+ } else {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ if (bit) {
+ data[j] += 1 << scanInfo.al;
+ }
+ }
+ }
+
+ // EOB run
+ } else if ((c & 0x0f) == 0x00) {
+ j = c >> 4;
+ eobRun = 0;
+ for (k = 0; k < j; ++k) {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ eobRun = (eobRun << 1) | bit;
+ }
+ eobRun += 1 << j;
+ while (i <= scanInfo.lastCoeff) {
+ j = dctZigZag[i++];
+ if (data[j] != 0) {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ if (bit) {
+ data[j] += 1 << scanInfo.al;
+ }
+ }
+ }
+ --eobRun;
+ break;
+
+ // zero run and one AC coefficient
+ } else {
+ run = (c >> 4) & 0x0f;
+ size = c & 0x0f;
+ if ((amp = readAmp(size)) == 9999) {
+ return gFalse;
+ }
+ j = 0; // make gcc happy
+ for (k = 0; k <= run && i <= scanInfo.lastCoeff; ++k) {
+ j = dctZigZag[i++];
+ while (data[j] != 0 && i <= scanInfo.lastCoeff) {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ if (bit) {
+ data[j] += 1 << scanInfo.al;
+ }
+ j = dctZigZag[i++];
+ }
+ }
+ data[j] = amp << scanInfo.al;
+ }
+ }
+
+ return gTrue;
+}
+
+// Decode a progressive JPEG image.
+void DCTStream::decodeImage() {
+ int dataIn[64];
+ Guchar dataOut[64];
+ Gushort *quantTable;
+ int pY, pCb, pCr, pR, pG, pB;
+ int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i;
+ int h, v, horiz, vert, hSub, vSub;
+ int *p0, *p1, *p2;
+
+ for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) {
+ for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) {
+ for (cc = 0; cc < numComps; ++cc) {
+ quantTable = quantTables[compInfo[cc].quantTable];
+ h = compInfo[cc].hSample;
+ v = compInfo[cc].vSample;
+ horiz = mcuWidth / h;
+ vert = mcuHeight / v;
+ hSub = horiz / 8;
+ vSub = vert / 8;
+ for (y2 = 0; y2 < mcuHeight; y2 += vert) {
+ for (x2 = 0; x2 < mcuWidth; x2 += horiz) {
+
+ // pull out the coded data unit
+ p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ dataIn[i] = p1[0];
+ dataIn[i+1] = p1[1];
+ dataIn[i+2] = p1[2];
+ dataIn[i+3] = p1[3];
+ dataIn[i+4] = p1[4];
+ dataIn[i+5] = p1[5];
+ dataIn[i+6] = p1[6];
+ dataIn[i+7] = p1[7];
+ p1 += bufWidth * vSub;
+ }
+
+ // transform
+ transformDataUnit(quantTable, dataIn, dataOut);
+
+ // store back into frameBuf, doing replication for
+ // subsampled components
+ p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
+ if (hSub == 1 && vSub == 1) {
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ p1[0] = dataOut[i] & 0xff;
+ p1[1] = dataOut[i+1] & 0xff;
+ p1[2] = dataOut[i+2] & 0xff;
+ p1[3] = dataOut[i+3] & 0xff;
+ p1[4] = dataOut[i+4] & 0xff;
+ p1[5] = dataOut[i+5] & 0xff;
+ p1[6] = dataOut[i+6] & 0xff;
+ p1[7] = dataOut[i+7] & 0xff;
+ p1 += bufWidth;
+ }
+ } else if (hSub == 2 && vSub == 2) {
+ p2 = p1 + bufWidth;
+ for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) {
+ p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff;
+ p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff;
+ p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff;
+ p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff;
+ p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff;
+ p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff;
+ p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff;
+ p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff;
+ p1 += bufWidth * 2;
+ p2 += bufWidth * 2;
+ }
+ } else {
+ i = 0;
+ for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) {
+ for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) {
+ p2 = p1 + x4;
+ for (y5 = 0; y5 < vSub; ++y5) {
+ for (x5 = 0; x5 < hSub; ++x5) {
+ p2[x5] = dataOut[i] & 0xff;
+ }
+ p2 += bufWidth;
+ }
+ ++i;
+ }
+ p1 += bufWidth * vSub;
+ }
+ }
+ }
+ }
+ }
+
+ // color space conversion
+ if (colorXform) {
+ // convert YCbCr to RGB
+ if (numComps == 3) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ p0 = &frameBuf[0][(y1+y2) * bufWidth + x1];
+ p1 = &frameBuf[1][(y1+y2) * bufWidth + x1];
+ p2 = &frameBuf[2][(y1+y2) * bufWidth + x1];
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = *p0;
+ pCb = *p1 - 128;
+ pCr = *p2 - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ *p0++ = dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr +
+ 32768) >> 16;
+ *p1++ = dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ *p2++ = dctClip[dctClipOffset + pB];
+ }
+ }
+ // convert YCbCrK to CMYK (K is passed through unchanged)
+ } else if (numComps == 4) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ p0 = &frameBuf[0][(y1+y2) * bufWidth + x1];
+ p1 = &frameBuf[1][(y1+y2) * bufWidth + x1];
+ p2 = &frameBuf[2][(y1+y2) * bufWidth + x1];
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = *p0;
+ pCb = *p1 - 128;
+ pCr = *p2 - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ *p0++ = 255 - dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr +
+ 32768) >> 16;
+ *p1++ = 255 - dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ *p2++ = 255 - dctClip[dctClipOffset + pB];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Transform one data unit -- this performs the dequantization and
+// IDCT steps. This IDCT algorithm is taken from:
+// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
+// "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
+// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
+// 988-991.
+// The stage numbers mentioned in the comments refer to Figure 1 in this
+// paper.
+void DCTStream::transformDataUnit(Gushort *quantTable,
+ int dataIn[64], Guchar dataOut[64]) {
+ int v0, v1, v2, v3, v4, v5, v6, v7, t;
+ int *p;
+ int i;
+
+ // dequant
+ for (i = 0; i < 64; ++i) {
+ dataIn[i] *= quantTable[i];
+ }
+
+ // inverse DCT on rows
+ for (i = 0; i < 64; i += 8) {
+ p = dataIn + i;
+
+ // check for all-zero AC coefficients
+ if (p[1] == 0 && p[2] == 0 && p[3] == 0 &&
+ p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) {
+ t = (dctSqrt2 * p[0] + 512) >> 10;
+ p[0] = t;
+ p[1] = t;
+ p[2] = t;
+ p[3] = t;
+ p[4] = t;
+ p[5] = t;
+ p[6] = t;
+ p[7] = t;
+ continue;
+ }
+
+ // stage 4
+ v0 = (dctSqrt2 * p[0] + 128) >> 8;
+ v1 = (dctSqrt2 * p[4] + 128) >> 8;
+ v2 = p[2];
+ v3 = p[6];
+ v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8;
+ v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8;
+ v5 = p[3] << 4;
+ v6 = p[5] << 4;
+
+ // stage 3
+ t = (v0 - v1+ 1) >> 1;
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = t;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
+ v3 = t;
+ t = (v4 - v6 + 1) >> 1;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = t;
+ t = (v7 + v5 + 1) >> 1;
+ v5 = (v7 - v5 + 1) >> 1;
+ v7 = t;
+
+ // stage 2
+ t = (v0 - v3 + 1) >> 1;
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = t;
+ t = (v1 - v2 + 1) >> 1;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = t;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ p[0] = v0 + v7;
+ p[7] = v0 - v7;
+ p[1] = v1 + v6;
+ p[6] = v1 - v6;
+ p[2] = v2 + v5;
+ p[5] = v2 - v5;
+ p[3] = v3 + v4;
+ p[4] = v3 - v4;
+ }
+
+ // inverse DCT on columns
+ for (i = 0; i < 8; ++i) {
+ p = dataIn + i;
+
+ // check for all-zero AC coefficients
+ if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 &&
+ p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) {
+ t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14;
+ p[0*8] = t;
+ p[1*8] = t;
+ p[2*8] = t;
+ p[3*8] = t;
+ p[4*8] = t;
+ p[5*8] = t;
+ p[6*8] = t;
+ p[7*8] = t;
+ continue;
+ }
+
+ // stage 4
+ v0 = (dctSqrt2 * p[0*8] + 2048) >> 12;
+ v1 = (dctSqrt2 * p[4*8] + 2048) >> 12;
+ v2 = p[2*8];
+ v3 = p[6*8];
+ v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12;
+ v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12;
+ v5 = p[3*8];
+ v6 = p[5*8];
+
+ // stage 3
+ t = (v0 - v1 + 1) >> 1;
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = t;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
+ v3 = t;
+ t = (v4 - v6 + 1) >> 1;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = t;
+ t = (v7 + v5 + 1) >> 1;
+ v5 = (v7 - v5 + 1) >> 1;
+ v7 = t;
+
+ // stage 2
+ t = (v0 - v3 + 1) >> 1;
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = t;
+ t = (v1 - v2 + 1) >> 1;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = t;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ p[0*8] = v0 + v7;
+ p[7*8] = v0 - v7;
+ p[1*8] = v1 + v6;
+ p[6*8] = v1 - v6;
+ p[2*8] = v2 + v5;
+ p[5*8] = v2 - v5;
+ p[3*8] = v3 + v4;
+ p[4*8] = v3 - v4;
+ }
+
+ // convert to 8-bit integers
+ for (i = 0; i < 64; ++i) {
+ const int ix = dctClipOffset + 128 + ((dataIn[i] + 8) >> 4);
+ if (unlikely(ix < 0 || ix >= dctClipLength)) {
+ dataOut[i] = 0;
+ } else {
+ dataOut[i] = dctClip[ix];
+ }
+ }
+}
+
+int DCTStream::readHuffSym(DCTHuffTable *table) {
+ Gushort code;
+ int bit;
+ int codeBits;
+
+ code = 0;
+ codeBits = 0;
+ do {
+ // add a bit to the code
+ if ((bit = readBit()) == EOF) {
+ return 9999;
+ }
+ code = (code << 1) + bit;
+ ++codeBits;
+
+ // look up code
+ if (code < table->firstCode[codeBits]) {
+ break;
+ }
+ if (code - table->firstCode[codeBits] < table->numCodes[codeBits]) {
+ code -= table->firstCode[codeBits];
+ return table->sym[table->firstSym[codeBits] + code];
+ }
+ } while (codeBits < 16);
+
+ error(errSyntaxError, getPos(), "Bad Huffman code in DCT stream");
+ return 9999;
+}
+
+int DCTStream::readAmp(int size) {
+ int amp, bit;
+ int bits;
+
+ amp = 0;
+ for (bits = 0; bits < size; ++bits) {
+ if ((bit = readBit()) == EOF)
+ return 9999;
+ amp = (amp << 1) + bit;
+ }
+ if (amp < (1 << (size - 1)))
+ amp -= (1 << size) - 1;
+ return amp;
+}
+
+int DCTStream::readBit() {
+ int bit;
+ int c, c2;
+
+ if (inputBits == 0) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ if (c == 0xff) {
+ do {
+ c2 = str->getChar();
+ } while (c2 == 0xff);
+ if (c2 != 0x00) {
+ error(errSyntaxError, getPos(), "Bad DCT data: missing 00 after ff");
+ return EOF;
+ }
+ }
+ inputBuf = c;
+ inputBits = 8;
+ }
+ bit = (inputBuf >> (inputBits - 1)) & 1;
+ --inputBits;
+ return bit;
+}
+
+GBool DCTStream::readHeader() {
+ GBool doScan;
+ int n;
+ int c = 0;
+ int i;
+
+ // read headers
+ doScan = gFalse;
+ while (!doScan) {
+ c = readMarker();
+ switch (c) {
+ case 0xc0: // SOF0 (sequential)
+ case 0xc1: // SOF1 (extended sequential)
+ if (!readBaselineSOF()) {
+ return gFalse;
+ }
+ break;
+ case 0xc2: // SOF2 (progressive)
+ if (!readProgressiveSOF()) {
+ return gFalse;
+ }
+ break;
+ case 0xc4: // DHT
+ if (!readHuffmanTables()) {
+ return gFalse;
+ }
+ break;
+ case 0xd8: // SOI
+ break;
+ case 0xd9: // EOI
+ return gFalse;
+ case 0xda: // SOS
+ if (!readScanInfo()) {
+ return gFalse;
+ }
+ doScan = gTrue;
+ break;
+ case 0xdb: // DQT
+ if (!readQuantTables()) {
+ return gFalse;
+ }
+ break;
+ case 0xdd: // DRI
+ if (!readRestartInterval()) {
+ return gFalse;
+ }
+ break;
+ case 0xe0: // APP0
+ if (!readJFIFMarker()) {
+ return gFalse;
+ }
+ break;
+ case 0xee: // APP14
+ if (!readAdobeMarker()) {
+ return gFalse;
+ }
+ break;
+ case EOF:
+ error(errSyntaxError, getPos(), "Bad DCT header");
+ return gFalse;
+ default:
+ // skip APPn / COM / etc.
+ if (c >= 0xe0) {
+ n = read16() - 2;
+ for (i = 0; i < n; ++i) {
+ str->getChar();
+ }
+ } else {
+ error(errSyntaxError, getPos(), "Unknown DCT marker <{0:02x}>", c);
+ return gFalse;
+ }
+ break;
+ }
+ }
+
+ return gTrue;
+}
+
+GBool DCTStream::readBaselineSOF() {
+ int length;
+ int prec;
+ int i;
+ int c;
+
+ length = read16();
+ prec = str->getChar();
+ height = read16();
+ width = read16();
+ numComps = str->getChar();
+ if (numComps <= 0 || numComps > 4) {
+ error(errSyntaxError, getPos(), "Bad number of components in DCT stream");
+ numComps = 0;
+ return gFalse;
+ }
+ if (prec != 8) {
+ error(errSyntaxError, getPos(), "Bad DCT precision {0:d}", prec);
+ return gFalse;
+ }
+ for (i = 0; i < numComps; ++i) {
+ compInfo[i].id = str->getChar();
+ c = str->getChar();
+ compInfo[i].hSample = (c >> 4) & 0x0f;
+ compInfo[i].vSample = c & 0x0f;
+ compInfo[i].quantTable = str->getChar();
+ if (compInfo[i].hSample < 1 || compInfo[i].hSample > 4 ||
+ compInfo[i].vSample < 1 || compInfo[i].vSample > 4) {
+ error(errSyntaxError, getPos(), "Bad DCT sampling factor");
+ return gFalse;
+ }
+ if (compInfo[i].quantTable < 0 || compInfo[i].quantTable > 3) {
+ error(errSyntaxError, getPos(), "Bad DCT quant table selector");
+ return gFalse;
+ }
+ }
+ progressive = gFalse;
+ return gTrue;
+}
+
+GBool DCTStream::readProgressiveSOF() {
+ int length;
+ int prec;
+ int i;
+ int c;
+
+ length = read16();
+ prec = str->getChar();
+ height = read16();
+ width = read16();
+ numComps = str->getChar();
+ if (prec != 8) {
+ error(errSyntaxError, getPos(), "Bad DCT precision {0:d}", prec);
+ return gFalse;
+ }
+ for (i = 0; i < numComps; ++i) {
+ compInfo[i].id = str->getChar();
+ c = str->getChar();
+ compInfo[i].hSample = (c >> 4) & 0x0f;
+ compInfo[i].vSample = c & 0x0f;
+ compInfo[i].quantTable = str->getChar();
+ if (compInfo[i].hSample < 1 || compInfo[i].hSample > 4 ||
+ compInfo[i].vSample < 1 || compInfo[i].vSample > 4) {
+ error(errSyntaxError, getPos(), "Bad DCT sampling factor");
+ return gFalse;
+ }
+ if (compInfo[i].quantTable < 0 || compInfo[i].quantTable > 3) {
+ error(errSyntaxError, getPos(), "Bad DCT quant table selector");
+ return gFalse;
+ }
+ }
+ progressive = gTrue;
+ return gTrue;
+}
+
+GBool DCTStream::readScanInfo() {
+ int length;
+ int id, c;
+ int i, j;
+
+ length = read16() - 2;
+ scanInfo.numComps = str->getChar();
+ if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) {
+ error(errSyntaxError, getPos(), "Bad number of components in DCT stream");
+ scanInfo.numComps = 0;
+ return gFalse;
+ }
+ --length;
+ if (length != 2 * scanInfo.numComps + 3) {
+ error(errSyntaxError, getPos(), "Bad DCT scan info block");
+ return gFalse;
+ }
+ interleaved = scanInfo.numComps == numComps;
+ for (j = 0; j < numComps; ++j) {
+ scanInfo.comp[j] = gFalse;
+ scanInfo.dcHuffTable[j] = 0;
+ scanInfo.acHuffTable[j] = 0;
+ }
+ for (i = 0; i < scanInfo.numComps; ++i) {
+ id = str->getChar();
+ // some (broken) DCT streams reuse ID numbers, but at least they
+ // keep the components in order, so we check compInfo[i] first to
+ // work around the problem
+ if (id == compInfo[i].id) {
+ j = i;
+ } else {
+ for (j = 0; j < numComps; ++j) {
+ if (id == compInfo[j].id) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ error(errSyntaxError, getPos(),
+ "Bad DCT component ID in scan info block");
+ return gFalse;
+ }
+ }
+ scanInfo.comp[j] = gTrue;
+ c = str->getChar();
+ scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f;
+ scanInfo.acHuffTable[j] = c & 0x0f;
+ }
+ scanInfo.firstCoeff = str->getChar();
+ scanInfo.lastCoeff = str->getChar();
+ if (scanInfo.firstCoeff < 0 || scanInfo.lastCoeff > 63 ||
+ scanInfo.firstCoeff > scanInfo.lastCoeff) {
+ error(errSyntaxError, getPos(),
+ "Bad DCT coefficient numbers in scan info block");
+ return gFalse;
+ }
+ c = str->getChar();
+ scanInfo.ah = (c >> 4) & 0x0f;
+ scanInfo.al = c & 0x0f;
+ return gTrue;
+}
+
+GBool DCTStream::readQuantTables() {
+ int length, prec, i, index;
+
+ length = read16() - 2;
+ while (length > 0) {
+ index = str->getChar();
+ prec = (index >> 4) & 0x0f;
+ index &= 0x0f;
+ if (prec > 1 || index >= 4) {
+ error(errSyntaxError, getPos(), "Bad DCT quantization table");
+ return gFalse;
+ }
+ if (index == numQuantTables) {
+ numQuantTables = index + 1;
+ }
+ for (i = 0; i < 64; ++i) {
+ if (prec) {
+ quantTables[index][dctZigZag[i]] = read16();
+ } else {
+ quantTables[index][dctZigZag[i]] = str->getChar();
+ }
+ }
+ if (prec) {
+ length -= 129;
+ } else {
+ length -= 65;
+ }
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readHuffmanTables() {
+ DCTHuffTable *tbl;
+ int length;
+ int index;
+ Gushort code;
+ Guchar sym;
+ int i;
+ int c;
+
+ length = read16() - 2;
+ while (length > 0) {
+ index = str->getChar();
+ --length;
+ if ((index & 0x0f) >= 4) {
+ error(errSyntaxError, getPos(), "Bad DCT Huffman table");
+ return gFalse;
+ }
+ if (index & 0x10) {
+ index &= 0x0f;
+ if (index >= numACHuffTables)
+ numACHuffTables = index+1;
+ tbl = &acHuffTables[index];
+ } else {
+ index &= 0x0f;
+ if (index >= numDCHuffTables)
+ numDCHuffTables = index+1;
+ tbl = &dcHuffTables[index];
+ }
+ sym = 0;
+ code = 0;
+ for (i = 1; i <= 16; ++i) {
+ c = str->getChar();
+ tbl->firstSym[i] = sym;
+ tbl->firstCode[i] = code;
+ tbl->numCodes[i] = c;
+ sym += c;
+ code = (code + c) << 1;
+ }
+ length -= 16;
+ for (i = 0; i < sym; ++i)
+ tbl->sym[i] = str->getChar();
+ length -= sym;
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readRestartInterval() {
+ int length;
+
+ length = read16();
+ if (length != 4) {
+ error(errSyntaxError, getPos(), "Bad DCT restart interval");
+ return gFalse;
+ }
+ restartInterval = read16();
+ return gTrue;
+}
+
+GBool DCTStream::readJFIFMarker() {
+ int length, i;
+ char buf[5];
+ int c;
+
+ length = read16();
+ length -= 2;
+ if (length >= 5) {
+ for (i = 0; i < 5; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ error(errSyntaxError, getPos(), "Bad DCT APP0 marker");
+ return gFalse;
+ }
+ buf[i] = c;
+ }
+ length -= 5;
+ if (!memcmp(buf, "JFIF\0", 5)) {
+ gotJFIFMarker = gTrue;
+ }
+ }
+ while (length > 0) {
+ if (str->getChar() == EOF) {
+ error(errSyntaxError, getPos(), "Bad DCT APP0 marker");
+ return gFalse;
+ }
+ --length;
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readAdobeMarker() {
+ int length, i;
+ char buf[12];
+ int c;
+
+ length = read16();
+ if (length < 14) {
+ goto err;
+ }
+ for (i = 0; i < 12; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ goto err;
+ }
+ buf[i] = c;
+ }
+ if (strncmp(buf, "Adobe", 5)) {
+ goto err;
+ }
+ colorXform = buf[11];
+ gotAdobeMarker = gTrue;
+ for (i = 14; i < length; ++i) {
+ if (str->getChar() == EOF) {
+ goto err;
+ }
+ }
+ return gTrue;
+
+ err:
+ error(errSyntaxError, getPos(), "Bad DCT Adobe APP14 marker");
+ return gFalse;
+}
+
+GBool DCTStream::readTrailer() {
+ int c;
+
+ c = readMarker();
+ if (c != 0xd9) { // EOI
+ error(errSyntaxError, getPos(), "Bad DCT trailer");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+int DCTStream::readMarker() {
+ int c;
+
+ do {
+ do {
+ c = str->getChar();
+ } while (c != 0xff && c != EOF);
+ while (c == 0xff) {
+ c = str->getChar();
+ }
+ } while (c == 0x00);
+ return c;
+}
+
+int DCTStream::read16() {
+ int c1, c2;
+
+ if ((c1 = str->getChar()) == EOF)
+ return EOF;
+ if ((c2 = str->getChar()) == EOF)
+ return EOF;
+ return (c1 << 8) + c2;
+}
+
+GooString *DCTStream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /DCTDecode filter\n");
+ return s;
+}
+
+GBool DCTStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+#endif
+
+#ifndef ENABLE_ZLIB
+//------------------------------------------------------------------------
+// FlateStream
+//------------------------------------------------------------------------
+
+int FlateStream::codeLenCodeMap[flateMaxCodeLenCodes] = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+};
+
+FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = {
+ {0, 3},
+ {0, 4},
+ {0, 5},
+ {0, 6},
+ {0, 7},
+ {0, 8},
+ {0, 9},
+ {0, 10},
+ {1, 11},
+ {1, 13},
+ {1, 15},
+ {1, 17},
+ {2, 19},
+ {2, 23},
+ {2, 27},
+ {2, 31},
+ {3, 35},
+ {3, 43},
+ {3, 51},
+ {3, 59},
+ {4, 67},
+ {4, 83},
+ {4, 99},
+ {4, 115},
+ {5, 131},
+ {5, 163},
+ {5, 195},
+ {5, 227},
+ {0, 258},
+ {0, 258},
+ {0, 258}
+};
+
+FlateDecode FlateStream::distDecode[flateMaxDistCodes] = {
+ { 0, 1},
+ { 0, 2},
+ { 0, 3},
+ { 0, 4},
+ { 1, 5},
+ { 1, 7},
+ { 2, 9},
+ { 2, 13},
+ { 3, 17},
+ { 3, 25},
+ { 4, 33},
+ { 4, 49},
+ { 5, 65},
+ { 5, 97},
+ { 6, 129},
+ { 6, 193},
+ { 7, 257},
+ { 7, 385},
+ { 8, 513},
+ { 8, 769},
+ { 9, 1025},
+ { 9, 1537},
+ {10, 2049},
+ {10, 3073},
+ {11, 4097},
+ {11, 6145},
+ {12, 8193},
+ {12, 12289},
+ {13, 16385},
+ {13, 24577}
+};
+
+static FlateCode flateFixedLitCodeTabCodes[512] = {
+ {7, 0x0100},
+ {8, 0x0050},
+ {8, 0x0010},
+ {8, 0x0118},
+ {7, 0x0110},
+ {8, 0x0070},
+ {8, 0x0030},
+ {9, 0x00c0},
+ {7, 0x0108},
+ {8, 0x0060},
+ {8, 0x0020},
+ {9, 0x00a0},
+ {8, 0x0000},
+ {8, 0x0080},
+ {8, 0x0040},
+ {9, 0x00e0},
+ {7, 0x0104},
+ {8, 0x0058},
+ {8, 0x0018},
+ {9, 0x0090},
+ {7, 0x0114},
+ {8, 0x0078},
+ {8, 0x0038},
+ {9, 0x00d0},
+ {7, 0x010c},
+ {8, 0x0068},
+ {8, 0x0028},
+ {9, 0x00b0},
+ {8, 0x0008},
+ {8, 0x0088},
+ {8, 0x0048},
+ {9, 0x00f0},
+ {7, 0x0102},
+ {8, 0x0054},
+ {8, 0x0014},
+ {8, 0x011c},
+ {7, 0x0112},
+ {8, 0x0074},
+ {8, 0x0034},
+ {9, 0x00c8},
+ {7, 0x010a},
+ {8, 0x0064},
+ {8, 0x0024},
+ {9, 0x00a8},
+ {8, 0x0004},
+ {8, 0x0084},
+ {8, 0x0044},
+ {9, 0x00e8},
+ {7, 0x0106},
+ {8, 0x005c},
+ {8, 0x001c},
+ {9, 0x0098},
+ {7, 0x0116},
+ {8, 0x007c},
+ {8, 0x003c},
+ {9, 0x00d8},
+ {7, 0x010e},
+ {8, 0x006c},
+ {8, 0x002c},
+ {9, 0x00b8},
+ {8, 0x000c},
+ {8, 0x008c},
+ {8, 0x004c},
+ {9, 0x00f8},
+ {7, 0x0101},
+ {8, 0x0052},
+ {8, 0x0012},
+ {8, 0x011a},
+ {7, 0x0111},
+ {8, 0x0072},
+ {8, 0x0032},
+ {9, 0x00c4},
+ {7, 0x0109},
+ {8, 0x0062},
+ {8, 0x0022},
+ {9, 0x00a4},
+ {8, 0x0002},
+ {8, 0x0082},
+ {8, 0x0042},
+ {9, 0x00e4},
+ {7, 0x0105},
+ {8, 0x005a},
+ {8, 0x001a},
+ {9, 0x0094},
+ {7, 0x0115},
+ {8, 0x007a},
+ {8, 0x003a},
+ {9, 0x00d4},
+ {7, 0x010d},
+ {8, 0x006a},
+ {8, 0x002a},
+ {9, 0x00b4},
+ {8, 0x000a},
+ {8, 0x008a},
+ {8, 0x004a},
+ {9, 0x00f4},
+ {7, 0x0103},
+ {8, 0x0056},
+ {8, 0x0016},
+ {8, 0x011e},
+ {7, 0x0113},
+ {8, 0x0076},
+ {8, 0x0036},
+ {9, 0x00cc},
+ {7, 0x010b},
+ {8, 0x0066},
+ {8, 0x0026},
+ {9, 0x00ac},
+ {8, 0x0006},
+ {8, 0x0086},
+ {8, 0x0046},
+ {9, 0x00ec},
+ {7, 0x0107},
+ {8, 0x005e},
+ {8, 0x001e},
+ {9, 0x009c},
+ {7, 0x0117},
+ {8, 0x007e},
+ {8, 0x003e},
+ {9, 0x00dc},
+ {7, 0x010f},
+ {8, 0x006e},
+ {8, 0x002e},
+ {9, 0x00bc},
+ {8, 0x000e},
+ {8, 0x008e},
+ {8, 0x004e},
+ {9, 0x00fc},
+ {7, 0x0100},
+ {8, 0x0051},
+ {8, 0x0011},
+ {8, 0x0119},
+ {7, 0x0110},
+ {8, 0x0071},
+ {8, 0x0031},
+ {9, 0x00c2},
+ {7, 0x0108},
+ {8, 0x0061},
+ {8, 0x0021},
+ {9, 0x00a2},
+ {8, 0x0001},
+ {8, 0x0081},
+ {8, 0x0041},
+ {9, 0x00e2},
+ {7, 0x0104},
+ {8, 0x0059},
+ {8, 0x0019},
+ {9, 0x0092},
+ {7, 0x0114},
+ {8, 0x0079},
+ {8, 0x0039},
+ {9, 0x00d2},
+ {7, 0x010c},
+ {8, 0x0069},
+ {8, 0x0029},
+ {9, 0x00b2},
+ {8, 0x0009},
+ {8, 0x0089},
+ {8, 0x0049},
+ {9, 0x00f2},
+ {7, 0x0102},
+ {8, 0x0055},
+ {8, 0x0015},
+ {8, 0x011d},
+ {7, 0x0112},
+ {8, 0x0075},
+ {8, 0x0035},
+ {9, 0x00ca},
+ {7, 0x010a},
+ {8, 0x0065},
+ {8, 0x0025},
+ {9, 0x00aa},
+ {8, 0x0005},
+ {8, 0x0085},
+ {8, 0x0045},
+ {9, 0x00ea},
+ {7, 0x0106},
+ {8, 0x005d},
+ {8, 0x001d},
+ {9, 0x009a},
+ {7, 0x0116},
+ {8, 0x007d},
+ {8, 0x003d},
+ {9, 0x00da},
+ {7, 0x010e},
+ {8, 0x006d},
+ {8, 0x002d},
+ {9, 0x00ba},
+ {8, 0x000d},
+ {8, 0x008d},
+ {8, 0x004d},
+ {9, 0x00fa},
+ {7, 0x0101},
+ {8, 0x0053},
+ {8, 0x0013},
+ {8, 0x011b},
+ {7, 0x0111},
+ {8, 0x0073},
+ {8, 0x0033},
+ {9, 0x00c6},
+ {7, 0x0109},
+ {8, 0x0063},
+ {8, 0x0023},
+ {9, 0x00a6},
+ {8, 0x0003},
+ {8, 0x0083},
+ {8, 0x0043},
+ {9, 0x00e6},
+ {7, 0x0105},
+ {8, 0x005b},
+ {8, 0x001b},
+ {9, 0x0096},
+ {7, 0x0115},
+ {8, 0x007b},
+ {8, 0x003b},
+ {9, 0x00d6},
+ {7, 0x010d},
+ {8, 0x006b},
+ {8, 0x002b},
+ {9, 0x00b6},
+ {8, 0x000b},
+ {8, 0x008b},
+ {8, 0x004b},
+ {9, 0x00f6},
+ {7, 0x0103},
+ {8, 0x0057},
+ {8, 0x0017},
+ {8, 0x011f},
+ {7, 0x0113},
+ {8, 0x0077},
+ {8, 0x0037},
+ {9, 0x00ce},
+ {7, 0x010b},
+ {8, 0x0067},
+ {8, 0x0027},
+ {9, 0x00ae},
+ {8, 0x0007},
+ {8, 0x0087},
+ {8, 0x0047},
+ {9, 0x00ee},
+ {7, 0x0107},
+ {8, 0x005f},
+ {8, 0x001f},
+ {9, 0x009e},
+ {7, 0x0117},
+ {8, 0x007f},
+ {8, 0x003f},
+ {9, 0x00de},
+ {7, 0x010f},
+ {8, 0x006f},
+ {8, 0x002f},
+ {9, 0x00be},
+ {8, 0x000f},
+ {8, 0x008f},
+ {8, 0x004f},
+ {9, 0x00fe},
+ {7, 0x0100},
+ {8, 0x0050},
+ {8, 0x0010},
+ {8, 0x0118},
+ {7, 0x0110},
+ {8, 0x0070},
+ {8, 0x0030},
+ {9, 0x00c1},
+ {7, 0x0108},
+ {8, 0x0060},
+ {8, 0x0020},
+ {9, 0x00a1},
+ {8, 0x0000},
+ {8, 0x0080},
+ {8, 0x0040},
+ {9, 0x00e1},
+ {7, 0x0104},
+ {8, 0x0058},
+ {8, 0x0018},
+ {9, 0x0091},
+ {7, 0x0114},
+ {8, 0x0078},
+ {8, 0x0038},
+ {9, 0x00d1},
+ {7, 0x010c},
+ {8, 0x0068},
+ {8, 0x0028},
+ {9, 0x00b1},
+ {8, 0x0008},
+ {8, 0x0088},
+ {8, 0x0048},
+ {9, 0x00f1},
+ {7, 0x0102},
+ {8, 0x0054},
+ {8, 0x0014},
+ {8, 0x011c},
+ {7, 0x0112},
+ {8, 0x0074},
+ {8, 0x0034},
+ {9, 0x00c9},
+ {7, 0x010a},
+ {8, 0x0064},
+ {8, 0x0024},
+ {9, 0x00a9},
+ {8, 0x0004},
+ {8, 0x0084},
+ {8, 0x0044},
+ {9, 0x00e9},
+ {7, 0x0106},
+ {8, 0x005c},
+ {8, 0x001c},
+ {9, 0x0099},
+ {7, 0x0116},
+ {8, 0x007c},
+ {8, 0x003c},
+ {9, 0x00d9},
+ {7, 0x010e},
+ {8, 0x006c},
+ {8, 0x002c},
+ {9, 0x00b9},
+ {8, 0x000c},
+ {8, 0x008c},
+ {8, 0x004c},
+ {9, 0x00f9},
+ {7, 0x0101},
+ {8, 0x0052},
+ {8, 0x0012},
+ {8, 0x011a},
+ {7, 0x0111},
+ {8, 0x0072},
+ {8, 0x0032},
+ {9, 0x00c5},
+ {7, 0x0109},
+ {8, 0x0062},
+ {8, 0x0022},
+ {9, 0x00a5},
+ {8, 0x0002},
+ {8, 0x0082},
+ {8, 0x0042},
+ {9, 0x00e5},
+ {7, 0x0105},
+ {8, 0x005a},
+ {8, 0x001a},
+ {9, 0x0095},
+ {7, 0x0115},
+ {8, 0x007a},
+ {8, 0x003a},
+ {9, 0x00d5},
+ {7, 0x010d},
+ {8, 0x006a},
+ {8, 0x002a},
+ {9, 0x00b5},
+ {8, 0x000a},
+ {8, 0x008a},
+ {8, 0x004a},
+ {9, 0x00f5},
+ {7, 0x0103},
+ {8, 0x0056},
+ {8, 0x0016},
+ {8, 0x011e},
+ {7, 0x0113},
+ {8, 0x0076},
+ {8, 0x0036},
+ {9, 0x00cd},
+ {7, 0x010b},
+ {8, 0x0066},
+ {8, 0x0026},
+ {9, 0x00ad},
+ {8, 0x0006},
+ {8, 0x0086},
+ {8, 0x0046},
+ {9, 0x00ed},
+ {7, 0x0107},
+ {8, 0x005e},
+ {8, 0x001e},
+ {9, 0x009d},
+ {7, 0x0117},
+ {8, 0x007e},
+ {8, 0x003e},
+ {9, 0x00dd},
+ {7, 0x010f},
+ {8, 0x006e},
+ {8, 0x002e},
+ {9, 0x00bd},
+ {8, 0x000e},
+ {8, 0x008e},
+ {8, 0x004e},
+ {9, 0x00fd},
+ {7, 0x0100},
+ {8, 0x0051},
+ {8, 0x0011},
+ {8, 0x0119},
+ {7, 0x0110},
+ {8, 0x0071},
+ {8, 0x0031},
+ {9, 0x00c3},
+ {7, 0x0108},
+ {8, 0x0061},
+ {8, 0x0021},
+ {9, 0x00a3},
+ {8, 0x0001},
+ {8, 0x0081},
+ {8, 0x0041},
+ {9, 0x00e3},
+ {7, 0x0104},
+ {8, 0x0059},
+ {8, 0x0019},
+ {9, 0x0093},
+ {7, 0x0114},
+ {8, 0x0079},
+ {8, 0x0039},
+ {9, 0x00d3},
+ {7, 0x010c},
+ {8, 0x0069},
+ {8, 0x0029},
+ {9, 0x00b3},
+ {8, 0x0009},
+ {8, 0x0089},
+ {8, 0x0049},
+ {9, 0x00f3},
+ {7, 0x0102},
+ {8, 0x0055},
+ {8, 0x0015},
+ {8, 0x011d},
+ {7, 0x0112},
+ {8, 0x0075},
+ {8, 0x0035},
+ {9, 0x00cb},
+ {7, 0x010a},
+ {8, 0x0065},
+ {8, 0x0025},
+ {9, 0x00ab},
+ {8, 0x0005},
+ {8, 0x0085},
+ {8, 0x0045},
+ {9, 0x00eb},
+ {7, 0x0106},
+ {8, 0x005d},
+ {8, 0x001d},
+ {9, 0x009b},
+ {7, 0x0116},
+ {8, 0x007d},
+ {8, 0x003d},
+ {9, 0x00db},
+ {7, 0x010e},
+ {8, 0x006d},
+ {8, 0x002d},
+ {9, 0x00bb},
+ {8, 0x000d},
+ {8, 0x008d},
+ {8, 0x004d},
+ {9, 0x00fb},
+ {7, 0x0101},
+ {8, 0x0053},
+ {8, 0x0013},
+ {8, 0x011b},
+ {7, 0x0111},
+ {8, 0x0073},
+ {8, 0x0033},
+ {9, 0x00c7},
+ {7, 0x0109},
+ {8, 0x0063},
+ {8, 0x0023},
+ {9, 0x00a7},
+ {8, 0x0003},
+ {8, 0x0083},
+ {8, 0x0043},
+ {9, 0x00e7},
+ {7, 0x0105},
+ {8, 0x005b},
+ {8, 0x001b},
+ {9, 0x0097},
+ {7, 0x0115},
+ {8, 0x007b},
+ {8, 0x003b},
+ {9, 0x00d7},
+ {7, 0x010d},
+ {8, 0x006b},
+ {8, 0x002b},
+ {9, 0x00b7},
+ {8, 0x000b},
+ {8, 0x008b},
+ {8, 0x004b},
+ {9, 0x00f7},
+ {7, 0x0103},
+ {8, 0x0057},
+ {8, 0x0017},
+ {8, 0x011f},
+ {7, 0x0113},
+ {8, 0x0077},
+ {8, 0x0037},
+ {9, 0x00cf},
+ {7, 0x010b},
+ {8, 0x0067},
+ {8, 0x0027},
+ {9, 0x00af},
+ {8, 0x0007},
+ {8, 0x0087},
+ {8, 0x0047},
+ {9, 0x00ef},
+ {7, 0x0107},
+ {8, 0x005f},
+ {8, 0x001f},
+ {9, 0x009f},
+ {7, 0x0117},
+ {8, 0x007f},
+ {8, 0x003f},
+ {9, 0x00df},
+ {7, 0x010f},
+ {8, 0x006f},
+ {8, 0x002f},
+ {9, 0x00bf},
+ {8, 0x000f},
+ {8, 0x008f},
+ {8, 0x004f},
+ {9, 0x00ff}
+};
+
+FlateHuffmanTab FlateStream::fixedLitCodeTab = {
+ flateFixedLitCodeTabCodes, 9
+};
+
+static FlateCode flateFixedDistCodeTabCodes[32] = {
+ {5, 0x0000},
+ {5, 0x0010},
+ {5, 0x0008},
+ {5, 0x0018},
+ {5, 0x0004},
+ {5, 0x0014},
+ {5, 0x000c},
+ {5, 0x001c},
+ {5, 0x0002},
+ {5, 0x0012},
+ {5, 0x000a},
+ {5, 0x001a},
+ {5, 0x0006},
+ {5, 0x0016},
+ {5, 0x000e},
+ {0, 0x0000},
+ {5, 0x0001},
+ {5, 0x0011},
+ {5, 0x0009},
+ {5, 0x0019},
+ {5, 0x0005},
+ {5, 0x0015},
+ {5, 0x000d},
+ {5, 0x001d},
+ {5, 0x0003},
+ {5, 0x0013},
+ {5, 0x000b},
+ {5, 0x001b},
+ {5, 0x0007},
+ {5, 0x0017},
+ {5, 0x000f},
+ {0, 0x0000}
+};
+
+FlateHuffmanTab FlateStream::fixedDistCodeTab = {
+ flateFixedDistCodeTabCodes, 5
+};
+
+FlateStream::FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
+ if (!pred->isOk()) {
+ delete pred;
+ pred = NULL;
+ }
+ } else {
+ pred = NULL;
+ }
+ litCodeTab.codes = NULL;
+ distCodeTab.codes = NULL;
+ memset(buf, 0, flateWindow);
+}
+
+FlateStream::~FlateStream() {
+ if (litCodeTab.codes != fixedLitCodeTab.codes) {
+ gfree(litCodeTab.codes);
+ }
+ if (distCodeTab.codes != fixedDistCodeTab.codes) {
+ gfree(distCodeTab.codes);
+ }
+ if (pred) {
+ delete pred;
+ }
+ delete str;
+}
+
+void FlateStream::flateReset(GBool unfiltered) {
+ if (unfiltered)
+ str->unfilteredReset();
+ else
+ str->reset();
+
+ index = 0;
+ remain = 0;
+ codeBuf = 0;
+ codeSize = 0;
+ compressedBlock = gFalse;
+ endOfBlock = gTrue;
+ eof = gTrue;
+}
+
+void FlateStream::unfilteredReset() {
+ flateReset(gTrue);
+}
+
+void FlateStream::reset() {
+ int cmf, flg;
+
+ flateReset(gFalse);
+
+ // read header
+ //~ need to look at window size?
+ endOfBlock = eof = gTrue;
+ cmf = str->getChar();
+ flg = str->getChar();
+ if (cmf == EOF || flg == EOF)
+ return;
+ if ((cmf & 0x0f) != 0x08) {
+ error(errSyntaxError, getPos(), "Unknown compression method in flate stream");
+ return;
+ }
+ if ((((cmf << 8) + flg) % 31) != 0) {
+ error(errSyntaxError, getPos(), "Bad FCHECK in flate stream");
+ return;
+ }
+ if (flg & 0x20) {
+ error(errSyntaxError, getPos(), "FDICT bit set in flate stream");
+ return;
+ }
+
+ eof = gFalse;
+}
+
+int FlateStream::getChar() {
+ if (pred) {
+ return pred->getChar();
+ }
+ return doGetRawChar();
+}
+
+int FlateStream::getChars(int nChars, Guchar *buffer) {
+ if (pred) {
+ return pred->getChars(nChars, buffer);
+ } else {
+ for (int i = 0; i < nChars; ++i) {
+ const int c = doGetRawChar();
+ if (likely(c != EOF)) buffer[i] = c;
+ else return i;
+ }
+ return nChars;
+ }
+}
+
+int FlateStream::lookChar() {
+ int c;
+
+ if (pred) {
+ return pred->lookChar();
+ }
+ while (remain == 0) {
+ if (endOfBlock && eof)
+ return EOF;
+ readSome();
+ }
+ c = buf[index];
+ return c;
+}
+
+void FlateStream::getRawChars(int nChars, int *buffer) {
+ for (int i = 0; i < nChars; ++i)
+ buffer[i] = doGetRawChar();
+}
+
+int FlateStream::getRawChar() {
+ return doGetRawChar();
+}
+
+GooString *FlateStream::getPSFilter(int psLevel, const char *indent) {
+ GooString *s;
+
+ if (psLevel < 3 || pred) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /FlateDecode filter\n");
+ return s;
+}
+
+GBool FlateStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+void FlateStream::readSome() {
+ int code1, code2;
+ int len, dist;
+ int i, j, k;
+ int c;
+
+ if (endOfBlock) {
+ if (!startBlock())
+ return;
+ }
+
+ if (compressedBlock) {
+ if ((code1 = getHuffmanCodeWord(&litCodeTab)) == EOF)
+ goto err;
+ if (code1 < 256) {
+ buf[index] = code1;
+ remain = 1;
+ } else if (code1 == 256) {
+ endOfBlock = gTrue;
+ remain = 0;
+ } else {
+ code1 -= 257;
+ code2 = lengthDecode[code1].bits;
+ if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF)
+ goto err;
+ len = lengthDecode[code1].first + code2;
+ if ((code1 = getHuffmanCodeWord(&distCodeTab)) == EOF)
+ goto err;
+ code2 = distDecode[code1].bits;
+ if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF)
+ goto err;
+ dist = distDecode[code1].first + code2;
+ i = index;
+ j = (index - dist) & flateMask;
+ for (k = 0; k < len; ++k) {
+ buf[i] = buf[j];
+ i = (i + 1) & flateMask;
+ j = (j + 1) & flateMask;
+ }
+ remain = len;
+ }
+
+ } else {
+ len = (blockLen < flateWindow) ? blockLen : flateWindow;
+ for (i = 0, j = index; i < len; ++i, j = (j + 1) & flateMask) {
+ if ((c = str->getChar()) == EOF) {
+ endOfBlock = eof = gTrue;
+ break;
+ }
+ buf[j] = c & 0xff;
+ }
+ remain = i;
+ blockLen -= len;
+ if (blockLen == 0)
+ endOfBlock = gTrue;
+ }
+
+ return;
+
+err:
+ error(errSyntaxError, getPos(), "Unexpected end of file in flate stream");
+ endOfBlock = eof = gTrue;
+ remain = 0;
+}
+
+GBool FlateStream::startBlock() {
+ int blockHdr;
+ int c;
+ int check;
+
+ // free the code tables from the previous block
+ if (litCodeTab.codes != fixedLitCodeTab.codes) {
+ gfree(litCodeTab.codes);
+ }
+ litCodeTab.codes = NULL;
+ if (distCodeTab.codes != fixedDistCodeTab.codes) {
+ gfree(distCodeTab.codes);
+ }
+ distCodeTab.codes = NULL;
+
+ // read block header
+ blockHdr = getCodeWord(3);
+ if (blockHdr & 1)
+ eof = gTrue;
+ blockHdr >>= 1;
+
+ // uncompressed block
+ if (blockHdr == 0) {
+ compressedBlock = gFalse;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ blockLen = c & 0xff;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ blockLen |= (c & 0xff) << 8;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ check = c & 0xff;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ check |= (c & 0xff) << 8;
+ if (check != (~blockLen & 0xffff))
+ error(errSyntaxError, getPos(), "Bad uncompressed block length in flate stream");
+ codeBuf = 0;
+ codeSize = 0;
+
+ // compressed block with fixed codes
+ } else if (blockHdr == 1) {
+ compressedBlock = gTrue;
+ loadFixedCodes();
+
+ // compressed block with dynamic codes
+ } else if (blockHdr == 2) {
+ compressedBlock = gTrue;
+ if (!readDynamicCodes()) {
+ goto err;
+ }
+
+ // unknown block type
+ } else {
+ goto err;
+ }
+
+ endOfBlock = gFalse;
+ return gTrue;
+
+err:
+ error(errSyntaxError, getPos(), "Bad block header in flate stream");
+ endOfBlock = eof = gTrue;
+ return gFalse;
+}
+
+void FlateStream::loadFixedCodes() {
+ litCodeTab.codes = fixedLitCodeTab.codes;
+ litCodeTab.maxLen = fixedLitCodeTab.maxLen;
+ distCodeTab.codes = fixedDistCodeTab.codes;
+ distCodeTab.maxLen = fixedDistCodeTab.maxLen;
+}
+
+GBool FlateStream::readDynamicCodes() {
+ int numCodeLenCodes;
+ int numLitCodes;
+ int numDistCodes;
+ int codeLenCodeLengths[flateMaxCodeLenCodes];
+ FlateHuffmanTab codeLenCodeTab;
+ int len, repeat, code;
+ int i;
+
+ codeLenCodeTab.codes = NULL;
+
+ // read lengths
+ if ((numLitCodes = getCodeWord(5)) == EOF) {
+ goto err;
+ }
+ numLitCodes += 257;
+ if ((numDistCodes = getCodeWord(5)) == EOF) {
+ goto err;
+ }
+ numDistCodes += 1;
+ if ((numCodeLenCodes = getCodeWord(4)) == EOF) {
+ goto err;
+ }
+ numCodeLenCodes += 4;
+ if (numLitCodes > flateMaxLitCodes ||
+ numDistCodes > flateMaxDistCodes ||
+ numCodeLenCodes > flateMaxCodeLenCodes) {
+ goto err;
+ }
+
+ // build the code length code table
+ for (i = 0; i < flateMaxCodeLenCodes; ++i) {
+ codeLenCodeLengths[i] = 0;
+ }
+ for (i = 0; i < numCodeLenCodes; ++i) {
+ if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) {
+ goto err;
+ }
+ }
+ compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab);
+
+ // build the literal and distance code tables
+ len = 0;
+ repeat = 0;
+ i = 0;
+ while (i < numLitCodes + numDistCodes) {
+ if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) {
+ goto err;
+ }
+ if (code == 16) {
+ if ((repeat = getCodeWord(2)) == EOF) {
+ goto err;
+ }
+ repeat += 3;
+ if (i + repeat > numLitCodes + numDistCodes) {
+ goto err;
+ }
+ for (; repeat > 0; --repeat) {
+ codeLengths[i++] = len;
+ }
+ } else if (code == 17) {
+ if ((repeat = getCodeWord(3)) == EOF) {
+ goto err;
+ }
+ repeat += 3;
+ if (i + repeat > numLitCodes + numDistCodes) {
+ goto err;
+ }
+ len = 0;
+ for (; repeat > 0; --repeat) {
+ codeLengths[i++] = 0;
+ }
+ } else if (code == 18) {
+ if ((repeat = getCodeWord(7)) == EOF) {
+ goto err;
+ }
+ repeat += 11;
+ if (i + repeat > numLitCodes + numDistCodes) {
+ goto err;
+ }
+ len = 0;
+ for (; repeat > 0; --repeat) {
+ codeLengths[i++] = 0;
+ }
+ } else {
+ codeLengths[i++] = len = code;
+ }
+ }
+ compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab);
+ compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab);
+
+ gfree(codeLenCodeTab.codes);
+ return gTrue;
+
+err:
+ error(errSyntaxError, getPos(), "Bad dynamic code table in flate stream");
+ gfree(codeLenCodeTab.codes);
+ return gFalse;
+}
+
+// Convert an array <lengths> of <n> lengths, in value order, into a
+// Huffman code lookup table.
+void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) {
+ int tabSize, len, code, code2, skip, val, i, t;
+
+ // find max code length
+ tab->maxLen = 0;
+ for (val = 0; val < n; ++val) {
+ if (lengths[val] > tab->maxLen) {
+ tab->maxLen = lengths[val];
+ }
+ }
+
+ // allocate the table
+ tabSize = 1 << tab->maxLen;
+ tab->codes = (FlateCode *)gmallocn(tabSize, sizeof(FlateCode));
+
+ // clear the table
+ for (i = 0; i < tabSize; ++i) {
+ tab->codes[i].len = 0;
+ tab->codes[i].val = 0;
+ }
+
+ // build the table
+ for (len = 1, code = 0, skip = 2;
+ len <= tab->maxLen;
+ ++len, code <<= 1, skip <<= 1) {
+ for (val = 0; val < n; ++val) {
+ if (lengths[val] == len) {
+
+ // bit-reverse the code
+ code2 = 0;
+ t = code;
+ for (i = 0; i < len; ++i) {
+ code2 = (code2 << 1) | (t & 1);
+ t >>= 1;
+ }
+
+ // fill in the table entries
+ for (i = code2; i < tabSize; i += skip) {
+ tab->codes[i].len = (Gushort)len;
+ tab->codes[i].val = (Gushort)val;
+ }
+
+ ++code;
+ }
+ }
+ }
+}
+
+int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) {
+ FlateCode *code;
+ int c;
+
+ while (codeSize < tab->maxLen) {
+ if ((c = str->getChar()) == EOF) {
+ break;
+ }
+ codeBuf |= (c & 0xff) << codeSize;
+ codeSize += 8;
+ }
+ code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)];
+ if (codeSize == 0 || codeSize < code->len || code->len == 0) {
+ return EOF;
+ }
+ codeBuf >>= code->len;
+ codeSize -= code->len;
+ return (int)code->val;
+}
+
+int FlateStream::getCodeWord(int bits) {
+ int c;
+
+ while (codeSize < bits) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ codeBuf |= (c & 0xff) << codeSize;
+ codeSize += 8;
+ }
+ c = codeBuf & ((1 << bits) - 1);
+ codeBuf >>= bits;
+ codeSize -= bits;
+ return c;
+}
+#endif
+
+//------------------------------------------------------------------------
+// EOFStream
+//------------------------------------------------------------------------
+
+EOFStream::EOFStream(Stream *strA):
+ FilterStream(strA) {
+}
+
+EOFStream::~EOFStream() {
+ delete str;
+}
+
+//------------------------------------------------------------------------
+// BufStream
+//------------------------------------------------------------------------
+
+BufStream::BufStream(Stream *strA, int bufSizeA): FilterStream(strA) {
+ bufSize = bufSizeA;
+ buf = (int *)gmallocn(bufSize, sizeof(int));
+}
+
+BufStream::~BufStream() {
+ gfree(buf);
+ delete str;
+}
+
+void BufStream::reset() {
+ int i;
+
+ str->reset();
+ for (i = 0; i < bufSize; ++i) {
+ buf[i] = str->getChar();
+ }
+}
+
+int BufStream::getChar() {
+ int c, i;
+
+ c = buf[0];
+ for (i = 1; i < bufSize; ++i) {
+ buf[i-1] = buf[i];
+ }
+ buf[bufSize - 1] = str->getChar();
+ return c;
+}
+
+int BufStream::lookChar() {
+ return buf[0];
+}
+
+int BufStream::lookChar(int idx) {
+ return buf[idx];
+}
+
+GBool BufStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// FixedLengthEncoder
+//------------------------------------------------------------------------
+
+FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA):
+ FilterStream(strA) {
+ length = lengthA;
+ count = 0;
+}
+
+FixedLengthEncoder::~FixedLengthEncoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void FixedLengthEncoder::reset() {
+ str->reset();
+ count = 0;
+}
+
+int FixedLengthEncoder::getChar() {
+ if (length >= 0 && count >= length)
+ return EOF;
+ ++count;
+ return str->getChar();
+}
+
+int FixedLengthEncoder::lookChar() {
+ if (length >= 0 && count >= length)
+ return EOF;
+ return str->getChar();
+}
+
+GBool FixedLengthEncoder::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// ASCIIHexEncoder
+//------------------------------------------------------------------------
+
+ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+ASCIIHexEncoder::~ASCIIHexEncoder() {
+ if (str->isEncoder()) {
+ delete str;
+ }
+}
+
+void ASCIIHexEncoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+GBool ASCIIHexEncoder::fillBuf() {
+ static const char *hex = "0123456789abcdef";
+ int c;
+
+ if (eof) {
+ return gFalse;
+ }
+ bufPtr = bufEnd = buf;
+ if ((c = str->getChar()) == EOF) {
+ *bufEnd++ = '>';
+ eof = gTrue;
+ } else {
+ if (lineLen >= 64) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ *bufEnd++ = hex[(c >> 4) & 0x0f];
+ *bufEnd++ = hex[c & 0x0f];
+ lineLen += 2;
+ }
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// ASCII85Encoder
+//------------------------------------------------------------------------
+
+ASCII85Encoder::ASCII85Encoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+ASCII85Encoder::~ASCII85Encoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void ASCII85Encoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+GBool ASCII85Encoder::fillBuf() {
+ Guint t;
+ char buf1[5];
+ int c0, c1, c2, c3;
+ int n, i;
+
+ if (eof) {
+ return gFalse;
+ }
+ c0 = str->getChar();
+ c1 = str->getChar();
+ c2 = str->getChar();
+ c3 = str->getChar();
+ bufPtr = bufEnd = buf;
+ if (c3 == EOF) {
+ if (c0 == EOF) {
+ n = 0;
+ t = 0;
+ } else {
+ if (c1 == EOF) {
+ n = 1;
+ t = c0 << 24;
+ } else if (c2 == EOF) {
+ n = 2;
+ t = (c0 << 24) | (c1 << 16);
+ } else {
+ n = 3;
+ t = (c0 << 24) | (c1 << 16) | (c2 << 8);
+ }
+ for (i = 4; i >= 0; --i) {
+ buf1[i] = (char)(t % 85 + 0x21);
+ t /= 85;
+ }
+ for (i = 0; i <= n; ++i) {
+ *bufEnd++ = buf1[i];
+ if (++lineLen == 65) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ }
+ }
+ *bufEnd++ = '~';
+ *bufEnd++ = '>';
+ eof = gTrue;
+ } else {
+ t = (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
+ if (t == 0) {
+ *bufEnd++ = 'z';
+ if (++lineLen == 65) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ } else {
+ for (i = 4; i >= 0; --i) {
+ buf1[i] = (char)(t % 85 + 0x21);
+ t /= 85;
+ }
+ for (i = 0; i <= 4; ++i) {
+ *bufEnd++ = buf1[i];
+ if (++lineLen == 65) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ }
+ }
+ }
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// RunLengthEncoder
+//------------------------------------------------------------------------
+
+RunLengthEncoder::RunLengthEncoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = nextEnd = buf;
+ eof = gFalse;
+}
+
+RunLengthEncoder::~RunLengthEncoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void RunLengthEncoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = nextEnd = buf;
+ eof = gFalse;
+}
+
+//
+// When fillBuf finishes, buf[] looks like this:
+// +-----+--------------+-----------------+--
+// + tag | ... data ... | next 0, 1, or 2 |
+// +-----+--------------+-----------------+--
+// ^ ^ ^
+// bufPtr bufEnd nextEnd
+//
+GBool RunLengthEncoder::fillBuf() {
+ int c, c1, c2;
+ int n;
+
+ // already hit EOF?
+ if (eof)
+ return gFalse;
+
+ // grab two bytes
+ if (nextEnd < bufEnd + 1) {
+ if ((c1 = str->getChar()) == EOF) {
+ eof = gTrue;
+ return gFalse;
+ }
+ } else {
+ c1 = bufEnd[0] & 0xff;
+ }
+ if (nextEnd < bufEnd + 2) {
+ if ((c2 = str->getChar()) == EOF) {
+ eof = gTrue;
+ buf[0] = 0;
+ buf[1] = c1;
+ bufPtr = buf;
+ bufEnd = &buf[2];
+ return gTrue;
+ }
+ } else {
+ c2 = bufEnd[1] & 0xff;
+ }
+
+ // check for repeat
+ c = 0; // make gcc happy
+ if (c1 == c2) {
+ n = 2;
+ while (n < 128 && (c = str->getChar()) == c1)
+ ++n;
+ buf[0] = (char)(257 - n);
+ buf[1] = c1;
+ bufEnd = &buf[2];
+ if (c == EOF) {
+ eof = gTrue;
+ } else if (n < 128) {
+ buf[2] = c;
+ nextEnd = &buf[3];
+ } else {
+ nextEnd = bufEnd;
+ }
+
+ // get up to 128 chars
+ } else {
+ buf[1] = c1;
+ buf[2] = c2;
+ n = 2;
+ while (n < 128) {
+ if ((c = str->getChar()) == EOF) {
+ eof = gTrue;
+ break;
+ }
+ ++n;
+ buf[n] = c;
+ if (buf[n] == buf[n-1])
+ break;
+ }
+ if (buf[n] == buf[n-1]) {
+ buf[0] = (char)(n-2-1);
+ bufEnd = &buf[n-1];
+ nextEnd = &buf[n+1];
+ } else {
+ buf[0] = (char)(n-1);
+ bufEnd = nextEnd = &buf[n+1];
+ }
+ }
+ bufPtr = buf;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// CMYKGrayEncoder
+//------------------------------------------------------------------------
+
+CMYKGrayEncoder::CMYKGrayEncoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+CMYKGrayEncoder::~CMYKGrayEncoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void CMYKGrayEncoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+GBool CMYKGrayEncoder::fillBuf() {
+ int c0, c1, c2, c3;
+ int i;
+
+ if (eof) {
+ return gFalse;
+ }
+ c0 = str->getChar();
+ c1 = str->getChar();
+ c2 = str->getChar();
+ c3 = str->getChar();
+ if (c3 == EOF) {
+ eof = gTrue;
+ return gFalse;
+ }
+ i = (3 * c0 + 6 * c1 + c2) / 10 + c3;
+ if (i > 255) i = 255;
+ bufPtr = bufEnd = buf;
+ *bufEnd++ = (char) i;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// RGBGrayEncoder
+//------------------------------------------------------------------------
+
+RGBGrayEncoder::RGBGrayEncoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+RGBGrayEncoder::~RGBGrayEncoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void RGBGrayEncoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+GBool RGBGrayEncoder::fillBuf() {
+ int c0, c1, c2;
+ int i;
+
+ if (eof) {
+ return gFalse;
+ }
+ c0 = str->getChar();
+ c1 = str->getChar();
+ c2 = str->getChar();
+ if (c2 == EOF) {
+ eof = gTrue;
+ return gFalse;
+ }
+ i = 255 - (3 * c0 + 6 * c1 + c2) / 10;
+ if (i < 0) i = 0;
+ bufPtr = bufEnd = buf;
+ *bufEnd++ = (char) i;
+ return gTrue;
+}
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream.h
new file mode 100644
index 00000000000..00b2925b3d5
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/Stream.h
@@ -0,0 +1,1258 @@
+//========================================================================
+//
+// Stream.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net>
+// Copyright (C) 2008, 2010, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2011, 2012 William Bader <williambader@hotmail.com>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Peter Breitenlohner <peb@mppmu.mpg.de>
+// Copyright (C) 2013 Adam Reichold <adamreichold@myopera.com>
+// Copyright (C) 2013 Pino Toscano <pino@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef STREAM_H
+#define STREAM_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include <stdio.h>
+#include "goo/gtypes.h"
+#include "Object.h"
+#include "goo/GooMutex.h"
+
+class GooFile;
+class BaseStream;
+class CachedFile;
+
+//------------------------------------------------------------------------
+
+enum StreamKind {
+ strFile,
+ strCachedFile,
+ strASCIIHex,
+ strASCII85,
+ strLZW,
+ strRunLength,
+ strCCITTFax,
+ strDCT,
+ strFlate,
+ strJBIG2,
+ strJPX,
+ strWeird, // internal-use stream types
+ strCrypt // internal-use to detect decode streams
+};
+
+enum StreamColorSpaceMode {
+ streamCSNone,
+ streamCSDeviceGray,
+ streamCSDeviceRGB,
+ streamCSDeviceCMYK
+};
+
+//------------------------------------------------------------------------
+
+// This is in Stream.h instead of Decrypt.h to avoid really annoying
+// include file dependency loops.
+enum CryptAlgorithm {
+ cryptRC4,
+ cryptAES,
+ cryptAES256
+};
+
+//------------------------------------------------------------------------
+
+typedef struct _ByteRange {
+ Guint offset;
+ Guint length;
+} ByteRange;
+
+//------------------------------------------------------------------------
+// Stream (base class)
+//------------------------------------------------------------------------
+
+class Stream {
+public:
+
+ // Constructor.
+ Stream();
+
+ // Destructor.
+ virtual ~Stream();
+
+ // Reference counting.
+ int incRef();
+ int decRef();
+
+ // Get kind of stream.
+ virtual StreamKind getKind() = 0;
+
+ // Reset stream to beginning.
+ virtual void reset() = 0;
+
+ // Close down the stream.
+ virtual void close();
+
+ inline int doGetChars(int nChars, Guchar *buffer)
+ {
+ if (hasGetChars()) {
+ return getChars(nChars, buffer);
+ } else {
+ for (int i = 0; i < nChars; ++i) {
+ const int c = getChar();
+ if (likely(c != EOF)) buffer[i] = c;
+ else return i;
+ }
+ return nChars;
+ }
+ }
+
+ inline void fillGooString(GooString *s)
+ {
+ Guchar readBuf[4096];
+ int readChars;
+ reset();
+ while ((readChars = doGetChars(4096, readBuf)) != 0) {
+ s->append((const char *)readBuf, readChars);
+ }
+ }
+
+ inline Guchar *toUnsignedChars(int *length, int initialSize = 4096, int sizeIncrement = 4096)
+ {
+ int readChars;
+ Guchar *buf = (Guchar *)gmalloc(initialSize);
+ int size = initialSize;
+ *length = 0;
+ int charsToRead = initialSize;
+ bool continueReading = true;
+ reset();
+ while (continueReading && (readChars = doGetChars(charsToRead, &buf[*length])) != 0) {
+ *length += readChars;
+ if (readChars == charsToRead) {
+ if (lookChar() != EOF) {
+ size += sizeIncrement;
+ charsToRead = sizeIncrement;
+ buf = (Guchar *)grealloc(buf, size);
+ } else {
+ continueReading = false;
+ }
+ } else {
+ continueReading = false;
+ }
+ }
+ return buf;
+ }
+
+ // Get next char from stream.
+ virtual int getChar() = 0;
+
+ // Peek at next char in stream.
+ virtual int lookChar() = 0;
+
+ // Get next char from stream without using the predictor.
+ // This is only used by StreamPredictor.
+ virtual int getRawChar();
+ virtual void getRawChars(int nChars, int *buffer);
+
+ // Get next char directly from stream source, without filtering it
+ virtual int getUnfilteredChar () = 0;
+
+ // Resets the stream without reading anything (even not the headers)
+ // WARNING: Reading the stream with something else than getUnfilteredChar
+ // may lead to unexcepted behaviour until you call reset ()
+ virtual void unfilteredReset () = 0;
+
+ // Get next line from stream.
+ virtual char *getLine(char *buf, int size);
+
+ // Get current position in file.
+ virtual Goffset getPos() = 0;
+
+ // Go to a position in the stream. If <dir> is negative, the
+ // position is from the end of the file; otherwise the position is
+ // from the start of the file.
+ virtual void setPos(Goffset pos, int dir = 0) = 0;
+
+ // Get PostScript command for the filter(s).
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+
+ // Does this stream type potentially contain non-printable chars?
+ virtual GBool isBinary(GBool last = gTrue) = 0;
+
+ // Get the BaseStream of this stream.
+ virtual BaseStream *getBaseStream() = 0;
+
+ // Get the stream after the last decoder (this may be a BaseStream
+ // or a DecryptStream).
+ virtual Stream *getUndecodedStream() = 0;
+
+ // Get the dictionary associated with this stream.
+ virtual Dict *getDict() = 0;
+
+ // Is this an encoding filter?
+ virtual GBool isEncoder() { return gFalse; }
+
+ // Get image parameters which are defined by the stream contents.
+ virtual void getImageParams(int * /*bitsPerComponent*/,
+ StreamColorSpaceMode * /*csMode*/) {}
+
+ // Return the next stream in the "stack".
+ virtual Stream *getNextStream() { return NULL; }
+
+ // Add filters to this stream according to the parameters in <dict>.
+ // Returns the new stream.
+ Stream *addFilters(Object *dict, int recursion = 0);
+
+private:
+ virtual GBool hasGetChars() { return false; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ Stream *makeFilter(char *name, Stream *str, Object *params, int recursion = 0, Object *dict = NULL);
+
+ int ref; // reference count
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+
+ //------------------------------------------------------------------------
+// OutStream
+//
+// This is the base class for all streams that output to a file
+//------------------------------------------------------------------------
+class OutStream {
+public:
+ // Constructor.
+ OutStream ();
+
+ // Desctructor.
+ virtual ~OutStream ();
+
+ // Reference counting.
+ int incRef() { return ++ref; }
+ int decRef() { return --ref; }
+
+ // Close the stream
+ virtual void close() = 0;
+
+ // Return position in stream
+ virtual Goffset getPos() = 0;
+
+ // Put a char in the stream
+ virtual void put (char c) = 0;
+
+ virtual void printf (const char *format, ...) GCC_PRINTF_FORMAT(2,3) = 0;
+
+private:
+ int ref; // reference count
+
+};
+
+//------------------------------------------------------------------------
+// FileOutStream
+//------------------------------------------------------------------------
+class FileOutStream : public OutStream {
+public:
+ FileOutStream (FILE* fa, Goffset startA);
+
+ virtual ~FileOutStream ();
+
+ virtual void close();
+
+ virtual Goffset getPos();
+
+ virtual void put (char c);
+
+ virtual void printf (const char *format, ...);
+private:
+ FILE *f;
+ Goffset start;
+
+};
+
+
+//------------------------------------------------------------------------
+// BaseStream
+//
+// This is the base class for all streams that read directly from a file.
+//------------------------------------------------------------------------
+
+class BaseStream: public Stream {
+public:
+
+ BaseStream(Object *dictA, Goffset lengthA);
+ virtual ~BaseStream();
+ virtual BaseStream *copy() = 0;
+ virtual Stream *makeSubStream(Goffset start, GBool limited,
+ Goffset length, Object *dict) = 0;
+ virtual void setPos(Goffset 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 GooString *getFileName() { return NULL; }
+ virtual Goffset getLength() { return length; }
+
+ // Get/set position of first byte of stream within the file.
+ virtual Goffset getStart() = 0;
+ virtual void moveStart(Goffset delta) = 0;
+
+protected:
+
+ Goffset length;
+ Object dict;
+};
+
+//------------------------------------------------------------------------
+// FilterStream
+//
+// This is the base class for all streams that filter another stream.
+//------------------------------------------------------------------------
+
+class FilterStream: public Stream {
+public:
+
+ FilterStream(Stream *strA);
+ virtual ~FilterStream();
+ virtual void close();
+ virtual Goffset getPos() { return str->getPos(); }
+ virtual void setPos(Goffset 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; }
+
+ virtual int getUnfilteredChar () { return str->getUnfilteredChar(); }
+ virtual void unfilteredReset () { str->unfilteredReset(); }
+
+protected:
+
+ Stream *str;
+};
+
+//------------------------------------------------------------------------
+// ImageStream
+//------------------------------------------------------------------------
+
+class ImageStream {
+public:
+
+ // Create an image stream object for an image with the specified
+ // parameters. Note that these are the actual image parameters,
+ // which may be different from the predictor parameters.
+ ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA);
+
+ ~ImageStream();
+
+ // Reset the stream.
+ void reset();
+
+ // Close the stream previously reset
+ void close();
+
+ // Gets the next pixel from the stream. <pix> should be able to hold
+ // at least nComps elements. Returns false at end of file.
+ GBool getPixel(Guchar *pix);
+
+ // Returns a pointer to the next line of pixels. Returns NULL at
+ // end of file.
+ Guchar *getLine();
+
+ // Skip an entire line from the image.
+ void skipLine();
+
+private:
+
+ Stream *str; // base stream
+ int width; // pixels per line
+ int nComps; // components per pixel
+ int nBits; // bits per component
+ int nVals; // components per line
+ int inputLineSize; // input line buffer size
+ Guchar *inputLine; // input line buffer
+ Guchar *imgLine; // line buffer
+ int imgIdx; // current index in imgLine
+};
+
+//------------------------------------------------------------------------
+// StreamPredictor
+//------------------------------------------------------------------------
+
+class StreamPredictor {
+public:
+
+ // Create a predictor object. Note that the parameters are for the
+ // predictor, and may not match the actual image parameters.
+ StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA);
+
+ ~StreamPredictor();
+
+ GBool isOk() { return ok; }
+
+ int lookChar();
+ int getChar();
+ int getChars(int nChars, Guchar *buffer);
+
+private:
+
+ GBool getNextLine();
+
+ Stream *str; // base stream
+ int predictor; // predictor
+ int width; // pixels per line
+ int nComps; // components per pixel
+ int nBits; // bits per component
+ int nVals; // components per line
+ int pixBytes; // bytes per pixel
+ int rowBytes; // bytes per line
+ Guchar *predLine; // line buffer
+ int predIdx; // current index in predLine
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// FileStream
+//------------------------------------------------------------------------
+
+#define fileStreamBufSize 256
+
+class FileStream: public BaseStream {
+public:
+
+ FileStream(GooFile* fileA, Goffset startA, GBool limitedA,
+ Goffset lengthA, Object *dictA);
+ virtual ~FileStream();
+ virtual BaseStream *copy();
+ virtual Stream *makeSubStream(Goffset startA, GBool limitedA,
+ Goffset lengthA, Object *dictA);
+ virtual StreamKind getKind() { return strFile; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual Goffset getPos() { return bufPos + (bufPtr - buf); }
+ virtual void setPos(Goffset pos, int dir = 0);
+ virtual Goffset getStart() { return start; }
+ virtual void moveStart(Goffset delta);
+
+ virtual int getUnfilteredChar () { return getChar(); }
+ virtual void unfilteredReset () { reset(); }
+
+private:
+
+ GBool fillBuf();
+
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer)
+ {
+ int n, m;
+
+ n = 0;
+ while (n < nChars) {
+ if (bufPtr >= bufEnd) {
+ if (!fillBuf()) {
+ break;
+ }
+ }
+ m = (int)(bufEnd - bufPtr);
+ if (m > nChars - n) {
+ m = nChars - n;
+ }
+ memcpy(buffer + n, bufPtr, m);
+ bufPtr += m;
+ n += m;
+ }
+ return n;
+ }
+
+private:
+ GooFile* file;
+ Goffset offset;
+ Goffset start;
+ GBool limited;
+ char buf[fileStreamBufSize];
+ char *bufPtr;
+ char *bufEnd;
+ Goffset bufPos;
+ Goffset savePos;
+ GBool saved;
+};
+
+//------------------------------------------------------------------------
+// CachedFileStream
+//------------------------------------------------------------------------
+
+#define cachedStreamBufSize 1024
+
+class CachedFileStream: public BaseStream {
+public:
+
+ CachedFileStream(CachedFile *ccA, Goffset startA, GBool limitedA,
+ Goffset lengthA, Object *dictA);
+ virtual ~CachedFileStream();
+ virtual BaseStream *copy();
+ virtual Stream *makeSubStream(Goffset startA, GBool limitedA,
+ Goffset lengthA, Object *dictA);
+ virtual StreamKind getKind() { return strCachedFile; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual Goffset getPos() { return bufPos + (bufPtr - buf); }
+ virtual void setPos(Goffset pos, int dir = 0);
+ virtual Goffset getStart() { return start; }
+ virtual void moveStart(Goffset delta);
+
+ virtual int getUnfilteredChar () { return getChar(); }
+ virtual void unfilteredReset () { reset(); }
+
+private:
+
+ GBool fillBuf();
+
+ CachedFile *cc;
+ Goffset start;
+ GBool limited;
+ char buf[cachedStreamBufSize];
+ char *bufPtr;
+ char *bufEnd;
+ Guint bufPos;
+ int savePos;
+ GBool saved;
+};
+
+
+//------------------------------------------------------------------------
+// MemStream
+//------------------------------------------------------------------------
+
+class MemStream: public BaseStream {
+public:
+
+ MemStream(char *bufA, Goffset startA, Goffset lengthA, Object *dictA);
+ virtual ~MemStream();
+ virtual BaseStream *copy();
+ virtual Stream *makeSubStream(Goffset start, GBool limited,
+ Goffset lengthA, Object *dictA);
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; }
+ virtual int lookChar()
+ { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; }
+ virtual Goffset getPos() { return (int)(bufPtr - buf); }
+ virtual void setPos(Goffset pos, int dir = 0);
+ virtual Goffset getStart() { return start; }
+ virtual void moveStart(Goffset delta);
+
+ //if needFree = true, the stream will delete buf when it is destroyed
+ //otherwise it will not touch it. Default value is false
+ virtual void setNeedFree (GBool val) { needFree = val; }
+
+ virtual int getUnfilteredChar () { return getChar(); }
+ virtual void unfilteredReset () { reset (); }
+
+private:
+
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ char *buf;
+ Goffset start;
+ char *bufEnd;
+ char *bufPtr;
+ GBool needFree;
+};
+
+//------------------------------------------------------------------------
+// EmbedStream
+//
+// This is a special stream type used for embedded streams (inline
+// images). It reads directly from the base stream -- after the
+// EmbedStream is deleted, reads from the base stream will proceed where
+// the BaseStream left off. Note that this is very different behavior
+// that creating a new FileStream (using makeSubStream).
+//------------------------------------------------------------------------
+
+class EmbedStream: public BaseStream {
+public:
+
+ EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Goffset lengthA);
+ virtual ~EmbedStream();
+ virtual BaseStream *copy();
+ virtual Stream *makeSubStream(Goffset start, GBool limitedA,
+ Goffset lengthA, Object *dictA);
+ virtual StreamKind getKind() { return str->getKind(); }
+ virtual void reset() {}
+ virtual int getChar();
+ virtual int lookChar();
+ virtual Goffset getPos() { return str->getPos(); }
+ virtual void setPos(Goffset pos, int dir = 0);
+ virtual Goffset getStart();
+ virtual void moveStart(Goffset delta);
+
+ virtual int getUnfilteredChar () { return str->getUnfilteredChar(); }
+ virtual void unfilteredReset () { str->unfilteredReset(); }
+
+
+private:
+
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ Stream *str;
+ GBool limited;
+};
+
+//------------------------------------------------------------------------
+// ASCIIHexStream
+//------------------------------------------------------------------------
+
+class ASCIIHexStream: public FilterStream {
+public:
+
+ ASCIIHexStream(Stream *strA);
+ virtual ~ASCIIHexStream();
+ virtual StreamKind getKind() { return strASCIIHex; }
+ virtual void reset();
+ virtual int getChar()
+ { int c = lookChar(); buf = EOF; return c; }
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ int buf;
+ GBool eof;
+};
+
+//------------------------------------------------------------------------
+// ASCII85Stream
+//------------------------------------------------------------------------
+
+class ASCII85Stream: public FilterStream {
+public:
+
+ ASCII85Stream(Stream *strA);
+ virtual ~ASCII85Stream();
+ virtual StreamKind getKind() { return strASCII85; }
+ virtual void reset();
+ virtual int getChar()
+ { int ch = lookChar(); ++index; return ch; }
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ int c[5];
+ int b[4];
+ int index, n;
+ GBool eof;
+};
+
+//------------------------------------------------------------------------
+// LZWStream
+//------------------------------------------------------------------------
+
+class LZWStream: public FilterStream {
+public:
+
+ LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA);
+ virtual ~LZWStream();
+ virtual StreamKind getKind() { return strLZW; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual int getRawChar();
+ virtual void getRawChars(int nChars, int *buffer);
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ inline int doGetRawChar() {
+ if (eof) {
+ return EOF;
+ }
+ if (seqIndex >= seqLength) {
+ if (!processNextCode()) {
+ return EOF;
+ }
+ }
+ return seqBuf[seqIndex++];
+ }
+
+ StreamPredictor *pred; // predictor
+ int early; // early parameter
+ GBool eof; // true if at eof
+ int inputBuf; // input buffer
+ int inputBits; // number of bits in input buffer
+ struct { // decoding table
+ int length;
+ int head;
+ Guchar tail;
+ } table[4097];
+ int nextCode; // next code to be used
+ int nextBits; // number of bits in next code word
+ int prevCode; // previous code used in stream
+ int newChar; // next char to be added to table
+ Guchar seqBuf[4097]; // buffer for current sequence
+ int seqLength; // length of current sequence
+ int seqIndex; // index into current sequence
+ GBool first; // first code after a table clear
+
+ GBool processNextCode();
+ void clearTable();
+ int getCode();
+};
+
+//------------------------------------------------------------------------
+// RunLengthStream
+//------------------------------------------------------------------------
+
+class RunLengthStream: public FilterStream {
+public:
+
+ RunLengthStream(Stream *strA);
+ virtual ~RunLengthStream();
+ virtual StreamKind getKind() { return strRunLength; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ char buf[128]; // buffer
+ char *bufPtr; // next char to read
+ char *bufEnd; // end of buffer
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// CCITTFaxStream
+//------------------------------------------------------------------------
+
+struct CCITTCodeTable;
+
+class CCITTFaxStream: public FilterStream {
+public:
+
+ CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA);
+ virtual ~CCITTFaxStream();
+ virtual StreamKind getKind() { return strCCITTFax; }
+ virtual void reset();
+ virtual int getChar()
+ { int c = lookChar(); buf = EOF; return c; }
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+ virtual void unfilteredReset ();
+
+ int getEncoding() { return encoding; }
+ GBool getEndOfLine() { return endOfLine; }
+ int getColumns() { return columns; }
+ GBool getBlackIs1() { return black; }
+
+private:
+
+ void ccittReset(GBool unfiltered);
+ int encoding; // 'K' parameter
+ GBool endOfLine; // 'EndOfLine' parameter
+ GBool byteAlign; // 'EncodedByteAlign' parameter
+ int columns; // 'Columns' parameter
+ int rows; // 'Rows' parameter
+ GBool endOfBlock; // 'EndOfBlock' parameter
+ GBool black; // 'BlackIs1' parameter
+ GBool eof; // true if at eof
+ GBool nextLine2D; // true if next line uses 2D encoding
+ int row; // current row
+ Guint inputBuf; // input buffer
+ int inputBits; // number of bits in input buffer
+ int *codingLine; // coding line changing elements
+ int *refLine; // reference line changing elements
+ int a0i; // index into codingLine
+ GBool err; // error on current line
+ int outputBits; // remaining ouput bits
+ int buf; // character buffer
+
+ void addPixels(int a1, int blackPixels);
+ void addPixelsNeg(int a1, int blackPixels);
+ short getTwoDimCode();
+ short getWhiteCode();
+ short getBlackCode();
+ short lookBits(int n);
+ void eatBits(int n) { if ((inputBits -= n) < 0) inputBits = 0; }
+};
+
+#ifndef ENABLE_LIBJPEG
+//------------------------------------------------------------------------
+// DCTStream
+//------------------------------------------------------------------------
+
+// DCT component info
+struct DCTCompInfo {
+ int id; // component ID
+ int hSample, vSample; // horiz/vert sampling resolutions
+ int quantTable; // quantization table number
+ int prevDC; // DC coefficient accumulator
+};
+
+struct DCTScanInfo {
+ GBool comp[4]; // comp[i] is set if component i is
+ // included in this scan
+ int numComps; // number of components in the scan
+ int dcHuffTable[4]; // DC Huffman table numbers
+ int acHuffTable[4]; // AC Huffman table numbers
+ int firstCoeff, lastCoeff; // first and last DCT coefficient
+ int ah, al; // successive approximation parameters
+};
+
+// DCT Huffman decoding table
+struct DCTHuffTable {
+ Guchar firstSym[17]; // first symbol for this bit length
+ Gushort firstCode[17]; // first code for this bit length
+ Gushort numCodes[17]; // number of codes of this bit length
+ Guchar sym[256]; // symbols
+};
+
+class DCTStream: public FilterStream {
+public:
+
+ DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion);
+ virtual ~DCTStream();
+ virtual StreamKind getKind() { return strDCT; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+ virtual void unfilteredReset();
+
+private:
+
+ void dctReset(GBool unfiltered);
+ GBool progressive; // set if in progressive mode
+ GBool interleaved; // set if in interleaved mode
+ int width, height; // image size
+ int mcuWidth, mcuHeight; // size of min coding unit, in data units
+ int bufWidth, bufHeight; // frameBuf size
+ DCTCompInfo compInfo[4]; // info for each component
+ DCTScanInfo scanInfo; // info for the current scan
+ int numComps; // number of components in image
+ int colorXform; // color transform: -1 = unspecified
+ // 0 = none
+ // 1 = YUV/YUVK -> RGB/CMYK
+ GBool gotJFIFMarker; // set if APP0 JFIF marker was present
+ GBool gotAdobeMarker; // set if APP14 Adobe marker was present
+ int restartInterval; // restart interval, in MCUs
+ Gushort quantTables[4][64]; // quantization tables
+ int numQuantTables; // number of quantization tables
+ DCTHuffTable dcHuffTables[4]; // DC Huffman tables
+ DCTHuffTable acHuffTables[4]; // AC Huffman tables
+ int numDCHuffTables; // number of DC Huffman tables
+ int numACHuffTables; // number of AC Huffman tables
+ Guchar *rowBuf[4][32]; // buffer for one MCU (non-progressive mode)
+ int *frameBuf[4]; // buffer for frame (progressive mode)
+ int comp, x, y, dy; // current position within image/MCU
+ int restartCtr; // MCUs left until restart
+ int restartMarker; // next restart marker
+ int eobRun; // number of EOBs left in the current run
+ int inputBuf; // input buffer for variable length codes
+ int inputBits; // number of valid bits in input buffer
+
+ void restart();
+ GBool readMCURow();
+ void readScan();
+ GBool readDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ int *prevDC, int data[64]);
+ GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ int *prevDC, int data[64]);
+ void decodeImage();
+ void transformDataUnit(Gushort *quantTable,
+ int dataIn[64], Guchar dataOut[64]);
+ int readHuffSym(DCTHuffTable *table);
+ int readAmp(int size);
+ int readBit();
+ GBool readHeader();
+ GBool readBaselineSOF();
+ GBool readProgressiveSOF();
+ GBool readScanInfo();
+ GBool readQuantTables();
+ GBool readHuffmanTables();
+ GBool readRestartInterval();
+ GBool readJFIFMarker();
+ GBool readAdobeMarker();
+ GBool readTrailer();
+ int readMarker();
+ int read16();
+};
+
+#endif
+
+#ifndef ENABLE_ZLIB
+//------------------------------------------------------------------------
+// FlateStream
+//------------------------------------------------------------------------
+
+#define flateWindow 32768 // buffer size
+#define flateMask (flateWindow-1)
+#define flateMaxHuffman 15 // max Huffman code length
+#define flateMaxCodeLenCodes 19 // max # code length codes
+#define flateMaxLitCodes 288 // max # literal codes
+#define flateMaxDistCodes 30 // max # distance codes
+
+// Huffman code table entry
+struct FlateCode {
+ Gushort len; // code length, in bits
+ Gushort val; // value represented by this code
+};
+
+struct FlateHuffmanTab {
+ FlateCode *codes;
+ int maxLen;
+};
+
+// Decoding info for length and distance code words
+struct FlateDecode {
+ int bits; // # extra bits
+ int first; // first length/distance
+};
+
+class FlateStream: public FilterStream {
+public:
+
+ FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits);
+ virtual ~FlateStream();
+ virtual StreamKind getKind() { return strFlate; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual int getRawChar();
+ virtual void getRawChars(int nChars, int *buffer);
+ virtual GooString *getPSFilter(int psLevel, const char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+ virtual void unfilteredReset ();
+
+private:
+ void flateReset(GBool unfiltered);
+ inline int doGetRawChar() {
+ int c;
+
+ while (remain == 0) {
+ if (endOfBlock && eof)
+ return EOF;
+ readSome();
+ }
+ c = buf[index];
+ index = (index + 1) & flateMask;
+ --remain;
+ return c;
+ }
+
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ StreamPredictor *pred; // predictor
+ Guchar buf[flateWindow]; // output data buffer
+ int index; // current index into output buffer
+ int remain; // number valid bytes in output buffer
+ int codeBuf; // input buffer
+ int codeSize; // number of bits in input buffer
+ int // literal and distance code lengths
+ codeLengths[flateMaxLitCodes + flateMaxDistCodes];
+ FlateHuffmanTab litCodeTab; // literal code table
+ FlateHuffmanTab distCodeTab; // distance code table
+ GBool compressedBlock; // set if reading a compressed block
+ int blockLen; // remaining length of uncompressed block
+ GBool endOfBlock; // set when end of block is reached
+ GBool eof; // set when end of stream is reached
+
+ static int // code length code reordering
+ codeLenCodeMap[flateMaxCodeLenCodes];
+ static FlateDecode // length decoding info
+ lengthDecode[flateMaxLitCodes-257];
+ static FlateDecode // distance decoding info
+ distDecode[flateMaxDistCodes];
+ static FlateHuffmanTab // fixed literal code table
+ fixedLitCodeTab;
+ static FlateHuffmanTab // fixed distance code table
+ fixedDistCodeTab;
+
+ void readSome();
+ GBool startBlock();
+ void loadFixedCodes();
+ GBool readDynamicCodes();
+ void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab);
+ int getHuffmanCodeWord(FlateHuffmanTab *tab);
+ int getCodeWord(int bits);
+};
+#endif
+
+//------------------------------------------------------------------------
+// EOFStream
+//------------------------------------------------------------------------
+
+class EOFStream: public FilterStream {
+public:
+
+ EOFStream(Stream *strA);
+ virtual ~EOFStream();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset() {}
+ virtual int getChar() { return EOF; }
+ virtual int lookChar() { return EOF; }
+ virtual GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last = gTrue*/) { return gFalse; }
+};
+
+//------------------------------------------------------------------------
+// BufStream
+//------------------------------------------------------------------------
+
+class BufStream: public FilterStream {
+public:
+
+ BufStream(Stream *strA, int bufSizeA);
+ virtual ~BufStream();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int psLevel, const char *indent)
+ { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue);
+
+ int lookChar(int idx);
+
+private:
+
+ int *buf;
+ int bufSize;
+};
+
+//------------------------------------------------------------------------
+// FixedLengthEncoder
+//------------------------------------------------------------------------
+
+class FixedLengthEncoder: public FilterStream {
+public:
+
+ FixedLengthEncoder(Stream *strA, int lengthA);
+ ~FixedLengthEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last = gTrue*/);
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ int length;
+ int count;
+};
+
+//------------------------------------------------------------------------
+// ASCIIHexEncoder
+//------------------------------------------------------------------------
+
+class ASCIIHexEncoder: public FilterStream {
+public:
+
+ ASCIIHexEncoder(Stream *strA);
+ virtual ~ASCIIHexEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last = gTrue*/) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[4];
+ char *bufPtr;
+ char *bufEnd;
+ int lineLen;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// ASCII85Encoder
+//------------------------------------------------------------------------
+
+class ASCII85Encoder: public FilterStream {
+public:
+
+ ASCII85Encoder(Stream *strA);
+ virtual ~ASCII85Encoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last = gTrue*/) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[8];
+ char *bufPtr;
+ char *bufEnd;
+ int lineLen;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// RunLengthEncoder
+//------------------------------------------------------------------------
+
+class RunLengthEncoder: public FilterStream {
+public:
+
+ RunLengthEncoder(Stream *strA);
+ virtual ~RunLengthEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last = gTrue*/) { return gTrue; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[131];
+ char *bufPtr;
+ char *bufEnd;
+ char *nextEnd;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// CMYKGrayEncoder
+//------------------------------------------------------------------------
+
+class CMYKGrayEncoder: public FilterStream {
+public:
+
+ CMYKGrayEncoder(Stream *strA);
+ virtual ~CMYKGrayEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last = gTrue*/) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[2];
+ char *bufPtr;
+ char *bufEnd;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// RGBGrayEncoder
+//------------------------------------------------------------------------
+
+class RGBGrayEncoder: public FilterStream {
+public:
+
+ RGBGrayEncoder(Stream *strA);
+ virtual ~RGBGrayEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last = gTrue*/) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[2];
+ char *bufPtr;
+ char *bufEnd;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/StructElement.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/StructElement.cc
new file mode 100644
index 00000000000..c6688208fee
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/StructElement.cc
@@ -0,0 +1,1409 @@
+//========================================================================
+//
+// StructElement.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2013, 2014 Igalia S.L.
+// Copyright 2014 Luigi Scarso <luigi.scarso@gmail.com>
+// Copyright 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright 2015 Dmytro Morgun <lztoad@gmail.com>
+//
+//========================================================================
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "StructElement.h"
+#include "StructTreeRoot.h"
+#include "GlobalParams.h"
+#include "UnicodeMap.h"
+#include "PDFDoc.h"
+#include "Dict.h"
+
+#include <assert.h>
+
+class GfxState;
+
+
+static GBool isPlacementName(Object *value)
+{
+ return value->isName("Block")
+ || value->isName("Inline")
+ || value->isName("Before")
+ || value->isName("Start")
+ || value->isName("End");
+}
+
+static GBool isWritingModeName(Object *value)
+{
+ return value->isName("LrTb")
+ || value->isName("RlTb")
+ || value->isName("TbRl");
+}
+
+static GBool isBorderStyleName(Object *value)
+{
+ return value->isName("None")
+ || value->isName("Hidden")
+ || value->isName("Dotted")
+ || value->isName("Dashed")
+ || value->isName("Solid")
+ || value->isName("Double")
+ || value->isName("Groove")
+ || value->isName("Ridge")
+ || value->isName("Inset")
+ || value->isName("Outset");
+}
+
+static GBool isTextAlignName(Object *value)
+{
+ return value->isName("Start")
+ || value->isName("End")
+ || value->isName("Center")
+ || value->isName("Justify");
+}
+
+static GBool isBlockAlignName(Object *value)
+{
+ return value->isName("Before")
+ || value->isName("Middle")
+ || value->isName("After")
+ || value->isName("Justify");
+}
+
+static GBool isInlineAlignName(Object *value)
+{
+ return value->isName("Start")
+ || value->isName("End")
+ || value->isName("Center");
+}
+
+static GBool isNumber(Object *value)
+{
+ return value->isNum();
+}
+
+static GBool isLineHeight(Object *value)
+{
+ return value->isName("Normal")
+ || value->isName("Auto")
+ || isNumber(value);
+}
+
+static GBool isTextDecorationName(Object *value)
+{
+ return value->isName("None")
+ || value->isName("Underline")
+ || value->isName("Overline")
+ || value->isName("LineThrough");
+}
+
+static GBool isRubyAlignName(Object *value)
+{
+ return value->isName("Start")
+ || value->isName("End")
+ || value->isName("Center")
+ || value->isName("Justify")
+ || value->isName("Distribute");
+}
+
+static GBool isRubyPositionName(Object *value)
+{
+ return value->isName("Before")
+ || value->isName("After")
+ || value->isName("Warichu")
+ || value->isName("Inline");
+}
+
+static GBool isGlyphOrientationName(Object *value)
+{
+ return value->isName("Auto")
+ || value->isName("90")
+ || value->isName("180")
+ || value->isName("270")
+ || value->isName("360")
+ || value->isName("-90")
+ || value->isName("-180");
+}
+
+static GBool isListNumberingName(Object *value)
+{
+ return value->isName("None")
+ || value->isName("Disc")
+ || value->isName("Circle")
+ || value->isName("Square")
+ || value->isName("Decimal")
+ || value->isName("UpperRoman")
+ || value->isName("LowerRoman")
+ || value->isName("UpperAlpha")
+ || value->isName("LowerAlpha");
+}
+
+static GBool isFieldRoleName(Object *value)
+{
+ return value->isName("rb")
+ || value->isName("cb")
+ || value->isName("pb")
+ || value->isName("tv");
+}
+
+static GBool isFieldCheckedName(Object *value)
+{
+ return value->isName("on")
+ || value->isName("off")
+ || value->isName("neutral");
+}
+
+static GBool isTableScopeName(Object *value)
+{
+ return value->isName("Row")
+ || value->isName("Column")
+ || value->isName("Both");
+}
+
+static GBool isRGBColor(Object *value)
+{
+ if (!(value->isArray() && value->arrayGetLength() == 3))
+ return gFalse;
+
+ GBool okay = gTrue;
+ for (int i = 0; i < 3; i++) {
+ Object obj;
+ if (!value->arrayGet(i, &obj)->isNum()) {
+ okay = gFalse;
+ obj.free();
+ break;
+ }
+ if (obj.getNum() < 0.0 || obj.getNum() > 1.0) {
+ okay = gFalse;
+ obj.free();
+ break;
+ }
+ obj.free();
+ }
+
+ return okay;
+}
+
+static GBool isNatural(Object *value)
+{
+ return (value->isInt() && value->getInt() > 0)
+ || (value->isInt64() && value->getInt64() > 0);
+}
+
+static GBool isPositive(Object *value)
+{
+ return value->isNum() && value->getNum() >= 0.0;
+}
+
+static GBool isNumberOrAuto(Object *value)
+{
+ return isNumber(value) || value->isName("Auto");
+}
+
+static GBool isTextString(Object *value)
+{
+ // XXX: Shall isName() also be checked?
+ return value->isString();
+}
+
+
+#define ARRAY_CHECKER(name, checkItem, length, allowSingle, allowNulls) \
+ static GBool name(Object *value) { \
+ if (!value->isArray()) \
+ return allowSingle ? checkItem(value) : gFalse; \
+ \
+ if (length && value->arrayGetLength() != length) \
+ return gFalse; \
+ \
+ GBool okay = gTrue; \
+ for (int i = 0; i < value->arrayGetLength(); i++) { \
+ Object obj; \
+ value->arrayGet(i, &obj); \
+ if ((!allowNulls && obj.isNull()) || !checkItem(&obj)) { \
+ okay = gFalse; \
+ obj.free(); \
+ break; \
+ } \
+ obj.free(); \
+ } \
+ return okay; \
+ }
+
+ARRAY_CHECKER(isRGBColorOrOptionalArray4, isRGBColor, 4, gTrue, gTrue );
+ARRAY_CHECKER(isPositiveOrOptionalArray4, isPositive, 4, gTrue, gTrue );
+ARRAY_CHECKER(isPositiveOrArray4, isPositive, 4, gTrue, gFalse);
+ARRAY_CHECKER(isBorderStyle, isBorderStyleName, 4, gTrue, gTrue );
+ARRAY_CHECKER(isNumberArray4, isNumber, 4, gFalse, gFalse);
+ARRAY_CHECKER(isNumberOrArrayN, isNumber, 0, gTrue, gFalse);
+ARRAY_CHECKER(isTableHeaders, isTextString, 0, gFalse, gFalse);
+
+
+// Type of functions used to do type-checking on attribute values
+typedef GBool (*AttributeCheckFunc)(Object*);
+
+// Maps attributes to their names and whether the attribute can be inherited.
+struct AttributeMapEntry {
+ Attribute::Type type;
+ const char *name;
+ const Object *defval;
+ GBool inherit;
+ AttributeCheckFunc check;
+};
+
+struct AttributeDefaults {
+ Object Inline;
+ Object LrTb;
+ Object Normal;
+ Object Distribute;
+ Object off;
+ Object Zero;
+ Object Auto;
+ Object Start;
+ Object None;
+ Object Before;
+ Object Nat1;
+
+ AttributeDefaults() {
+ Inline.initName("Inline");
+ LrTb.initName("LrTb");
+ Normal.initName("Normal");
+ Distribute.initName("Distribute");
+ off.initName("off");
+
+ Zero.initReal(0.0);
+ Auto.initName("Auto");
+ Start.initName("Start");
+ None.initName("None");
+ Before.initName("Before");
+ Nat1.initInt(1);
+ }
+
+ ~AttributeDefaults() {
+ Inline.free();
+ LrTb.free();
+ Normal.free();
+ Distribute.free();
+ off.free();
+ Zero.free();
+ Auto.free();
+ Start.free();
+ None.free();
+ Before.free();
+ Nat1.free();
+ }
+};
+
+static const AttributeDefaults attributeDefaults;
+
+
+#define ATTR_LIST_END \
+ { Attribute::Unknown, NULL, NULL, gFalse, NULL }
+
+#define ATTR_WITH_DEFAULT(name, inherit, check, defval) \
+ { Attribute::name, \
+ #name, \
+ &attributeDefaults.defval, \
+ inherit, \
+ check }
+
+#define ATTR(name, inherit, check) \
+ { Attribute::name, \
+ #name, \
+ NULL, \
+ inherit, \
+ check }
+
+static const AttributeMapEntry attributeMapCommonShared[] =
+{
+ ATTR_WITH_DEFAULT(Placement, gFalse, isPlacementName, Inline),
+ ATTR_WITH_DEFAULT(WritingMode, gTrue, isWritingModeName, LrTb),
+ ATTR (BackgroundColor, gFalse, isRGBColor),
+ ATTR (BorderColor, gTrue, isRGBColorOrOptionalArray4),
+ ATTR_WITH_DEFAULT(BorderStyle, gFalse, isBorderStyle, None),
+ ATTR (BorderThickness, gTrue, isPositiveOrOptionalArray4),
+ ATTR_WITH_DEFAULT(Padding, gFalse, isPositiveOrArray4, Zero),
+ ATTR (Color, gTrue, isRGBColor),
+ ATTR_LIST_END
+};
+
+static const AttributeMapEntry attributeMapCommonBlock[] =
+{
+ ATTR_WITH_DEFAULT(SpaceBefore, gFalse, isPositive, Zero),
+ ATTR_WITH_DEFAULT(SpaceAfter, gFalse, isPositive, Zero),
+ ATTR_WITH_DEFAULT(StartIndent, gTrue, isNumber, Zero),
+ ATTR_WITH_DEFAULT(EndIndent, gTrue, isNumber, Zero),
+ ATTR_WITH_DEFAULT(TextIndent, gTrue, isNumber, Zero),
+ ATTR_WITH_DEFAULT(TextAlign, gTrue, isTextAlignName, Start),
+ ATTR (BBox, gFalse, isNumberArray4),
+ ATTR_WITH_DEFAULT(Width, gFalse, isNumberOrAuto, Auto),
+ ATTR_WITH_DEFAULT(Height, gFalse, isNumberOrAuto, Auto),
+ ATTR_WITH_DEFAULT(BlockAlign, gTrue, isBlockAlignName, Before),
+ ATTR_WITH_DEFAULT(InlineAlign, gTrue, isInlineAlignName, Start),
+ ATTR_LIST_END
+};
+
+static const AttributeMapEntry attributeMapCommonInline[] =
+{
+ ATTR_WITH_DEFAULT(BaselineShift, gFalse, isNumber, Zero),
+ ATTR_WITH_DEFAULT(LineHeight, gTrue, isLineHeight, Normal),
+ ATTR (TextDecorationColor, gTrue, isRGBColor),
+ ATTR (TextDecorationThickness, gTrue, isPositive),
+ ATTR_WITH_DEFAULT(TextDecorationType, gFalse, isTextDecorationName, None),
+ ATTR_WITH_DEFAULT(GlyphOrientationVertical, gTrue, isGlyphOrientationName, Auto),
+ ATTR_LIST_END
+};
+
+static const AttributeMapEntry attributeMapCommonRubyText[] =
+{
+ ATTR_WITH_DEFAULT(RubyPosition, gTrue, isRubyPositionName, Before),
+ ATTR_WITH_DEFAULT(RubyAlign, gTrue, isRubyAlignName, Distribute),
+ ATTR_LIST_END
+};
+
+static const AttributeMapEntry attributeMapCommonColumns[] =
+{
+ ATTR_WITH_DEFAULT(ColumnCount, gFalse, isNatural, Nat1),
+ ATTR (ColumnGap, gFalse, isNumberOrArrayN),
+ ATTR (ColumnWidths, gFalse, isNumberOrArrayN),
+ ATTR_LIST_END
+};
+
+static const AttributeMapEntry attributeMapCommonList[] = {
+ ATTR_WITH_DEFAULT(ListNumbering, gTrue, isListNumberingName, None),
+ ATTR_LIST_END
+};
+
+static const AttributeMapEntry attributeMapCommonPrintField[] =
+{
+ ATTR (Role, gFalse, isFieldRoleName),
+ ATTR_WITH_DEFAULT(checked, gFalse, isFieldCheckedName, off),
+ ATTR (Desc, gFalse, isTextString),
+ ATTR_LIST_END
+};
+
+static const AttributeMapEntry attributeMapCommonTable[] =
+{
+ ATTR(Headers, gFalse, isTableHeaders),
+ ATTR(Scope, gFalse, isTableScopeName),
+ ATTR(Summary, gFalse, isTextString),
+ ATTR_LIST_END
+};
+
+static const AttributeMapEntry attributeMapCommonTableCell[] =
+{
+ ATTR_WITH_DEFAULT(RowSpan, gFalse, isNatural, Nat1),
+ ATTR_WITH_DEFAULT(ColSpan, gFalse, isNatural, Nat1),
+ ATTR_WITH_DEFAULT(TBorderStyle, gTrue, isBorderStyle, None),
+ ATTR_WITH_DEFAULT(TPadding, gTrue, isPositiveOrArray4, Zero),
+ ATTR_LIST_END
+};
+
+#undef ATTR_WITH_DEFAULT
+#undef ATTR
+
+
+static const AttributeMapEntry *attributeMapAll[] = {
+ attributeMapCommonShared,
+ attributeMapCommonBlock,
+ attributeMapCommonInline,
+ attributeMapCommonRubyText,
+ attributeMapCommonColumns,
+ attributeMapCommonList,
+ attributeMapCommonPrintField,
+ attributeMapCommonTable,
+ attributeMapCommonTableCell,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapShared[] = {
+ attributeMapCommonShared,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapBlock[] = {
+ attributeMapCommonShared,
+ attributeMapCommonBlock,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapInline[] = {
+ attributeMapCommonShared,
+ attributeMapCommonInline,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapTableCell[] = {
+ attributeMapCommonShared,
+ attributeMapCommonBlock,
+ attributeMapCommonTable,
+ attributeMapCommonTableCell,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapRubyText[] = {
+ attributeMapCommonShared,
+ attributeMapCommonInline,
+ attributeMapCommonRubyText,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapColumns[] = {
+ attributeMapCommonShared,
+ attributeMapCommonInline,
+ attributeMapCommonColumns,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapList[] = {
+ attributeMapCommonShared,
+ attributeMapCommonList,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapTable[] = {
+ attributeMapCommonShared,
+ attributeMapCommonBlock,
+ attributeMapCommonTable,
+ NULL,
+};
+
+static const AttributeMapEntry *attributeMapIllustration[] = {
+ // XXX: Illustrations may have some attributes from the "shared", "inline",
+ // the "block" sets. This is a loose specification; making it better
+ // means duplicating entries from the sets. This seems good enough...
+ attributeMapCommonShared,
+ attributeMapCommonBlock,
+ attributeMapCommonInline,
+ NULL,
+};
+
+// Table mapping owners of attributes to their names.
+static const struct OwnerMapEntry {
+ Attribute::Owner owner;
+ const char *name;
+} ownerMap[] = {
+ // XXX: Those are sorted in the owner priority resolution order. If the
+ // same attribute is defined with two owners, the order in the table
+ // can be used to know which one has more priority.
+ { Attribute::XML_1_00, "XML-1.00" },
+ { Attribute::HTML_3_20, "HTML-3.20" },
+ { Attribute::HTML_4_01, "HTML-4.01" },
+ { Attribute::OEB_1_00, "OEB-1.00" },
+ { Attribute::RTF_1_05, "RTF-1.05" },
+ { Attribute::CSS_1_00, "CSS-1.00" },
+ { Attribute::CSS_2_00, "CSS-2.00" },
+ { Attribute::Layout, "Layout" },
+ { Attribute::PrintField, "PrintField" },
+ { Attribute::Table, "Table" },
+ { Attribute::List, "List" },
+ { Attribute::UserProperties, "UserProperties" },
+};
+
+
+static GBool ownerHasMorePriority(Attribute::Owner a, Attribute::Owner b)
+{
+ unsigned aIndex, bIndex;
+
+ for (unsigned i = aIndex = bIndex = 0; i < sizeof(ownerMap) / sizeof(ownerMap[0]); i++) {
+ if (ownerMap[i].owner == a)
+ aIndex = i;
+ if (ownerMap[i].owner == b)
+ bIndex = i;
+ }
+
+ return aIndex < bIndex;
+}
+
+
+// Maps element types to their names and also serves as lookup table
+// for additional element type attributes.
+
+enum ElementType {
+ elementTypeUndefined,
+ elementTypeGrouping,
+ elementTypeInline,
+ elementTypeBlock,
+};
+
+static const struct TypeMapEntry {
+ StructElement::Type type;
+ const char *name;
+ ElementType elementType;
+ const AttributeMapEntry **attributes;
+} typeMap[] = {
+ { StructElement::Document, "Document", elementTypeGrouping, attributeMapShared },
+ { StructElement::Part, "Part", elementTypeGrouping, attributeMapShared },
+ { StructElement::Art, "Art", elementTypeGrouping, attributeMapColumns },
+ { StructElement::Sect, "Sect", elementTypeGrouping, attributeMapColumns },
+ { StructElement::Div, "Div", elementTypeGrouping, attributeMapColumns },
+ { StructElement::BlockQuote, "BlockQuote", elementTypeGrouping, attributeMapInline },
+ { StructElement::Caption, "Caption", elementTypeGrouping, attributeMapInline },
+ { StructElement::NonStruct, "NonStruct", elementTypeGrouping, attributeMapInline },
+ { StructElement::Index, "Index", elementTypeGrouping, attributeMapInline },
+ { StructElement::Private, "Private", elementTypeGrouping, attributeMapInline },
+ { StructElement::Span, "Span", elementTypeInline, attributeMapInline },
+ { StructElement::Quote, "Quote", elementTypeInline, attributeMapInline },
+ { StructElement::Note, "Note", elementTypeInline, attributeMapInline },
+ { StructElement::Reference, "Reference", elementTypeInline, attributeMapInline },
+ { StructElement::BibEntry, "BibEntry", elementTypeInline, attributeMapInline },
+ { StructElement::Code, "Code", elementTypeInline, attributeMapInline },
+ { StructElement::Link, "Link", elementTypeInline, attributeMapInline },
+ { StructElement::Annot, "Annot", elementTypeInline, attributeMapInline },
+ { StructElement::Ruby, "Ruby", elementTypeInline, attributeMapRubyText },
+ { StructElement::RB, "RB", elementTypeUndefined, attributeMapRubyText },
+ { StructElement::RT, "RT", elementTypeUndefined, attributeMapRubyText },
+ { StructElement::RP, "RP", elementTypeUndefined, attributeMapShared },
+ { StructElement::Warichu, "Warichu", elementTypeInline, attributeMapRubyText },
+ { StructElement::WT, "WT", elementTypeUndefined, attributeMapShared },
+ { StructElement::WP, "WP", elementTypeUndefined, attributeMapShared },
+ { StructElement::P, "P", elementTypeBlock, attributeMapBlock },
+ { StructElement::H, "H", elementTypeBlock, attributeMapBlock },
+ { StructElement::H1, "H1", elementTypeBlock, attributeMapBlock },
+ { StructElement::H2, "H2", elementTypeBlock, attributeMapBlock },
+ { StructElement::H3, "H3", elementTypeBlock, attributeMapBlock },
+ { StructElement::H4, "H4", elementTypeBlock, attributeMapBlock },
+ { StructElement::H5, "H5", elementTypeBlock, attributeMapBlock },
+ { StructElement::H6, "H6", elementTypeBlock, attributeMapBlock },
+ { StructElement::L, "L", elementTypeBlock, attributeMapList },
+ { StructElement::LI, "LI", elementTypeBlock, attributeMapBlock },
+ { StructElement::Lbl, "Lbl", elementTypeBlock, attributeMapBlock },
+ { StructElement::LBody, "LBody", elementTypeBlock, attributeMapBlock },
+ { StructElement::Table, "Table", elementTypeBlock, attributeMapTable },
+ { StructElement::TR, "TR", elementTypeUndefined, attributeMapShared },
+ { StructElement::TH, "TH", elementTypeUndefined, attributeMapTableCell },
+ { StructElement::TD, "TD", elementTypeUndefined, attributeMapTableCell },
+ { StructElement::THead, "THead", elementTypeUndefined, attributeMapShared },
+ { StructElement::TFoot, "TFoot", elementTypeUndefined, attributeMapShared },
+ { StructElement::TBody, "TBody", elementTypeUndefined, attributeMapShared },
+ { StructElement::Figure, "Figure", elementTypeUndefined, attributeMapIllustration },
+ { StructElement::Formula, "Formula", elementTypeUndefined, attributeMapIllustration },
+ { StructElement::Form, "Form", elementTypeUndefined, attributeMapIllustration },
+ { StructElement::TOC, "TOC", elementTypeGrouping, attributeMapShared },
+ { StructElement::TOCI, "TOCI", elementTypeGrouping, attributeMapShared },
+};
+
+
+//------------------------------------------------------------------------
+// Helpers for the attribute and structure type tables
+//------------------------------------------------------------------------
+
+static inline const AttributeMapEntry *
+getAttributeMapEntry(const AttributeMapEntry **entryList, Attribute::Type type)
+{
+ assert(entryList);
+ while (*entryList) {
+ const AttributeMapEntry *entry = *entryList;
+ while (entry->type != Attribute::Unknown) {
+ assert(entry->name);
+ if (type == entry->type)
+ return entry;
+ entry++;
+ }
+ entryList++;
+ }
+ return NULL;
+}
+
+static inline const AttributeMapEntry *
+getAttributeMapEntry(const AttributeMapEntry **entryList, const char *name)
+{
+ assert(entryList);
+ while (*entryList) {
+ const AttributeMapEntry *entry = *entryList;
+ while (entry->type != Attribute::Unknown) {
+ assert(entry->name);
+ if (strcmp(name, entry->name) == 0)
+ return entry;
+ entry++;
+ }
+ entryList++;
+ }
+ return NULL;
+}
+
+static inline const OwnerMapEntry *getOwnerMapEntry(Attribute::Owner owner)
+{
+ for (unsigned i = 0; i < sizeof(ownerMap) / sizeof(ownerMap[0]); i++) {
+ if (owner == ownerMap[i].owner)
+ return &ownerMap[i];
+ }
+ return NULL;
+}
+
+static inline const OwnerMapEntry *getOwnerMapEntry(const char *name)
+{
+ for (unsigned i = 0; i < sizeof(ownerMap) / sizeof(ownerMap[0]); i++) {
+ if (strcmp(name, ownerMap[i].name) == 0)
+ return &ownerMap[i];
+ }
+ return NULL;
+}
+
+static const char *ownerToName(Attribute::Owner owner)
+{
+ const OwnerMapEntry *entry = getOwnerMapEntry(owner);
+ return entry ? entry->name : "UnknownOwner";
+}
+
+static Attribute::Owner nameToOwner(const char *name)
+{
+ const OwnerMapEntry *entry = getOwnerMapEntry(name);
+ return entry ? entry->owner : Attribute::UnknownOwner;
+}
+
+static inline const TypeMapEntry *getTypeMapEntry(StructElement::Type type)
+{
+ for (unsigned i = 0; i < sizeof(typeMap) / sizeof(typeMap[0]); i++) {
+ if (type == typeMap[i].type)
+ return &typeMap[i];
+ }
+ return NULL;
+}
+
+static inline const TypeMapEntry *getTypeMapEntry(const char *name)
+{
+ for (unsigned i = 0; i < sizeof(typeMap) / sizeof(typeMap[0]); i++) {
+ if (strcmp(name, typeMap[i].name) == 0)
+ return &typeMap[i];
+ }
+ return NULL;
+}
+
+static const char *typeToName(StructElement::Type type)
+{
+ if (type == StructElement::MCID)
+ return "MarkedContent";
+ if (type == StructElement::OBJR)
+ return "ObjectReference";
+
+ const TypeMapEntry *entry = getTypeMapEntry(type);
+ return entry ? entry->name : "Unknown";
+}
+
+static StructElement::Type nameToType(const char *name)
+{
+ const TypeMapEntry *entry = getTypeMapEntry(name);
+ return entry ? entry->type : StructElement::Unknown;
+}
+
+
+//------------------------------------------------------------------------
+// Attribute
+//------------------------------------------------------------------------
+
+Attribute::Attribute(const char *nameA, int nameLenA, Object *valueA):
+ type(UserProperty),
+ owner(UserProperties),
+ revision(0),
+ name(nameA, nameLenA),
+ value(),
+ hidden(gFalse),
+ formatted(NULL)
+{
+ assert(valueA);
+ valueA->copy(&value);
+}
+
+Attribute::Attribute(Type type, Object *valueA):
+ type(type),
+ owner(UserProperties), // TODO: Determine corresponding owner from Type
+ revision(0),
+ name(),
+ value(),
+ hidden(gFalse),
+ formatted(NULL)
+{
+ assert(valueA);
+
+ valueA->copy(&value);
+
+ if (!checkType())
+ type = Unknown;
+}
+
+Attribute::~Attribute()
+{
+ delete formatted;
+ value.free();
+}
+
+const char *Attribute::getTypeName() const
+{
+ if (type == UserProperty)
+ return name.getCString();
+
+ const AttributeMapEntry *entry = getAttributeMapEntry(attributeMapAll, type);
+ if (entry)
+ return entry->name;
+
+ return "Unknown";
+}
+
+const char *Attribute::getOwnerName() const
+{
+ return ownerToName(owner);
+}
+
+Object *Attribute::getDefaultValue(Attribute::Type type)
+{
+ const AttributeMapEntry *entry = getAttributeMapEntry(attributeMapAll, type);
+ return entry ? const_cast<Object*>(entry->defval) : NULL;
+}
+
+void Attribute::setFormattedValue(const char *formattedA)
+{
+ if (formattedA) {
+ if (formatted)
+ formatted->Set(formattedA);
+ else
+ formatted = new GooString(formattedA);
+ } else {
+ delete formatted;
+ formatted = NULL;
+ }
+}
+
+GBool Attribute::checkType(StructElement *element)
+{
+ // If an element is passed, tighther type-checking can be done.
+ if (!element)
+ return gTrue;
+
+ const TypeMapEntry *elementTypeEntry = getTypeMapEntry(element->getType());
+ if (elementTypeEntry && elementTypeEntry->attributes) {
+ const AttributeMapEntry *entry = getAttributeMapEntry(elementTypeEntry->attributes, type);
+ if (entry) {
+ if (entry->check && !((*entry->check)(&value))) {
+ return gFalse;
+ }
+ } else {
+ // No entry: the attribute is not valid for the containing element.
+ return gFalse;
+ }
+ }
+
+ return gTrue;
+}
+
+Attribute::Type Attribute::getTypeForName(const char *name, StructElement *element)
+{
+ const AttributeMapEntry **attributes = attributeMapAll;
+ if (element) {
+ const TypeMapEntry *elementTypeEntry = getTypeMapEntry(element->getType());
+ if (elementTypeEntry && elementTypeEntry->attributes) {
+ attributes = elementTypeEntry->attributes;
+ }
+ }
+
+ const AttributeMapEntry *entry = getAttributeMapEntry(attributes, name);
+ return entry ? entry->type : Unknown;
+}
+
+Attribute *Attribute::parseUserProperty(Dict *property)
+{
+ Object obj, value;
+ const char *name = NULL;
+ int nameLen = GooString::CALC_STRING_LEN;
+
+ if (property->lookup("N", &obj)->isString()) {
+ GooString *s = obj.getString();
+ name = s->getCString();
+ nameLen = s->getLength();
+ } else if (obj.isName())
+ name = obj.getName();
+ else {
+ error(errSyntaxError, -1, "N object is wrong type ({0:s})", obj.getTypeName());
+ obj.free();
+ return NULL;
+ }
+
+ if (property->lookup("V", &value)->isNull()) {
+ error(errSyntaxError, -1, "V object is wrong type ({0:s})", value.getTypeName());
+ value.free();
+ obj.free();
+ return NULL;
+ }
+
+ Attribute *attribute = new Attribute(name, nameLen, &value);
+ value.free();
+ obj.free();
+
+ if (property->lookup("F", &obj)->isString()) {
+ attribute->setFormattedValue(obj.getString()->getCString());
+ } else if (!obj.isNull()) {
+ error(errSyntaxWarning, -1, "F object is wrong type ({0:s})", obj.getTypeName());
+ }
+ obj.free();
+
+ if (property->lookup("H", &obj)->isBool()) {
+ attribute->setHidden(obj.getBool());
+ } else if (!obj.isNull()) {
+ error(errSyntaxWarning, -1, "H object is wrong type ({0:s})", obj.getTypeName());
+ }
+ obj.free();
+
+ return attribute;
+}
+
+
+//------------------------------------------------------------------------
+// StructElement
+//------------------------------------------------------------------------
+
+StructElement::StructData::StructData():
+ altText(0),
+ actualText(0),
+ id(0),
+ title(0),
+ expandedAbbr(0),
+ language(0),
+ revision(0)
+{
+}
+
+StructElement::StructData::~StructData()
+{
+ delete altText;
+ delete actualText;
+ delete id;
+ delete title;
+ delete language;
+ parentRef.free();
+ for (ElemPtrArray::iterator i = elements.begin(); i != elements.end(); ++i) delete *i;
+ for (AttrPtrArray::iterator i = attributes.begin(); i != attributes.end(); ++i) delete *i;
+}
+
+
+StructElement::StructElement(Dict *element,
+ StructTreeRoot *treeRootA,
+ StructElement *parentA,
+ std::set<int> &seen):
+ type(Unknown),
+ treeRoot(treeRootA),
+ parent(parentA),
+ s(new StructData())
+{
+ assert(treeRoot);
+ assert(element);
+
+ parse(element);
+ parseChildren(element, seen);
+}
+
+StructElement::StructElement(int mcid, StructTreeRoot *treeRootA, StructElement *parentA):
+ type(MCID),
+ treeRoot(treeRootA),
+ parent(parentA),
+ c(new ContentData(mcid))
+{
+ assert(treeRoot);
+ assert(parent);
+}
+
+StructElement::StructElement(const Ref& ref, StructTreeRoot *treeRootA, StructElement *parentA):
+ type(OBJR),
+ treeRoot(treeRootA),
+ parent(parentA),
+ c(new ContentData(ref))
+{
+ assert(treeRoot);
+ assert(parent);
+}
+
+StructElement::~StructElement()
+{
+ if (isContent())
+ delete c;
+ else
+ delete s;
+ pageRef.free();
+}
+
+GBool StructElement::isBlock() const
+{
+ const TypeMapEntry *entry = getTypeMapEntry(type);
+ return entry ? (entry->elementType == elementTypeBlock) : gFalse;
+}
+
+GBool StructElement::isInline() const
+{
+ const TypeMapEntry *entry = getTypeMapEntry(type);
+ return entry ? (entry->elementType == elementTypeInline) : gFalse;
+}
+
+GBool StructElement::isGrouping() const
+{
+ const TypeMapEntry *entry = getTypeMapEntry(type);
+ return entry ? (entry->elementType == elementTypeGrouping) : gFalse;
+}
+
+GBool StructElement::hasPageRef() const
+{
+ return pageRef.isRef() || (parent && parent->hasPageRef());
+}
+
+bool StructElement::getPageRef(Ref& ref) const
+{
+ if (pageRef.isRef()) {
+ ref = pageRef.getRef();
+ return gTrue;
+ }
+
+ if (parent)
+ return parent->getPageRef(ref);
+
+ return gFalse;
+}
+
+const char *StructElement::getTypeName() const
+{
+ return typeToName(type);
+}
+
+const Attribute *StructElement::findAttribute(Attribute::Type attributeType, GBool inherit,
+ Attribute::Owner attributeOwner) const
+{
+ if (isContent())
+ return parent->findAttribute(attributeType, inherit, attributeOwner);
+
+ if (attributeType == Attribute::Unknown || attributeType == Attribute::UserProperty)
+ return NULL;
+
+ const Attribute *result = NULL;
+
+ if (attributeOwner == Attribute::UnknownOwner) {
+ // Search for the attribute, no matter who the owner is
+ for (unsigned i = 0; i < getNumAttributes(); i++) {
+ const Attribute *attr = getAttribute(i);
+ if (attributeType == attr->getType()) {
+ if (!result || ownerHasMorePriority(attr->getOwner(), result->getOwner()))
+ result = attr;
+ }
+ }
+ } else {
+ // Search for the attribute, with a specific owner
+ for (unsigned i = 0; i < getNumAttributes(); i++) {
+ const Attribute *attr = getAttribute(i);
+ if (attributeType == attr->getType() && attributeOwner == attr->getOwner()) {
+ result = attr;
+ break;
+ }
+ }
+ }
+
+ if (result)
+ return result;
+
+ if (inherit && parent) {
+ const AttributeMapEntry *entry = getAttributeMapEntry(attributeMapAll, attributeType);
+ assert(entry);
+ // TODO: Take into account special inheritance cases, for example:
+ // inline elements which have been changed to be block using
+ // "/Placement/Block" have slightly different rules.
+ if (entry->inherit)
+ return parent->findAttribute(attributeType, inherit, attributeOwner);
+ }
+
+ return NULL;
+}
+
+GooString* StructElement::appendSubTreeText(GooString *string, GBool recursive) const
+{
+ if (isContent() && !isObjectRef()) {
+ MarkedContentOutputDev mcdev(getMCID());
+ const TextSpanArray& spans(getTextSpansInternal(mcdev));
+
+ if (!string)
+ string = new GooString();
+
+ for (TextSpanArray::const_iterator i = spans.begin(); i != spans.end(); ++i)
+ string->append(i->getText());
+
+ return string;
+ }
+
+ if (!recursive)
+ return NULL;
+
+ // Do a depth-first traversal, to get elements in logical order
+ if (!string)
+ string = new GooString();
+
+ for (unsigned i = 0; i < getNumChildren(); i++)
+ getChild(i)->appendSubTreeText(string, recursive);
+
+ return string;
+}
+
+const TextSpanArray& StructElement::getTextSpansInternal(MarkedContentOutputDev& mcdev) const
+{
+ assert(isContent());
+
+ int startPage = 0, endPage = 0;
+
+ Ref ref;
+ if (getPageRef(ref)) {
+ startPage = endPage = treeRoot->getDoc()->findPage(ref.num, ref.gen);
+ }
+
+ if (!(startPage && endPage)) {
+ startPage = 1;
+ endPage = treeRoot->getDoc()->getNumPages();
+ }
+
+ treeRoot->getDoc()->displayPages(&mcdev, startPage, endPage, 72.0, 72.0, 0, gTrue, gFalse, gFalse);
+ return mcdev.getTextSpans();
+}
+
+static StructElement::Type roleMapResolve(Dict *roleMap, const char *name, const char *curName, Object *resolved)
+{
+ // Circular reference
+ if (curName && !strcmp(name, curName))
+ return StructElement::Unknown;
+
+ if (roleMap->lookup(curName ? curName : name, resolved)->isName()) {
+ StructElement::Type type = nameToType(resolved->getName());
+ return type == StructElement::Unknown
+ ? roleMapResolve(roleMap, name, resolved->getName(), resolved)
+ : type;
+ }
+
+ if (!resolved->isNull())
+ error(errSyntaxWarning, -1, "RoleMap entry is wrong type ({0:s})", resolved->getTypeName());
+ return StructElement::Unknown;
+}
+
+void StructElement::parse(Dict *element)
+{
+ Object obj;
+
+ // Type is optional, but if present must be StructElem
+ if (!element->lookup("Type", &obj)->isNull() && !obj.isName("StructElem")) {
+ error(errSyntaxError, -1, "Type of StructElem object is wrong");
+ obj.free();
+ return;
+ }
+ obj.free();
+
+ // Parent object reference (required).
+ if (!element->lookupNF("P", &s->parentRef)->isRef()) {
+ error(errSyntaxError, -1, "P object is wrong type ({0:s})", obj.getTypeName());
+ return;
+ }
+
+ // Check whether the S-type is valid for the top level
+ // element and create a node of the appropriate type.
+ if (!element->lookup("S", &obj)->isName()) {
+ error(errSyntaxError, -1, "S object is wrong type ({0:s})", obj.getTypeName());
+ obj.free();
+ return;
+ }
+
+ // Type name may not be standard, resolve through RoleMap first.
+ if (treeRoot->getRoleMap()) {
+ Object resolvedName;
+ type = roleMapResolve(treeRoot->getRoleMap(), obj.getName(), NULL, &resolvedName);
+ }
+
+ // Resolving through RoleMap may leave type as Unknown, e.g. for types
+ // which are not present in it, yet they are standard element types.
+ if (type == Unknown)
+ type = nameToType(obj.getName());
+
+ // At this point either the type name must have been resolved.
+ if (type == Unknown) {
+ error(errSyntaxError, -1, "StructElem object is wrong type ({0:s})", obj.getName());
+ obj.free();
+ return;
+ }
+ obj.free();
+
+ // Object ID (optional), to be looked at the IDTree in the tree root.
+ if (element->lookup("ID", &obj)->isString()) {
+ s->id = obj.takeString();
+ }
+ obj.free();
+
+ // Page reference (optional) in which at least one of the child items
+ // is to be rendered in. Note: each element stores only the /Pg value
+ // contained by it, and StructElement::getPageRef() may look in parent
+ // elements to find the page where an element belongs.
+ element->lookupNF("Pg", &pageRef);
+
+ // Revision number (optional).
+ if (element->lookup("R", &obj)->isInt()) {
+ s->revision = obj.getInt();
+ }
+ obj.free();
+
+ // Element title (optional).
+ if (element->lookup("T", &obj)->isString()) {
+ s->title = obj.takeString();
+ }
+ obj.free();
+
+ // Language (optional).
+ if (element->lookup("Lang", &obj)->isString()) {
+ s->language = obj.takeString();
+ }
+ obj.free();
+
+ // Alternative text (optional).
+ if (element->lookup("Alt", &obj)->isString()) {
+ s->altText = obj.takeString();
+ }
+ obj.free();
+
+ // Expanded form of an abbreviation (optional).
+ if (element->lookup("E", &obj)->isString()) {
+ s->expandedAbbr = obj.takeString();
+ }
+ obj.free();
+
+ // Actual text (optional).
+ if (element->lookup("ActualText", &obj)->isString()) {
+ s->actualText = obj.takeString();
+ }
+ obj.free();
+
+ // Attributes directly attached to the element (optional).
+ if (element->lookup("A", &obj)->isDict()) {
+ parseAttributes(obj.getDict());
+ } else if (obj.isArray()) {
+ Object iobj;
+ unsigned attrIndex = getNumAttributes();
+ for (int i = 0; i < obj.arrayGetLength(); i++) {
+ if (obj.arrayGet(i, &iobj)->isDict()) {
+ attrIndex = getNumAttributes();
+ parseAttributes(iobj.getDict());
+ } else if (iobj.isInt()) {
+ const int revision = iobj.getInt();
+ // Set revision numbers for the elements previously created.
+ for (unsigned j = attrIndex; j < getNumAttributes(); j++)
+ getAttribute(j)->setRevision(revision);
+ } else {
+ error(errSyntaxWarning, -1, "A item is wrong type ({0:s})", iobj.getTypeName());
+ }
+ iobj.free();
+ }
+ } else if (!obj.isNull()) {
+ error(errSyntaxWarning, -1, "A is wrong type ({0:s})", obj.getTypeName());
+ }
+ obj.free();
+
+ // Attributes referenced indirectly through the ClassMap (optional).
+ if (treeRoot->getClassMap()) {
+ Object classes;
+ if (element->lookup("C", &classes)->isName()) {
+ Object attr;
+ if (treeRoot->getClassMap()->lookup(classes.getName(), &attr)->isDict()) {
+ parseAttributes(attr.getDict(), gTrue);
+ } else if (attr.isArray()) {
+ for (int i = 0; i < attr.arrayGetLength(); i++) {
+ Object iobj;
+ unsigned attrIndex = getNumAttributes();
+ if (attr.arrayGet(i, &iobj)->isDict()) {
+ attrIndex = getNumAttributes();
+ parseAttributes(iobj.getDict(), gTrue);
+ } else if (iobj.isInt()) {
+ // Set revision numbers for the elements previously created.
+ const int revision = iobj.getInt();
+ for (unsigned j = attrIndex; j < getNumAttributes(); j++)
+ getAttribute(j)->setRevision(revision);
+ } else {
+ error(errSyntaxWarning, -1, "C item is wrong type ({0:s})", iobj.getTypeName());
+ }
+ iobj.free();
+ }
+ } else if (!attr.isNull()) {
+ error(errSyntaxWarning, -1, "C object is wrong type ({0:s})", classes.getTypeName());
+ }
+ classes.free();
+ attr.free();
+ }
+ }
+}
+
+StructElement *StructElement::parseChild(Object *ref,
+ Object *childObj,
+ std::set<int> &seen)
+{
+ assert(childObj);
+ assert(ref);
+
+ StructElement *child = NULL;
+
+ if (childObj->isInt()) {
+ child = new StructElement(childObj->getInt(), treeRoot, this);
+ } else if (childObj->isDict("MCR")) {
+ /*
+ * TODO: The optional Stm/StwOwn attributes are not handled, so all the
+ * page will be always scanned when calling StructElement::getText().
+ */
+ Object mcidObj;
+ Object pageRefObj;
+
+ if (!childObj->dictLookup("MCID", &mcidObj)->isInt()) {
+ error(errSyntaxError, -1, "MCID object is wrong type ({0:s})", mcidObj.getTypeName());
+ mcidObj.free();
+ return NULL;
+ }
+
+ child = new StructElement(mcidObj.getInt(), treeRoot, this);
+ mcidObj.free();
+
+ if (childObj->dictLookupNF("Pg", &pageRefObj)->isRef()) {
+ child->pageRef = pageRefObj;
+ } else {
+ pageRefObj.free();
+ }
+ } else if (childObj->isDict("OBJR")) {
+ Object refObj;
+
+ if (childObj->dictLookupNF("Obj", &refObj)->isRef()) {
+ Object pageRefObj;
+
+ child = new StructElement(refObj.getRef(), treeRoot, this);
+
+ if (childObj->dictLookupNF("Pg", &pageRefObj)->isRef()) {
+ child->pageRef = pageRefObj;
+ } else {
+ pageRefObj.free();
+ }
+ } else {
+ error(errSyntaxError, -1, "Obj object is wrong type ({0:s})", refObj.getTypeName());
+ }
+ refObj.free();
+ } else if (childObj->isDict()) {
+ if (!ref->isRef()) {
+ error(errSyntaxError, -1,
+ "Structure element dictionary is not an indirect reference ({0:s})",
+ ref->getTypeName());
+ } else if (seen.find(ref->getRefNum()) == seen.end()) {
+ seen.insert(ref->getRefNum());
+ child = new StructElement(childObj->getDict(), treeRoot, this, seen);
+ } else {
+ error(errSyntaxWarning, -1,
+ "Loop detected in structure tree, skipping subtree at object {0:d}:{1:d}",
+ ref->getRefNum(), ref->getRefGen());
+ }
+ } else {
+ error(errSyntaxWarning, -1, "K has a child of wrong type ({0:s})", childObj->getTypeName());
+ }
+
+ if (child) {
+ if (child->isOk()) {
+ appendChild(child);
+ if (ref->isRef())
+ treeRoot->parentTreeAdd(ref->getRef(), child);
+ } else {
+ delete child;
+ child = NULL;
+ }
+ }
+
+ return child;
+}
+
+void StructElement::parseChildren(Dict *element, std::set<int> &seen)
+{
+ Object kids;
+
+ if (element->lookup("K", &kids)->isArray()) {
+ for (int i = 0; i < kids.arrayGetLength(); i++) {
+ Object obj, ref;
+ parseChild(kids.arrayGetNF(i, &ref), kids.arrayGet(i, &obj), seen);
+ obj.free();
+ ref.free();
+ }
+ } else if (kids.isDict() || kids.isInt()) {
+ Object ref;
+ parseChild(element->lookupNF("K", &ref), &kids, seen);
+ ref.free();
+ }
+
+ kids.free();
+}
+
+void StructElement::parseAttributes(Dict *attributes, GBool keepExisting)
+{
+ Object owner;
+ if (attributes->lookup("O", &owner)->isName("UserProperties")) {
+ // In this case /P is an array of UserProperty dictionaries
+ Object userProperties;
+ if (attributes->lookup("P", &userProperties)->isArray()) {
+ for (int i = 0; i < userProperties.arrayGetLength(); i++) {
+ Object property;
+ if (userProperties.arrayGet(i, &property)->isDict()) {
+ Attribute *attribute = Attribute::parseUserProperty(property.getDict());
+ if (attribute && attribute->isOk()) {
+ appendAttribute(attribute);
+ } else {
+ error(errSyntaxWarning, -1, "Item in P is invalid");
+ delete attribute;
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Item in P is wrong type ({0:s})", property.getTypeName());
+ }
+ property.free();
+ }
+ }
+ userProperties.free();
+ } else if (owner.isName()) {
+ // In this case /P contains standard attributes.
+ // Check first if the owner is a valid standard one.
+ Attribute::Owner ownerValue = nameToOwner(owner.getName());
+ if (ownerValue != Attribute::UnknownOwner) {
+ // Iterate over the entries of the "attributes" dictionary.
+ // The /O entry (owner) is skipped.
+ for (int i = 0; i < attributes->getLength(); i++) {
+ const char *key = attributes->getKey(i);
+ if (strcmp(key, "O") != 0) {
+ Attribute::Type type = Attribute::getTypeForName(key, this);
+
+ // Check if the attribute is already defined.
+ if (keepExisting) {
+ GBool exists = gFalse;
+ for (unsigned j = 0; j < getNumAttributes(); j++) {
+ if (getAttribute(j)->getType() == type) {
+ exists = gTrue;
+ break;
+ }
+ }
+ if (exists)
+ continue;
+ }
+
+ if (type != Attribute::Unknown) {
+ Object value;
+ GBool typeCheckOk = gTrue;
+ Attribute *attribute = new Attribute(type, attributes->getVal(i, &value));
+ value.free();
+
+ if (attribute->isOk() && (typeCheckOk = attribute->checkType(this))) {
+ appendAttribute(attribute);
+ } else {
+ // It is not needed to free "value", the Attribute instance
+ // owns the contents, so deleting "attribute" is enough.
+ if (!typeCheckOk) {
+ error(errSyntaxWarning, -1, "Attribute {0:s} value is of wrong type ({1:s})",
+ attribute->getTypeName(), attribute->getValue()->getTypeName());
+ }
+ delete attribute;
+ }
+ } else {
+ error(errSyntaxWarning, -1, "Wrong Attribute '{0:s}' in element {1:s}", key, getTypeName());
+ }
+ }
+ }
+ } else {
+ error(errSyntaxWarning, -1, "O object is invalid value ({0:s})", owner.getName());
+ }
+ } else if (!owner.isNull()) {
+ error(errSyntaxWarning, -1, "O is wrong type ({0:s})", owner.getTypeName());
+ }
+ owner.free();
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/StructElement.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/StructElement.h
new file mode 100644
index 00000000000..cd89a970ddb
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/StructElement.h
@@ -0,0 +1,310 @@
+//========================================================================
+//
+// StructElement.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2013, 2014 Igalia S.L.
+// Copyright 2014 Luigi Scarso <luigi.scarso@gmail.com>
+// Copyright 2014 Albert Astals Cid <aacid@kde.org>
+//
+//========================================================================
+
+#ifndef STRUCTELEMENT_H
+#define STRUCTELEMENT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "goo/GooString.h"
+#include "MarkedContentOutputDev.h"
+#include "Object.h"
+#include <vector>
+#include <set>
+
+class GooString;
+class Dict;
+class StructElement;
+class StructTreeRoot;
+
+
+class Attribute {
+public:
+ enum Type {
+ Unknown = 0, // Uninitialized, parsing error, etc.
+ UserProperty, // User defined attribute (i.e. non-standard)
+
+ // Common standard attributes
+ Placement, WritingMode, BackgroundColor, BorderColor, BorderStyle,
+ BorderThickness, Color, Padding,
+
+ // Block element standard attributes
+ SpaceBefore, SpaceAfter, StartIndent, EndIndent, TextIndent, TextAlign,
+ BBox, Width, Height, BlockAlign, InlineAlign, TBorderStyle, TPadding,
+
+ // Inline element standard attributes
+ BaselineShift, LineHeight, TextDecorationColor, TextDecorationThickness,
+ TextDecorationType, RubyAlign, RubyPosition, GlyphOrientationVertical,
+
+ // Column-only standard attributes
+ ColumnCount, ColumnGap, ColumnWidths,
+
+ // List-only standard attributes
+ ListNumbering,
+
+ // PrintField-only standard attributes
+ Role, checked, Desc,
+
+ // Table-only standard attributes
+ RowSpan, ColSpan, Headers, Scope, Summary,
+ };
+
+ enum Owner {
+ UnknownOwner = 0,
+ // User-defined attributes
+ UserProperties,
+ // Standard attributes
+ Layout, List, PrintField, Table,
+ // Translation to other formats
+ XML_1_00, HTML_3_20, HTML_4_01, OEB_1_00, RTF_1_05, CSS_1_00, CSS_2_00,
+ };
+
+ // Creates a standard attribute. The name is predefined, and the
+ // value is type-checked to conform to the PDF specification.
+ Attribute(Type type, Object *value);
+
+ // Creates an UserProperty attribute, with an arbitrary name and value.
+ Attribute(const char *name, int nameLen, Object *value);
+
+ GBool isOk() const { return type != Unknown; }
+
+ // Name, type and value can be set only on construction.
+ Type getType() const { return type; }
+ Owner getOwner() const { return owner; }
+ const char *getTypeName() const;
+ const char *getOwnerName() const;
+ Object *getValue() const { return &value; }
+ static Object *getDefaultValue(Type type);
+
+ // The caller gets the ownership of the return GooString and is responsible of deleting it
+ GooString *getName() const { return type == UserProperty ? name.copy() : new GooString(getTypeName()); }
+
+ // The revision is optional, and defaults to zero.
+ Guint getRevision() const { return revision; }
+ void setRevision(Guint revisionA) { revision = revisionA; }
+
+ // Hidden elements should not be displayed by the user agent
+ GBool isHidden() const { return hidden; }
+ void setHidden(GBool hiddenA) { hidden = hiddenA; }
+
+ // The formatted value may be in the PDF, or be left undefined (NULL).
+ // In the later case the user agent should provide a default representation.
+ const char *getFormattedValue() const { return formatted ? formatted->getCString() : NULL; }
+ void setFormattedValue(const char *formattedA);
+
+ ~Attribute();
+
+private:
+ Type type;
+ Owner owner;
+ Guint revision;
+ mutable GooString name;
+ mutable Object value;
+ GBool hidden;
+ GooString *formatted;
+
+ GBool checkType(StructElement *element = NULL);
+ static Type getTypeForName(const char *name, StructElement *element = NULL);
+ static Attribute *parseUserProperty(Dict *property);
+
+ friend class StructElement;
+};
+
+
+class StructElement {
+public:
+ enum Type {
+ Unknown = 0,
+ MCID, // MCID reference, used internally
+ OBJR, // Object reference, used internally
+
+ Document, Part, Art, Sect, Div, // Structural elements
+
+ Span, Quote, Note, Reference, BibEntry, // Inline elements
+ Code, Link, Annot,
+ BlockQuote, Caption, NonStruct,
+ TOC, TOCI, Index, Private,
+
+ P, H, H1, H2, H3, H4, H5, H6, // Paragraph-like
+
+ L, LI, Lbl, LBody, // List elements
+
+ Table, TR, TH, TD, THead, TFoot, TBody, // Table elements
+
+ Ruby, RB, RT, RP, // Ruby text elements
+ Warichu, WT, WP,
+
+ Figure, Formula, Form, // Illustration-like elements
+ };
+
+ static const Ref InvalidRef;
+
+ const char *getTypeName() const;
+ Type getType() const { return type; }
+ GBool isOk() const { return type != Unknown; }
+ GBool isBlock() const;
+ GBool isInline() const;
+ GBool isGrouping() const;
+
+ inline GBool isContent() const { return (type == MCID) || isObjectRef(); }
+ inline GBool isObjectRef() const { return (type == OBJR && c->ref.num != -1 && c->ref.gen != -1); }
+
+ int getMCID() const { return c->mcid; }
+ Ref getObjectRef() const { return c->ref; }
+ Ref getParentRef() { return isContent() ? parent->getParentRef() : s->parentRef.getRef(); }
+ GBool hasPageRef() const;
+ GBool getPageRef(Ref& ref) const;
+ StructTreeRoot *getStructTreeRoot() { return treeRoot; }
+
+ // Optional element identifier.
+ const GooString *getID() const { return isContent() ? NULL : s->id; }
+ GooString *getID() { return isContent() ? NULL : s->id; }
+
+ // Optional ISO language name, e.g. en_US
+ GooString *getLanguage() {
+ if (!isContent() && s->language) return s->language;
+ return parent ? parent->getLanguage() : NULL;
+ }
+ const GooString *getLanguage() const {
+ if (!isContent() && s->language) return s->language;
+ return parent ? parent->getLanguage() : NULL;
+ }
+
+ // Optional revision number, defaults to zero.
+ Guint getRevision() const { return isContent() ? 0 : s->revision; }
+ void setRevision(Guint revision) { if (isContent()) s->revision = revision; }
+
+ // Optional element title, in human-readable form.
+ const GooString *getTitle() const { return isContent() ? NULL : s->title; }
+ GooString *getTitle() { return isContent() ? NULL : s->title; }
+
+ // Optional element expanded abbreviation text.
+ const GooString *getExpandedAbbr() const { return isContent() ? NULL : s->expandedAbbr; }
+ GooString *getExpandedAbbr() { return isContent() ? NULL : s->expandedAbbr; }
+
+ unsigned getNumChildren() const { return isContent() ? 0 : s->elements.size(); }
+ const StructElement *getChild(int i) const { return isContent() ? NULL : s->elements.at(i); }
+ StructElement *getChild(int i) { return isContent() ? NULL : s->elements.at(i); }
+
+ void appendChild(StructElement *element) {
+ if (!isContent() && element && element->isOk()) {
+ s->elements.push_back(element);
+ }
+ }
+
+ unsigned getNumAttributes() const { return isContent() ? 0 : s->attributes.size(); }
+ const Attribute *getAttribute(int i) const { return isContent() ? NULL : s->attributes.at(i); }
+ Attribute *getAttribute(int i) { return isContent() ? NULL : s->attributes.at(i); }
+
+ void appendAttribute(Attribute *attribute) {
+ if (!isContent() && attribute) {
+ s->attributes.push_back(attribute);
+ }
+ }
+
+ const Attribute* findAttribute(Attribute::Type attributeType, GBool inherit = gFalse,
+ Attribute::Owner owner = Attribute::UnknownOwner) const;
+
+ const GooString *getAltText() const { return isContent() ? NULL : s->altText; }
+ GooString *getAltText() { return isContent() ? NULL : s->altText; }
+
+ const GooString *getActualText() const { return isContent() ? NULL : s->actualText; }
+ GooString *getActualText() { return isContent() ? NULL : s->actualText; }
+
+ // Content text referenced by the element:
+ //
+ // - For MCID reference elements, this is just the text of the
+ // corresponding marked content object in the page stream, regardless
+ // of the setting of the "recursive" flag.
+ // - For other elements, if the "recursive" flag is set, the text
+ // enclosed by *all* the child MCID reference elements of the subtree
+ // is returned. The text is assembled by traversing the leaf MCID
+ // reference elements in logical order.
+ // - In any other case, the function returns NULL.
+ //
+ // A new string is returned, and the ownership passed to the caller.
+ //
+ GooString *getText(GBool recursive = gTrue) const {
+ return appendSubTreeText(NULL, recursive);
+ }
+
+ const TextSpanArray getTextSpans() const {
+ if (!isContent())
+ return TextSpanArray();
+ MarkedContentOutputDev mcdev(getMCID());
+ return getTextSpansInternal(mcdev);
+ }
+
+ ~StructElement();
+
+private:
+ GooString* appendSubTreeText(GooString *string, GBool recursive) const;
+ const TextSpanArray& getTextSpansInternal(MarkedContentOutputDev& mcdev) const;
+
+ typedef std::vector<Attribute*> AttrPtrArray;
+ typedef std::vector<StructElement*> ElemPtrArray;
+
+ struct StructData {
+ Object parentRef;
+ GooString *altText;
+ GooString *actualText;
+ GooString *id;
+ GooString *title;
+ GooString *expandedAbbr;
+ GooString *language;
+ Guint revision;
+ ElemPtrArray elements;
+ AttrPtrArray attributes;
+
+ StructData();
+ ~StructData();
+ };
+
+ // Data in content elements (MCID, MCR)
+ struct ContentData {
+ union {
+ int mcid;
+ Ref ref;
+ };
+
+ ContentData(int mcidA): mcid(mcidA) {}
+ ContentData(const Ref& r) { ref.num = r.num; ref.gen = r.gen; }
+ };
+
+ // Common data
+ Type type;
+ StructTreeRoot *treeRoot;
+ StructElement *parent;
+ mutable Object pageRef;
+
+ union {
+ StructData *s;
+ ContentData *c;
+ };
+
+ StructElement(Dict *elementDict, StructTreeRoot *treeRootA, StructElement *parentA, std::set<int> &seen);
+ StructElement(int mcid, StructTreeRoot *treeRootA, StructElement *parentA);
+ StructElement(const Ref &ref, StructTreeRoot *treeRootA, StructElement *parentA);
+
+ void parse(Dict* elementDict);
+ StructElement* parseChild(Object *ref, Object* childObj, std::set<int> &seen);
+ void parseChildren(Dict* element, std::set<int> &seen);
+ void parseAttributes(Dict *element, GBool keepExisting = gFalse);
+
+ friend class StructTreeRoot;
+};
+
+#endif
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/StructTreeRoot.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/StructTreeRoot.cc
new file mode 100644
index 00000000000..e46e3e28388
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/StructTreeRoot.cc
@@ -0,0 +1,175 @@
+//========================================================================
+//
+// StructTreeRoot.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2013, 2014 Igalia S.L.
+// Copyright 2014 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+//========================================================================
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/GooString.h"
+#include "StructTreeRoot.h"
+#include "StructElement.h"
+#include "PDFDoc.h"
+#include "Object.h"
+#include "Dict.h"
+#include <set>
+#include <assert.h>
+
+
+StructTreeRoot::StructTreeRoot(PDFDoc *docA, Dict *structTreeRootDict):
+ doc(docA)
+{
+ assert(doc);
+ assert(structTreeRootDict);
+ parse(structTreeRootDict);
+}
+
+StructTreeRoot::~StructTreeRoot()
+{
+ for (ElemPtrArray::iterator i = elements.begin(); i != elements.end(); ++i)
+ delete *i;
+ classMap.free();
+ roleMap.free();
+}
+
+void StructTreeRoot::parse(Dict *root)
+{
+ // The RoleMap/ClassMap dictionaries are needed by all the parsing
+ // functions, which will resolve the custom names to canonical
+ // standard names.
+ root->lookup("RoleMap", &roleMap);
+ root->lookup("ClassMap", &classMap);
+
+ // ParentTree (optional). If present, it must be a number tree,
+ // otherwise it is not possible to map stream objects to their
+ // corresponsing structure element. Here only the references are
+ // loaded into the array, the pointers to the StructElements will
+ // be filled-in later when parsing them.
+ Object obj;
+ if (root->lookup("ParentTree", &obj)->isDict()) {
+ Object nums;
+ if (obj.dictLookup("Nums", &nums)->isArray()) {
+ if (nums.arrayGetLength() % 2 == 0) {
+ parentTree.resize(nums.arrayGetLength() / 2);
+ // Index numbers in even positions, references in odd ones
+ for (int i = 0; i < nums.arrayGetLength(); i += 2) {
+ Object index, value;
+
+ if (!nums.arrayGet(i, &index)->isInt()) {
+ error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i, index.getTypeName());
+ index.free();
+ continue;
+ }
+ if (index.getInt() < 0) {
+ error(errSyntaxError, -1, "Nums item at position {0:d} is invalid value ({1:d})", i, index.getInt());
+ index.free();
+ continue;
+ }
+
+ const unsigned idx = index.getInt();
+ if (nums.arrayGetNF(i + 1, &value)->isRef()) {
+ parentTree[idx].resize(1);
+ parentTree[idx][0].ref = value.getRef();
+ } else if (nums.arrayGet(i + 1, &value)->isArray()) {
+ parentTree[idx].resize(value.arrayGetLength());
+ for (int j = 0; j < value.arrayGetLength(); j++) {
+ Object itemvalue;
+ if (value.arrayGetNF(j, &itemvalue)->isRef())
+ parentTree[idx][j].ref = itemvalue.getRef();
+ else
+ error(errSyntaxError, -1, "Nums array item at position {0:d}/{1:d} is invalid type ({2:s})", i, j, itemvalue.getTypeName());
+ itemvalue.free();
+ }
+ } else {
+ error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i + 1, value.getTypeName());
+ }
+
+ value.free();
+ index.free();
+ }
+ } else {
+ error(errSyntaxError, -1, "Nums array length is not a even ({0:d})", nums.arrayGetLength());
+ }
+ } else {
+ error(errSyntaxError, -1, "Nums object is wrong type ({0:s})", nums.getTypeName());
+ }
+ nums.free();
+ }
+ obj.free();
+
+ std::set<int> seenElements;
+
+ // Parse the children StructElements
+ const GBool marked = doc->getCatalog()->getMarkInfo() & Catalog::markInfoMarked;
+ Object kids;
+ if (root->lookup("K", &kids)->isArray()) {
+ if (marked && kids.arrayGetLength() > 1) {
+ error(errSyntaxWarning, -1, "K in StructTreeRoot has more than one children in a tagged PDF");
+ }
+ for (int i = 0; i < kids.arrayGetLength(); i++) {
+ Object obj, ref;
+ kids.arrayGetNF(i, &ref);
+ if (ref.isRef()) {
+ seenElements.insert(ref.getRefNum());
+ }
+ if (kids.arrayGet(i, &obj)->isDict()) {
+ StructElement *child = new StructElement(obj.getDict(), this, NULL, seenElements);
+ if (child->isOk()) {
+ if (marked && !(child->getType() == StructElement::Document ||
+ child->getType() == StructElement::Part ||
+ child->getType() == StructElement::Art ||
+ child->getType() == StructElement::Div)) {
+ error(errSyntaxWarning, -1, "StructTreeRoot element of tagged PDF is wrong type ({0:s})", child->getTypeName());
+ }
+ appendChild(child);
+ if (ref.isRef()) {
+ parentTreeAdd(ref.getRef(), child);
+ }
+ } else {
+ error(errSyntaxWarning, -1, "StructTreeRoot element could not be parsed");
+ delete child;
+ }
+ } else {
+ error(errSyntaxWarning, -1, "K has a child of wrong type ({0:s})", obj.getTypeName());
+ }
+ obj.free();
+ ref.free();
+ }
+ } else if (kids.isDict()) {
+ if (marked) {
+ error(errSyntaxWarning, -1, "K has a child of wrong type for a tagged PDF ({0:s})", kids.getTypeName());
+ }
+ StructElement *child = new StructElement(kids.getDict(), this, NULL, seenElements);
+ if (child->isOk()) {
+ appendChild(child);
+ Object ref;
+ if (root->lookupNF("K", &ref)->isRef())
+ parentTreeAdd(ref.getRef(), child);
+ ref.free();
+ } else {
+ error(errSyntaxWarning, -1, "StructTreeRoot element could not be parsed");
+ delete child;
+ }
+ } else if (!kids.isNull()) {
+ error(errSyntaxWarning, -1, "K in StructTreeRoot is wrong type ({0:s})", kids.getTypeName());
+ }
+
+ kids.free();
+}
+
+void StructTreeRoot::parentTreeAdd(const Ref &objectRef, StructElement *element)
+{
+ for (std::vector< std::vector<Parent> >::iterator i = parentTree.begin(); i != parentTree.end(); ++i) {
+ for (std::vector<Parent>::iterator j = i->begin(); j != i->end(); ++j) {
+ if (j->ref.num == objectRef.num && j->ref.gen == objectRef.gen)
+ j->element = element;
+ }
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/StructTreeRoot.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/StructTreeRoot.h
new file mode 100644
index 00000000000..3b1f3c84421
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/StructTreeRoot.h
@@ -0,0 +1,83 @@
+//========================================================================
+//
+// StructTreeRoot.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2013, 2014 Igalia S.L.
+//
+//========================================================================
+
+#ifndef STRUCTTREEROOT_H
+#define STRUCTTREEROOT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "Object.h"
+#include "StructElement.h"
+#include <vector>
+
+class Dict;
+class PDFDoc;
+
+
+class StructTreeRoot
+{
+public:
+ StructTreeRoot(PDFDoc *docA, Dict *rootDict);
+ ~StructTreeRoot();
+
+ PDFDoc *getDoc() { return doc; }
+ Dict *getRoleMap() { return roleMap.isDict() ? roleMap.getDict() : NULL; }
+ Dict *getClassMap() { return classMap.isDict() ? classMap.getDict() : NULL; }
+ unsigned getNumChildren() const { return elements.size(); }
+ const StructElement *getChild(int i) const { return elements.at(i); }
+ StructElement *getChild(int i) { return elements.at(i); }
+
+ void appendChild(StructElement *element) {
+ if (element && element->isOk()) {
+ elements.push_back(element);
+ }
+ }
+
+ const StructElement *findParentElement(unsigned index) const {
+ if (index < parentTree.size() && parentTree[index].size() == 1) {
+ return parentTree[index][0].element;
+ }
+ return NULL;
+ }
+
+private:
+ typedef std::vector<StructElement*> ElemPtrArray;
+
+ // Structure for items in /ParentTree, it keeps a mapping of
+ // object references and pointers to StructElement objects.
+ struct Parent {
+ Ref ref;
+ StructElement *element;
+
+ Parent(): element(NULL) { ref.num = ref.gen = -1; }
+ Parent(const Parent &p): element(p.element) {
+ ref.num = p.ref.num;
+ ref.gen = p.ref.gen;
+ }
+ ~Parent() {}
+ };
+
+ PDFDoc *doc;
+ Object roleMap;
+ Object classMap;
+ ElemPtrArray elements;
+ std::vector< std::vector<Parent> > parentTree;
+
+ void parse(Dict *rootDict);
+ void parentTreeAdd(const Ref &objectRef, StructElement *element);
+
+ friend class StructElement;
+};
+
+#endif
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/TextOutputDev.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/TextOutputDev.cc
new file mode 100644
index 00000000000..bbb371a30b8
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/TextOutputDev.cc
@@ -0,0 +1,5818 @@
+//========================================================================
+//
+// TextOutputDev.cc
+//
+// Copyright 1997-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005-2007 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2005 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+// Copyright (C) 2006-2008, 2011-2013 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2006, 2007, 2013 Ed Catmur <ed@catmur.co.uk>
+// Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2007, 2008, 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2008 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2008, 2010-2012, 2014, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008 Pino Toscano <pino@kde.org>
+// Copyright (C) 2008, 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2009 Ross Moore <ross@maths.mq.edu.au>
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2010 Brian Ewins <brian.ewins@gmail.com>
+// Copyright (C) 2010 Marek Kasik <mkasik@redhat.com>
+// Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+// Copyright (C) 2011 Sam Liao <phyomh@gmail.com>
+// Copyright (C) 2012 Horst Prote <prote@fmi.uni-stuttgart.de>
+// Copyright (C) 2012, 2013-2015 Jason Crain <jason@aquaticape.us>
+// Copyright (C) 2012 Peter Breitenlohner <peb@mppmu.mpg.de>
+// Copyright (C) 2013 José Aliste <jaliste@src.gnome.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2013 Ed Catmur <ed@catmur.co.uk>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+#include <float.h>
+#include <ctype.h>
+#ifdef _WIN32
+#include <fcntl.h> // for O_BINARY
+#include <io.h> // for setmode
+#endif
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "goo/GooList.h"
+#include "poppler-config.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "UnicodeMap.h"
+#include "UnicodeTypeTable.h"
+#include "Link.h"
+#include "TextOutputDev.h"
+#include "Page.h"
+#include "Annot.h"
+#include "UTF.h"
+
+#ifdef MACOS
+// needed for setting type/creator of MacOS files
+#include "ICSupport.h"
+#endif
+
+//------------------------------------------------------------------------
+// parameters
+//------------------------------------------------------------------------
+
+// Each bucket in a text pool includes baselines within a range of
+// this many points.
+#define textPoolStep 4
+
+// Inter-character space width which will cause addChar to start a new
+// word.
+#define minWordBreakSpace 0.1
+
+// Negative inter-character space width, i.e., overlap, which will
+// cause addChar to start a new word.
+#define minDupBreakOverlap 0.2
+
+// Max distance between baselines of two lines within a block, as a
+// fraction of the font size.
+#define maxLineSpacingDelta 1.5
+
+// Max difference in primary font sizes on two lines in the same
+// block. Delta1 is used when examining new lines above and below the
+// current block; delta2 is used when examining text that overlaps the
+// current block; delta3 is used when examining text to the left and
+// right of the current block.
+#define maxBlockFontSizeDelta1 0.05
+#define maxBlockFontSizeDelta2 0.6
+#define maxBlockFontSizeDelta3 0.2
+
+// Max difference in font sizes inside a word.
+#define maxWordFontSizeDelta 0.05
+
+// Maximum distance between baselines of two words on the same line,
+// e.g., distance between subscript or superscript and the primary
+// baseline, as a fraction of the font size.
+#define maxIntraLineDelta 0.5
+
+// Minimum inter-word spacing, as a fraction of the font size. (Only
+// used for raw ordering.)
+#define minWordSpacing 0.15
+
+// Maximum inter-word spacing, as a fraction of the font size.
+#define maxWordSpacing 1.5
+
+// Maximum horizontal spacing which will allow a word to be pulled
+// into a block.
+#define minColSpacing1 0.3
+
+// Minimum spacing between columns, as a fraction of the font size.
+#define minColSpacing2 1.0
+
+// Maximum vertical spacing between blocks within a flow, as a
+// multiple of the font size.
+#define maxBlockSpacing 2.5
+
+// Minimum spacing between characters within a word, as a fraction of
+// the font size.
+#define minCharSpacing -0.5
+
+// Maximum spacing between characters within a word, as a fraction of
+// the font size, when there is no obvious extra-wide character
+// spacing.
+#define maxCharSpacing 0.03
+
+// When extra-wide character spacing is detected, the inter-character
+// space threshold is set to the minimum inter-character space
+// multiplied by this constant.
+#define maxWideCharSpacingMul 1.3
+
+// Upper limit on spacing between characters in a word.
+#define maxWideCharSpacing 0.4
+
+// Max difference in primary,secondary coordinates (as a fraction of
+// the font size) allowed for duplicated text (fake boldface, drop
+// shadows) which is to be discarded.
+#define dupMaxPriDelta 0.1
+#define dupMaxSecDelta 0.2
+
+// Max width of underlines (in points).
+#define maxUnderlineWidth 3
+
+// Min distance between baseline and underline (in points).
+//~ this should be font-size-dependent
+#define minUnderlineGap -2
+
+// Max distance between baseline and underline (in points).
+//~ this should be font-size-dependent
+#define maxUnderlineGap 4
+
+// Max horizontal distance between edge of word and start of underline
+// (in points).
+//~ this should be font-size-dependent
+#define underlineSlack 1
+
+// Max distance between edge of text and edge of link border
+#define hyperlinkSlack 2
+
+// Max distance between characters when combining a base character and
+// combining character
+#define combMaxMidDelta 0.3
+#define combMaxBaseDelta 0.4
+
+//------------------------------------------------------------------------
+// TextUnderline
+//------------------------------------------------------------------------
+
+class TextUnderline {
+public:
+
+ TextUnderline(double x0A, double y0A, double x1A, double y1A)
+ { x0 = x0A; y0 = y0A; x1 = x1A; y1 = y1A; horiz = y0 == y1; }
+ ~TextUnderline() {}
+
+ double x0, y0, x1, y1;
+ GBool horiz;
+};
+
+//------------------------------------------------------------------------
+// TextLink
+//------------------------------------------------------------------------
+
+class TextLink {
+public:
+
+ TextLink(int xMinA, int yMinA, int xMaxA, int yMaxA, AnnotLink *linkA)
+ { xMin = xMinA; yMin = yMinA; xMax = xMaxA; yMax = yMaxA; link = linkA; }
+ ~TextLink() {}
+
+ int xMin, yMin, xMax, yMax;
+ AnnotLink *link;
+};
+
+//------------------------------------------------------------------------
+// TextFontInfo
+//------------------------------------------------------------------------
+
+TextFontInfo::TextFontInfo(GfxState *state) {
+ gfxFont = state->getFont();
+ if (gfxFont)
+ gfxFont->incRefCnt();
+#if TEXTOUT_WORD_LIST
+ fontName = (gfxFont && gfxFont->getName()) ? gfxFont->getName()->copy()
+ : (GooString *)NULL;
+ flags = gfxFont ? gfxFont->getFlags() : 0;
+#endif
+}
+
+TextFontInfo::~TextFontInfo() {
+ if (gfxFont)
+ gfxFont->decRefCnt();
+#if TEXTOUT_WORD_LIST
+ if (fontName) {
+ delete fontName;
+ }
+#endif
+}
+
+GBool TextFontInfo::matches(GfxState *state) {
+ return state->getFont() == gfxFont;
+}
+
+GBool TextFontInfo::matches(TextFontInfo *fontInfo) {
+ return gfxFont == fontInfo->gfxFont;
+}
+
+double TextFontInfo::getAscent() {
+ return gfxFont ? gfxFont->getAscent() : 0.95;
+}
+
+double TextFontInfo::getDescent() {
+ return gfxFont ? gfxFont->getDescent() : -0.35;
+}
+
+int TextFontInfo::getWMode() {
+ return gfxFont ? gfxFont->getWMode() : 0;
+}
+
+//------------------------------------------------------------------------
+// TextWord
+//------------------------------------------------------------------------
+
+TextWord::TextWord(GfxState *state, int rotA, double fontSizeA) {
+ rot = rotA;
+ fontSize = fontSizeA;
+ text = NULL;
+ charcode = NULL;
+ edge = NULL;
+ charPos = NULL;
+ font = NULL;
+ textMat = NULL;
+ len = size = 0;
+ spaceAfter = gFalse;
+ next = NULL;
+
+#if TEXTOUT_WORD_LIST
+ GfxRGB rgb;
+
+ if ((state->getRender() & 3) == 1) {
+ state->getStrokeRGB(&rgb);
+ } else {
+ state->getFillRGB(&rgb);
+ }
+ colorR = colToDbl(rgb.r);
+ colorG = colToDbl(rgb.g);
+ colorB = colToDbl(rgb.b);
+#endif
+
+ underlined = gFalse;
+ link = NULL;
+}
+
+TextWord::~TextWord() {
+ gfree(text);
+ gfree(charcode);
+ gfree(edge);
+ gfree(charPos);
+ gfree(font);
+ gfree(textMat);
+}
+
+void TextWord::addChar(GfxState *state, TextFontInfo *fontA, double x, double y,
+ double dx, double dy, int charPosA, int charLen,
+ CharCode c, Unicode u, const Matrix &textMatA) {
+ ensureCapacity(len+1);
+ text[len] = u;
+ charcode[len] = c;
+ charPos[len] = charPosA;
+ charPos[len + 1] = charPosA + charLen;
+ font[len] = fontA;
+ textMat[len] = textMatA;
+
+ if (len == 0)
+ setInitialBounds(fontA, x, y);
+
+ if (wMode) { // vertical writing mode
+ // NB: the rotation value has been incremented by 1 (in
+ // TextPage::beginWord()) for vertical writing mode
+ switch (rot) {
+ case 0:
+ edge[len] = x - fontSize;
+ xMax = edge[len+1] = x;
+ break;
+ case 1:
+ edge[len] = y - fontSize;
+ yMax = edge[len+1] = y;
+ break;
+ case 2:
+ edge[len] = x + fontSize;
+ xMin = edge[len+1] = x;
+ break;
+ case 3:
+ edge[len] = y + fontSize;
+ yMin = edge[len+1] = y;
+ break;
+ }
+ } else { // horizontal writing mode
+ switch (rot) {
+ case 0:
+ edge[len] = x;
+ xMax = edge[len+1] = x + dx;
+ break;
+ case 1:
+ edge[len] = y;
+ yMax = edge[len+1] = y + dy;
+ break;
+ case 2:
+ edge[len] = x;
+ xMin = edge[len+1] = x + dx;
+ break;
+ case 3:
+ edge[len] = y;
+ yMin = edge[len+1] = y + dy;
+ break;
+ }
+ }
+ ++len;
+}
+
+void TextWord::setInitialBounds(TextFontInfo *fontA, double x, double y) {
+ double ascent = fontA->getAscent() * fontSize;
+ double descent = fontA->getDescent() * fontSize;
+ wMode = fontA->getWMode();
+
+ if (wMode) { // vertical writing mode
+ // NB: the rotation value has been incremented by 1 (in
+ // TextPage::beginWord()) for vertical writing mode
+ switch (rot) {
+ case 0:
+ xMin = x - fontSize;
+ yMin = y - fontSize;
+ yMax = y;
+ base = y;
+ break;
+ case 1:
+ xMin = x;
+ yMin = y - fontSize;
+ xMax = x + fontSize;
+ base = x;
+ break;
+ case 2:
+ yMin = y;
+ xMax = x + fontSize;
+ yMax = y + fontSize;
+ base = y;
+ break;
+ case 3:
+ xMin = x - fontSize;
+ xMax = x;
+ yMax = y + fontSize;
+ base = x;
+ break;
+ }
+ } else { // horizontal writing mode
+ switch (rot) {
+ case 0:
+ xMin = x;
+ yMin = y - ascent;
+ yMax = y - descent;
+ if (yMin == yMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ yMin = y;
+ yMax = y + 1;
+ }
+ base = y;
+ break;
+ case 1:
+ xMin = x + descent;
+ yMin = y;
+ xMax = x + ascent;
+ if (xMin == xMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ xMin = x;
+ xMax = x + 1;
+ }
+ base = x;
+ break;
+ case 2:
+ yMin = y + descent;
+ xMax = x;
+ yMax = y + ascent;
+ if (yMin == yMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ yMin = y;
+ yMax = y + 1;
+ }
+ base = y;
+ break;
+ case 3:
+ xMin = x - ascent;
+ xMax = x - descent;
+ yMax = y;
+ if (xMin == xMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ xMin = x;
+ xMax = x + 1;
+ }
+ base = x;
+ break;
+ }
+ }
+}
+
+void TextWord::ensureCapacity(int capacity) {
+ if (capacity > size) {
+ size = std::max(size + 16, capacity);
+ text = (Unicode *)greallocn(text, size, sizeof(Unicode));
+ charcode = (CharCode *)greallocn(charcode, (size + 1), sizeof(CharCode));
+ edge = (double *)greallocn(edge, (size + 1), sizeof(double));
+ charPos = (int *)greallocn(charPos, size + 1, sizeof(int));
+ font = (TextFontInfo **)greallocn(font, size, sizeof(TextFontInfo *));
+ textMat = (Matrix *)greallocn(textMat, size, sizeof(Matrix));
+ }
+}
+
+struct CombiningTable {
+ Unicode base;
+ Unicode comb;
+};
+
+static struct CombiningTable combiningTable[] = {
+ {0x0060, 0x0300}, // grave
+ {0x00a8, 0x0308}, // dieresis
+ {0x00af, 0x0304}, // macron
+ {0x00b4, 0x0301}, // acute
+ {0x00b8, 0x0327}, // cedilla
+ {0x02c6, 0x0302}, // circumflex
+ {0x02c7, 0x030c}, // caron
+ {0x02d8, 0x0306}, // breve
+ {0x02d9, 0x0307}, // dotaccent
+ {0x02da, 0x030a}, // ring
+ {0x02dc, 0x0303}, // tilde
+ {0x02dd, 0x030b} // hungarumlaut (double acute accent)
+};
+
+// returning combining versions of characters
+Unicode getCombiningChar(Unicode u) {
+ int len = sizeof(combiningTable) / sizeof(combiningTable[0]);
+ for (int i = 0; i < len; ++i) {
+ if (u == combiningTable[i].base)
+ return combiningTable[i].comb;
+ }
+ return 0;
+}
+
+GBool TextWord::addCombining(GfxState *state, TextFontInfo *fontA, double fontSizeA, double x, double y,
+ double dx, double dy, int charPosA, int charLen,
+ CharCode c, Unicode u, const Matrix &textMatA) {
+ if (len == 0 || wMode != 0 || fontA->getWMode() != 0)
+ return gFalse;
+
+ Unicode cCurrent = getCombiningChar(u);
+ Unicode cPrev = getCombiningChar(text[len-1]);
+ double edgeMid = (edge[len-1] + edge[len]) / 2;
+ double charMid, maxScaledMidDelta, charBase, maxScaledBaseDelta;
+
+ if (cCurrent != 0 && unicodeTypeAlphaNum(text[len-1])) {
+ // Current is a combining character, previous is base character
+ maxScaledMidDelta = fabs(edge[len] - edge[len-1]) * combMaxMidDelta;
+ charMid = charBase = maxScaledBaseDelta = 0;
+
+ // Test if characters overlap
+ if (rot == 0 || rot == 2) {
+ charMid = x + (dx / 2);
+ charBase = y;
+ maxScaledBaseDelta = (yMax - yMin) * combMaxBaseDelta;
+ } else {
+ charMid = y + (dy / 2);
+ charBase = x;
+ maxScaledBaseDelta = (xMax - xMin) * combMaxBaseDelta;
+ }
+
+ if (fabs(charMid - edgeMid) >= maxScaledMidDelta ||
+ fabs(charBase - base) >= maxScaledBaseDelta)
+ return gFalse;
+
+ // Add character, but don't adjust edge / bounding box because
+ // combining character's positioning could be odd.
+ ensureCapacity(len+1);
+ text[len] = cCurrent;
+ charcode[len] = c;
+ charPos[len] = charPosA;
+ charPos[len+1] = charPosA + charLen;
+ font[len] = fontA;
+ textMat[len] = textMatA;
+ edge[len+1] = edge[len];
+ edge[len] = (edge[len+1] + edge[len-1]) / 2;
+ ++len;
+ return gTrue;
+ }
+
+ if (cPrev != 0 && unicodeTypeAlphaNum(u)) {
+ // Previous is a combining character, current is base character
+ maxScaledBaseDelta = (fontA->getAscent() - fontA->getDescent()) * fontSizeA * combMaxBaseDelta;
+ charMid = charBase = maxScaledMidDelta = 0;
+
+ // Test if characters overlap
+ if (rot == 0 || rot == 2) {
+ charMid = x + (dx / 2);
+ charBase = y;
+ maxScaledMidDelta = fabs(dx * combMaxMidDelta);
+ } else {
+ charMid = y + (dy / 2);
+ charBase = x;
+ maxScaledMidDelta = fabs(dy * combMaxMidDelta);
+ }
+
+ if (fabs(charMid - edgeMid) >= maxScaledMidDelta ||
+ fabs(charBase - base) >= maxScaledBaseDelta)
+ return gFalse;
+
+ // move combining character to after base character
+ ensureCapacity(len+1);
+ fontSize = fontSizeA;
+ text[len] = cPrev;
+ charcode[len] = charcode[len-1];
+ charPos[len] = charPosA;
+ charPos[len+1] = charPosA + charLen;
+ font[len] = font[len-1];
+ textMat[len] = textMat[len-1];
+
+ text[len-1] = u;
+ charcode[len-1] = c;
+ font[len-1] = fontA;
+ textMat[len-1] = textMatA;
+
+ if (len == 1)
+ setInitialBounds(fontA, x, y);
+
+ // Updated edges / bounding box because we changed the base
+ // character.
+ if (wMode) {
+ switch (rot) {
+ case 0:
+ edge[len-1] = x - fontSize;
+ xMax = edge[len+1] = x;
+ break;
+ case 1:
+ edge[len-1] = y - fontSize;
+ yMax = edge[len+1] = y;
+ break;
+ case 2:
+ edge[len-1] = x + fontSize;
+ xMin = edge[len+1] = x;
+ break;
+ case 3:
+ edge[len-1] = y + fontSize;
+ yMin = edge[len+1] = y;
+ break;
+ }
+ } else {
+ switch (rot) {
+ case 0:
+ edge[len-1] = x;
+ xMax = edge[len+1] = x + dx;
+ break;
+ case 1:
+ edge[len-1] = y;
+ yMax = edge[len+1] = y + dy;
+ break;
+ case 2:
+ edge[len-1] = x;
+ xMin = edge[len+1] = x + dx;
+ break;
+ case 3:
+ edge[len-1] = y;
+ yMin = edge[len+1] = y + dy;
+ break;
+ }
+ }
+
+ edge[len] = (edge[len+1] + edge[len-1]) / 2;
+ ++len;
+ return gTrue;
+ }
+ return gFalse;
+}
+
+void TextWord::merge(TextWord *word) {
+ int i;
+
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
+ }
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
+ }
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ ensureCapacity(len + word->len);
+ for (i = 0; i < word->len; ++i) {
+ text[len + i] = word->text[i];
+ charcode[len + i] = word->charcode[i];
+ edge[len + i] = word->edge[i];
+ charPos[len + i] = word->charPos[i];
+ font[len + i] = word->font[i];
+ textMat[len + i] = word->textMat[i];
+ }
+ edge[len + word->len] = word->edge[word->len];
+ charPos[len + word->len] = word->charPos[word->len];
+ len += word->len;
+}
+
+inline int TextWord::primaryCmp(TextWord *word) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - word->xMin;
+ break;
+ case 1:
+ cmp = yMin - word->yMin;
+ break;
+ case 2:
+ cmp = word->xMax - xMax;
+ break;
+ case 3:
+ cmp = word->yMax - yMax;
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+double TextWord::primaryDelta(TextWord *word) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = word->xMin - xMax;
+ break;
+ case 1:
+ delta = word->yMin - yMax;
+ break;
+ case 2:
+ delta = xMin - word->xMax;
+ break;
+ case 3:
+ delta = yMin - word->yMax;
+ break;
+ }
+ return delta;
+}
+
+int TextWord::cmpYX(const void *p1, const void *p2) {
+ TextWord *word1 = *(TextWord **)p1;
+ TextWord *word2 = *(TextWord **)p2;
+ double cmp;
+
+ cmp = word1->yMin - word2->yMin;
+ if (cmp == 0) {
+ cmp = word1->xMin - word2->xMin;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+#if TEXTOUT_WORD_LIST
+
+GooString *TextWord::getText() {
+ GooString *s;
+ UnicodeMap *uMap;
+ char buf[8];
+ int n, i;
+
+ s = new GooString();
+ if (!(uMap = globalParams->getTextEncoding())) {
+ return s;
+ }
+ for (i = 0; i < len; ++i) {
+ n = uMap->mapUnicode(text[i], buf, sizeof(buf));
+ s->append(buf, n);
+ }
+ uMap->decRefCnt();
+ return s;
+}
+
+void TextWord::getCharBBox(int charIdx, double *xMinA, double *yMinA,
+ double *xMaxA, double *yMaxA) {
+ if (charIdx < 0 || charIdx >= len) {
+ return;
+ }
+ switch (rot) {
+ case 0:
+ *xMinA = edge[charIdx];
+ *xMaxA = edge[charIdx + 1];
+ *yMinA = yMin;
+ *yMaxA = yMax;
+ break;
+ case 1:
+ *xMinA = xMin;
+ *xMaxA = xMax;
+ *yMinA = edge[charIdx];
+ *yMaxA = edge[charIdx + 1];
+ break;
+ case 2:
+ *xMinA = edge[charIdx + 1];
+ *xMaxA = edge[charIdx];
+ *yMinA = yMin;
+ *yMaxA = yMax;
+ break;
+ case 3:
+ *xMinA = xMin;
+ *xMaxA = xMax;
+ *yMinA = edge[charIdx + 1];
+ *yMaxA = edge[charIdx];
+ break;
+ }
+}
+
+#endif // TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextPool
+//------------------------------------------------------------------------
+
+TextPool::TextPool() {
+ minBaseIdx = 0;
+ maxBaseIdx = -1;
+ pool = NULL;
+ cursor = NULL;
+ cursorBaseIdx = -1;
+}
+
+TextPool::~TextPool() {
+ int baseIdx;
+ TextWord *word, *word2;
+
+ for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
+ for (word = pool[baseIdx - minBaseIdx]; word; word = word2) {
+ word2 = word->next;
+ delete word;
+ }
+ }
+ gfree(pool);
+}
+
+int TextPool::getBaseIdx(double base) {
+ int baseIdx;
+
+ baseIdx = (int)(base / textPoolStep);
+ if (baseIdx < minBaseIdx) {
+ return minBaseIdx;
+ }
+ if (baseIdx > maxBaseIdx) {
+ return maxBaseIdx;
+ }
+ return baseIdx;
+}
+
+void TextPool::addWord(TextWord *word) {
+ TextWord **newPool;
+ int wordBaseIdx, newMinBaseIdx, newMaxBaseIdx, baseIdx;
+ TextWord *w0, *w1;
+
+ // expand the array if needed
+ if (unlikely((word->base / textPoolStep) > INT_MAX)) {
+ error(errSyntaxWarning, -1, "word->base / textPoolStep > INT_MAX");
+ return;
+ }
+ wordBaseIdx = (int)(word->base / textPoolStep);
+ if (minBaseIdx > maxBaseIdx) {
+ minBaseIdx = wordBaseIdx - 128;
+ maxBaseIdx = wordBaseIdx + 128;
+ pool = (TextWord **)gmallocn(maxBaseIdx - minBaseIdx + 1,
+ sizeof(TextWord *));
+ for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
+ pool[baseIdx - minBaseIdx] = NULL;
+ }
+ } else if (wordBaseIdx < minBaseIdx) {
+ newMinBaseIdx = wordBaseIdx - 128;
+ newPool = (TextWord **)gmallocn(maxBaseIdx - newMinBaseIdx + 1,
+ sizeof(TextWord *));
+ for (baseIdx = newMinBaseIdx; baseIdx < minBaseIdx; ++baseIdx) {
+ newPool[baseIdx - newMinBaseIdx] = NULL;
+ }
+ memcpy(&newPool[minBaseIdx - newMinBaseIdx], pool,
+ (maxBaseIdx - minBaseIdx + 1) * sizeof(TextWord *));
+ gfree(pool);
+ pool = newPool;
+ minBaseIdx = newMinBaseIdx;
+ } else if (wordBaseIdx > maxBaseIdx) {
+ newMaxBaseIdx = wordBaseIdx + 128;
+ pool = (TextWord **)greallocn(pool, newMaxBaseIdx - minBaseIdx + 1,
+ sizeof(TextWord *));
+ for (baseIdx = maxBaseIdx + 1; baseIdx <= newMaxBaseIdx; ++baseIdx) {
+ pool[baseIdx - minBaseIdx] = NULL;
+ }
+ maxBaseIdx = newMaxBaseIdx;
+ }
+
+ // insert the new word
+ if (cursor && wordBaseIdx == cursorBaseIdx &&
+ word->primaryCmp(cursor) >= 0) {
+ w0 = cursor;
+ w1 = cursor->next;
+ } else {
+ w0 = NULL;
+ w1 = pool[wordBaseIdx - minBaseIdx];
+ }
+ for (; w1 && word->primaryCmp(w1) > 0; w0 = w1, w1 = w1->next) ;
+ word->next = w1;
+ if (w0) {
+ w0->next = word;
+ } else {
+ pool[wordBaseIdx - minBaseIdx] = word;
+ }
+ cursor = word;
+ cursorBaseIdx = wordBaseIdx;
+}
+
+//------------------------------------------------------------------------
+// TextLine
+//------------------------------------------------------------------------
+
+TextLine::TextLine(TextBlock *blkA, int rotA, double baseA) {
+ blk = blkA;
+ rot = rotA;
+ base = baseA;
+ words = lastWord = NULL;
+ text = NULL;
+ edge = NULL;
+ col = NULL;
+ len = 0;
+ convertedLen = 0;
+ hyphenated = gFalse;
+ next = NULL;
+ xMin = yMin = 0;
+ xMax = yMax = -1;
+ normalized = NULL;
+ normalized_len = 0;
+ normalized_idx = NULL;
+}
+
+TextLine::~TextLine() {
+ TextWord *word;
+
+ while (words) {
+ word = words;
+ words = words->next;
+ delete word;
+ }
+ gfree(text);
+ gfree(edge);
+ gfree(col);
+ if (normalized) {
+ gfree(normalized);
+ gfree(normalized_idx);
+ }
+}
+
+void TextLine::addWord(TextWord *word) {
+ if (lastWord) {
+ lastWord->next = word;
+ } else {
+ words = word;
+ }
+ lastWord = word;
+
+ if (xMin > xMax) {
+ xMin = word->xMin;
+ xMax = word->xMax;
+ yMin = word->yMin;
+ yMax = word->yMax;
+ } else {
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
+ }
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ }
+}
+
+double TextLine::primaryDelta(TextLine *line) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = line->xMin - xMax;
+ break;
+ case 1:
+ delta = line->yMin - yMax;
+ break;
+ case 2:
+ delta = xMin - line->xMax;
+ break;
+ case 3:
+ delta = yMin - line->yMax;
+ break;
+ }
+ return delta;
+}
+
+int TextLine::primaryCmp(TextLine *line) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - line->xMin;
+ break;
+ case 1:
+ cmp = yMin - line->yMin;
+ break;
+ case 2:
+ cmp = line->xMax - xMax;
+ break;
+ case 3:
+ cmp = line->yMax - yMax;
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLine::secondaryCmp(TextLine *line) {
+ double cmp;
+
+ cmp = (rot == 0 || rot == 3) ? base - line->base : line->base - base;
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLine::cmpYX(TextLine *line) {
+ int cmp;
+
+ if ((cmp = secondaryCmp(line))) {
+ return cmp;
+ }
+ return primaryCmp(line);
+}
+
+int TextLine::cmpXY(const void *p1, const void *p2) {
+ TextLine *line1 = *(TextLine **)p1;
+ TextLine *line2 = *(TextLine **)p2;
+ int cmp;
+
+ if ((cmp = line1->primaryCmp(line2))) {
+ return cmp;
+ }
+ return line1->secondaryCmp(line2);
+}
+
+void TextLine::coalesce(UnicodeMap *uMap) {
+ TextWord *word0, *word1;
+ double space, delta, minSpace;
+ GBool isUnicode;
+ char buf[8];
+ int i, j;
+
+ if (words->next) {
+
+ // compute the inter-word space threshold
+ if (words->len > 1 || words->next->len > 1) {
+ minSpace = 0;
+ } else {
+ minSpace = words->primaryDelta(words->next);
+ for (word0 = words->next, word1 = word0->next;
+ word1 && minSpace > 0;
+ word0 = word1, word1 = word0->next) {
+ if (word1->len > 1) {
+ minSpace = 0;
+ }
+ delta = word0->primaryDelta(word1);
+ if (delta < minSpace) {
+ minSpace = delta;
+ }
+ }
+ }
+ if (minSpace <= 0) {
+ space = maxCharSpacing * words->fontSize;
+ } else {
+ space = maxWideCharSpacingMul * minSpace;
+ if (space > maxWideCharSpacing * words->fontSize) {
+ space = maxWideCharSpacing * words->fontSize;
+ }
+ }
+
+ // merge words
+ word0 = words;
+ word1 = words->next;
+ while (word1) {
+ if (word0->primaryDelta(word1) >= space) {
+ word0->spaceAfter = gTrue;
+ word0 = word1;
+ word1 = word1->next;
+ } else if (word0->font[word0->len - 1] == word1->font[0] &&
+ word0->underlined == word1->underlined &&
+ fabs(word0->fontSize - word1->fontSize) <
+ maxWordFontSizeDelta * words->fontSize &&
+ word1->charPos[0] == word0->charPos[word0->len]) {
+ word0->merge(word1);
+ word0->next = word1->next;
+ delete word1;
+ word1 = word0->next;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+
+ // build the line text
+ isUnicode = uMap ? uMap->isUnicode() : gFalse;
+ len = 0;
+ for (word1 = words; word1; word1 = word1->next) {
+ len += word1->len;
+ if (word1->spaceAfter) {
+ ++len;
+ }
+ }
+ text = (Unicode *)gmallocn(len, sizeof(Unicode));
+ edge = (double *)gmallocn(len + 1, sizeof(double));
+ i = 0;
+ for (word1 = words; word1; word1 = word1->next) {
+ for (j = 0; j < word1->len; ++j) {
+ text[i] = word1->text[j];
+ edge[i] = word1->edge[j];
+ ++i;
+ }
+ edge[i] = word1->edge[word1->len];
+ if (word1->spaceAfter) {
+ text[i] = (Unicode)0x0020;
+ ++i;
+ }
+ }
+
+ // compute convertedLen and set up the col array
+ col = (int *)gmallocn(len + 1, sizeof(int));
+ convertedLen = 0;
+ for (i = 0; i < len; ++i) {
+ col[i] = convertedLen;
+ if (isUnicode) {
+ ++convertedLen;
+ } else if (uMap) {
+ convertedLen += uMap->mapUnicode(text[i], buf, sizeof(buf));
+ }
+ }
+ col[len] = convertedLen;
+
+ // check for hyphen at end of line
+ //~ need to check for other chars used as hyphens
+ hyphenated = text[len - 1] == (Unicode)'-';
+}
+
+//------------------------------------------------------------------------
+// TextLineFrag
+//------------------------------------------------------------------------
+
+class TextLineFrag {
+public:
+
+ TextLine *line; // the line object
+ int start, len; // offset and length of this fragment
+ // (in Unicode chars)
+ double xMin, xMax; // bounding box coordinates
+ double yMin, yMax;
+ double base; // baseline virtual coordinate
+ int col; // first column
+
+ void init(TextLine *lineA, int startA, int lenA);
+ void computeCoords(GBool oneRot);
+
+ static int cmpYXPrimaryRot(const void *p1, const void *p2);
+ static int cmpYXLineRot(const void *p1, const void *p2);
+ static int cmpXYLineRot(const void *p1, const void *p2);
+ static int cmpXYColumnPrimaryRot(const void *p1, const void *p2);
+ static int cmpXYColumnLineRot(const void *p1, const void *p2);
+};
+
+void TextLineFrag::init(TextLine *lineA, int startA, int lenA) {
+ line = lineA;
+ start = startA;
+ len = lenA;
+ col = line->col[start];
+}
+
+void TextLineFrag::computeCoords(GBool oneRot) {
+ TextBlock *blk;
+ double d0, d1, d2, d3, d4;
+
+ if (oneRot) {
+
+ switch (line->rot) {
+ case 0:
+ xMin = line->edge[start];
+ xMax = line->edge[start + len];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ break;
+ case 1:
+ xMin = line->xMin;
+ xMax = line->xMax;
+ yMin = line->edge[start];
+ yMax = line->edge[start + len];
+ break;
+ case 2:
+ xMin = line->edge[start + len];
+ xMax = line->edge[start];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ break;
+ case 3:
+ xMin = line->xMin;
+ xMax = line->xMax;
+ yMin = line->edge[start + len];
+ yMax = line->edge[start];
+ break;
+ }
+ base = line->base;
+
+ } else {
+
+ if (line->rot == 0 && line->blk->page->primaryRot == 0) {
+
+ xMin = line->edge[start];
+ xMax = line->edge[start + len];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ base = line->base;
+
+ } else {
+
+ blk = line->blk;
+ d0 = line->edge[start];
+ d1 = line->edge[start + len];
+ d2 = d3 = d4 = 0; // make gcc happy
+
+ switch (line->rot) {
+ case 0:
+ d2 = line->yMin;
+ d3 = line->yMax;
+ d4 = line->base;
+ d0 = (d0 - blk->xMin) / (blk->xMax - blk->xMin);
+ d1 = (d1 - blk->xMin) / (blk->xMax - blk->xMin);
+ d2 = (d2 - blk->yMin) / (blk->yMax - blk->yMin);
+ d3 = (d3 - blk->yMin) / (blk->yMax - blk->yMin);
+ d4 = (d4 - blk->yMin) / (blk->yMax - blk->yMin);
+ break;
+ case 1:
+ d2 = line->xMax;
+ d3 = line->xMin;
+ d4 = line->base;
+ d0 = (d0 - blk->yMin) / (blk->yMax - blk->yMin);
+ d1 = (d1 - blk->yMin) / (blk->yMax - blk->yMin);
+ d2 = (blk->xMax - d2) / (blk->xMax - blk->xMin);
+ d3 = (blk->xMax - d3) / (blk->xMax - blk->xMin);
+ d4 = (blk->xMax - d4) / (blk->xMax - blk->xMin);
+ break;
+ case 2:
+ d2 = line->yMax;
+ d3 = line->yMin;
+ d4 = line->base;
+ d0 = (blk->xMax - d0) / (blk->xMax - blk->xMin);
+ d1 = (blk->xMax - d1) / (blk->xMax - blk->xMin);
+ d2 = (blk->yMax - d2) / (blk->yMax - blk->yMin);
+ d3 = (blk->yMax - d3) / (blk->yMax - blk->yMin);
+ d4 = (blk->yMax - d4) / (blk->yMax - blk->yMin);
+ break;
+ case 3:
+ d2 = line->xMin;
+ d3 = line->xMax;
+ d4 = line->base;
+ d0 = (blk->yMax - d0) / (blk->yMax - blk->yMin);
+ d1 = (blk->yMax - d1) / (blk->yMax - blk->yMin);
+ d2 = (d2 - blk->xMin) / (blk->xMax - blk->xMin);
+ d3 = (d3 - blk->xMin) / (blk->xMax - blk->xMin);
+ d4 = (d4 - blk->xMin) / (blk->xMax - blk->xMin);
+ break;
+ }
+
+ switch (line->blk->page->primaryRot) {
+ case 0:
+ xMin = blk->xMin + d0 * (blk->xMax - blk->xMin);
+ xMax = blk->xMin + d1 * (blk->xMax - blk->xMin);
+ yMin = blk->yMin + d2 * (blk->yMax - blk->yMin);
+ yMax = blk->yMin + d3 * (blk->yMax - blk->yMin);
+ base = blk->yMin + d4 * (blk->yMax - blk->yMin);
+ break;
+ case 1:
+ xMin = blk->xMax - d3 * (blk->xMax - blk->xMin);
+ xMax = blk->xMax - d2 * (blk->xMax - blk->xMin);
+ yMin = blk->yMin + d0 * (blk->yMax - blk->yMin);
+ yMax = blk->yMin + d1 * (blk->yMax - blk->yMin);
+ base = blk->xMax - d4 * (blk->xMax - blk->xMin);
+ break;
+ case 2:
+ xMin = blk->xMax - d1 * (blk->xMax - blk->xMin);
+ xMax = blk->xMax - d0 * (blk->xMax - blk->xMin);
+ yMin = blk->yMax - d3 * (blk->yMax - blk->yMin);
+ yMax = blk->yMax - d2 * (blk->yMax - blk->yMin);
+ base = blk->yMax - d4 * (blk->yMax - blk->yMin);
+ break;
+ case 3:
+ xMin = blk->xMin + d2 * (blk->xMax - blk->xMin);
+ xMax = blk->xMin + d3 * (blk->xMax - blk->xMin);
+ yMin = blk->yMax - d1 * (blk->yMax - blk->yMin);
+ yMax = blk->yMax - d0 * (blk->yMax - blk->yMin);
+ base = blk->xMin + d4 * (blk->xMax - blk->xMin);
+ break;
+ }
+
+ }
+ }
+}
+
+int TextLineFrag::cmpYXPrimaryRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (frag1->line->blk->page->primaryRot) {
+ case 0:
+ if (fabs(cmp = frag1->yMin - frag2->yMin) < 0.01) {
+ cmp = frag1->xMin - frag2->xMin;
+ }
+ break;
+ case 1:
+ if (fabs(cmp = frag2->xMax - frag1->xMax) < 0.01) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 2:
+ if (fabs(cmp = frag2->yMin - frag1->yMin) < 0.01) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 3:
+ if (fabs(cmp = frag1->xMax - frag2->xMax) < 0.01) {
+ cmp = frag2->yMax - frag1->yMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLineFrag::cmpYXLineRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (frag1->line->rot) {
+ case 0:
+ if ((cmp = frag1->yMin - frag2->yMin) == 0) {
+ cmp = frag1->xMin - frag2->xMin;
+ }
+ break;
+ case 1:
+ if ((cmp = frag2->xMax - frag1->xMax) == 0) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 2:
+ if ((cmp = frag2->yMin - frag1->yMin) == 0) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 3:
+ if ((cmp = frag1->xMax - frag2->xMax) == 0) {
+ cmp = frag2->yMax - frag1->yMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLineFrag::cmpXYLineRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (frag1->line->rot) {
+ case 0:
+ if ((cmp = frag1->xMin - frag2->xMin) == 0) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 1:
+ if ((cmp = frag1->yMin - frag2->yMin) == 0) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 2:
+ if ((cmp = frag2->xMax - frag1->xMax) == 0) {
+ cmp = frag2->yMin - frag1->yMin;
+ }
+ break;
+ case 3:
+ if ((cmp = frag2->yMax - frag1->yMax) == 0) {
+ cmp = frag1->xMax - frag2->xMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLineFrag::cmpXYColumnPrimaryRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ // if columns overlap, compare y values
+ if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] -
+ frag2->line->col[frag2->start]) &&
+ frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start])) {
+ cmp = 0; // make gcc happy
+ switch (frag1->line->blk->page->primaryRot) {
+ case 0: cmp = frag1->yMin - frag2->yMin; break;
+ case 1: cmp = frag2->xMax - frag1->xMax; break;
+ case 2: cmp = frag2->yMin - frag1->yMin; break;
+ case 3: cmp = frag1->xMax - frag2->xMax; break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+ }
+
+ // otherwise, compare starting column
+ return frag1->col - frag2->col;
+}
+
+int TextLineFrag::cmpXYColumnLineRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ // if columns overlap, compare y values
+ if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] -
+ frag2->line->col[frag2->start]) &&
+ frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start])) {
+ cmp = 0; // make gcc happy
+ switch (frag1->line->rot) {
+ case 0: cmp = frag1->yMin - frag2->yMin; break;
+ case 1: cmp = frag2->xMax - frag1->xMax; break;
+ case 2: cmp = frag2->yMin - frag1->yMin; break;
+ case 3: cmp = frag1->xMax - frag2->xMax; break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+ }
+
+ // otherwise, compare starting column
+ return frag1->col - frag2->col;
+}
+
+//------------------------------------------------------------------------
+// TextBlock
+//------------------------------------------------------------------------
+
+TextBlock::TextBlock(TextPage *pageA, int rotA) {
+ page = pageA;
+ rot = rotA;
+ xMin = yMin = 0;
+ xMax = yMax = -1;
+ priMin = 0;
+ priMax = page->pageWidth;
+ pool = new TextPool();
+ lines = NULL;
+ curLine = NULL;
+ next = NULL;
+ stackNext = NULL;
+ tableId = -1;
+ tableEnd = gFalse;
+}
+
+TextBlock::~TextBlock() {
+ TextLine *line;
+
+ delete pool;
+ while (lines) {
+ line = lines;
+ lines = lines->next;
+ delete line;
+ }
+}
+
+void TextBlock::addWord(TextWord *word) {
+ pool->addWord(word);
+ if (xMin > xMax) {
+ xMin = word->xMin;
+ xMax = word->xMax;
+ yMin = word->yMin;
+ yMax = word->yMax;
+ } else {
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
+ }
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ }
+}
+
+void TextBlock::coalesce(UnicodeMap *uMap, double fixedPitch) {
+ TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord;
+ TextLine *line, *line0, *line1;
+ int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx;
+ int baseIdx, bestWordBaseIdx, idx0, idx1;
+ double minBase, maxBase;
+ double fontSize, wordSpacing, delta, priDelta, secDelta;
+ TextLine **lineArray;
+ GBool found, overlap;
+ int col1, col2;
+ int i, j, k;
+
+ // discard duplicated text (fake boldface, drop shadows)
+ for (idx0 = pool->minBaseIdx; idx0 <= pool->maxBaseIdx; ++idx0) {
+ word0 = pool->getPool(idx0);
+ while (word0) {
+ priDelta = dupMaxPriDelta * word0->fontSize;
+ secDelta = dupMaxSecDelta * word0->fontSize;
+ maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
+ found = gFalse;
+ word1 = word2 = NULL; // make gcc happy
+ for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) {
+ if (idx1 == idx0) {
+ word1 = word0;
+ word2 = word0->next;
+ } else {
+ word1 = NULL;
+ word2 = pool->getPool(idx1);
+ }
+ for (; word2; word1 = word2, word2 = word2->next) {
+ if (word2->len == word0->len &&
+ !memcmp(word2->text, word0->text,
+ word0->len * sizeof(Unicode))) {
+ switch (rot) {
+ case 0:
+ case 2:
+ found = fabs(word0->xMin - word2->xMin) < priDelta &&
+ fabs(word0->xMax - word2->xMax) < priDelta &&
+ fabs(word0->yMin - word2->yMin) < secDelta &&
+ fabs(word0->yMax - word2->yMax) < secDelta;
+ break;
+ case 1:
+ case 3:
+ found = fabs(word0->xMin - word2->xMin) < secDelta &&
+ fabs(word0->xMax - word2->xMax) < secDelta &&
+ fabs(word0->yMin - word2->yMin) < priDelta &&
+ fabs(word0->yMax - word2->yMax) < priDelta;
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ if (word1) {
+ word1->next = word2->next;
+ } else {
+ pool->setPool(idx1, word2->next);
+ }
+ delete word2;
+ } else {
+ word0 = word0->next;
+ }
+ }
+ }
+
+ // build the lines
+ curLine = NULL;
+ poolMinBaseIdx = pool->minBaseIdx;
+ charCount = 0;
+ nLines = 0;
+ while (1) {
+
+ // find the first non-empty line in the pool
+ for (;
+ poolMinBaseIdx <= pool->maxBaseIdx && !pool->getPool(poolMinBaseIdx);
+ ++poolMinBaseIdx) ;
+ if (poolMinBaseIdx > pool->maxBaseIdx) {
+ break;
+ }
+
+ // look for the left-most word in the first four lines of the
+ // pool -- this avoids starting with a superscript word
+ startBaseIdx = poolMinBaseIdx;
+ for (baseIdx = poolMinBaseIdx + 1;
+ baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx;
+ ++baseIdx) {
+ if (!pool->getPool(baseIdx)) {
+ continue;
+ }
+ if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx))
+ < 0) {
+ startBaseIdx = baseIdx;
+ }
+ }
+
+ // create a new line
+ word0 = pool->getPool(startBaseIdx);
+ pool->setPool(startBaseIdx, word0->next);
+ word0->next = NULL;
+ line = new TextLine(this, word0->rot, word0->base);
+ line->addWord(word0);
+ lastWord = word0;
+
+ // compute the search range
+ fontSize = word0->fontSize;
+ minBase = word0->base - maxIntraLineDelta * fontSize;
+ maxBase = word0->base + maxIntraLineDelta * fontSize;
+ minBaseIdx = pool->getBaseIdx(minBase);
+ maxBaseIdx = pool->getBaseIdx(maxBase);
+ wordSpacing = fixedPitch ? fixedPitch : maxWordSpacing * fontSize;
+
+ // find the rest of the words in this line
+ while (1) {
+
+ // find the left-most word whose baseline is in the range for
+ // this line
+ bestWordBaseIdx = 0;
+ bestWord0 = bestWord1 = NULL;
+ overlap = gFalse;
+ for (baseIdx = minBaseIdx;
+ !overlap && baseIdx <= maxBaseIdx;
+ ++baseIdx) {
+ for (word0 = NULL, word1 = pool->getPool(baseIdx);
+ word1;
+ word0 = word1, word1 = word1->next) {
+ if (word1->base >= minBase &&
+ word1->base <= maxBase) {
+ delta = lastWord->primaryDelta(word1);
+ if (delta < minCharSpacing * fontSize) {
+ overlap = gTrue;
+ break;
+ } else {
+ if (delta < wordSpacing &&
+ (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
+ bestWordBaseIdx = baseIdx;
+ bestWord0 = word0;
+ bestWord1 = word1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (overlap || !bestWord1) {
+ break;
+ }
+
+ // remove it from the pool, and add it to the line
+ if (bestWord0) {
+ bestWord0->next = bestWord1->next;
+ } else {
+ pool->setPool(bestWordBaseIdx, bestWord1->next);
+ }
+ bestWord1->next = NULL;
+ line->addWord(bestWord1);
+ lastWord = bestWord1;
+ }
+
+ // add the line
+ if (curLine && line->cmpYX(curLine) > 0) {
+ line0 = curLine;
+ line1 = curLine->next;
+ } else {
+ line0 = NULL;
+ line1 = lines;
+ }
+ for (;
+ line1 && line->cmpYX(line1) > 0;
+ line0 = line1, line1 = line1->next) ;
+ if (line0) {
+ line0->next = line;
+ } else {
+ lines = line;
+ }
+ line->next = line1;
+ curLine = line;
+ line->coalesce(uMap);
+ charCount += line->len;
+ ++nLines;
+ }
+
+ // sort lines into xy order for column assignment
+ lineArray = (TextLine **)gmallocn(nLines, sizeof(TextLine *));
+ for (line = lines, i = 0; line; line = line->next, ++i) {
+ lineArray[i] = line;
+ }
+ qsort(lineArray, nLines, sizeof(TextLine *), &TextLine::cmpXY);
+
+ // column assignment
+ nColumns = 0;
+ if (fixedPitch) {
+ for (i = 0; i < nLines; ++i) {
+ line0 = lineArray[i];
+ col1 = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ col1 = (int)((line0->xMin - xMin) / fixedPitch + 0.5);
+ break;
+ case 1:
+ col1 = (int)((line0->yMin - yMin) / fixedPitch + 0.5);
+ break;
+ case 2:
+ col1 = (int)((xMax - line0->xMax) / fixedPitch + 0.5);
+ break;
+ case 3:
+ col1 = (int)((yMax - line0->yMax) / fixedPitch + 0.5);
+ break;
+ }
+ for (k = 0; k <= line0->len; ++k) {
+ line0->col[k] += col1;
+ }
+ if (line0->col[line0->len] > nColumns) {
+ nColumns = line0->col[line0->len];
+ }
+ }
+ } else {
+ for (i = 0; i < nLines; ++i) {
+ line0 = lineArray[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ line1 = lineArray[j];
+ if (line1->primaryDelta(line0) >= 0) {
+ col2 = line1->col[line1->len] + 1;
+ } else {
+ k = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ for (k = 0;
+ k < line1->len &&
+ line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 1:
+ for (k = 0;
+ k < line1->len &&
+ line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 2:
+ for (k = 0;
+ k < line1->len &&
+ line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 3:
+ for (k = 0;
+ k < line1->len &&
+ line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ }
+ col2 = line1->col[k];
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ for (k = 0; k <= line0->len; ++k) {
+ line0->col[k] += col1;
+ }
+ if (line0->col[line0->len] > nColumns) {
+ nColumns = line0->col[line0->len];
+ }
+ }
+ }
+ gfree(lineArray);
+}
+
+void TextBlock::updatePriMinMax(TextBlock *blk) {
+ double newPriMin, newPriMax;
+ GBool gotPriMin, gotPriMax;
+
+ gotPriMin = gotPriMax = gFalse;
+ newPriMin = newPriMax = 0; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ case 2:
+ if (blk->yMin < yMax && blk->yMax > yMin) {
+ if (blk->xMin < xMin) {
+ newPriMin = blk->xMax;
+ gotPriMin = gTrue;
+ }
+ if (blk->xMax > xMax) {
+ newPriMax = blk->xMin;
+ gotPriMax = gTrue;
+ }
+ }
+ break;
+ case 1:
+ case 3:
+ if (blk->xMin < xMax && blk->xMax > xMin) {
+ if (blk->yMin < yMin) {
+ newPriMin = blk->yMax;
+ gotPriMin = gTrue;
+ }
+ if (blk->yMax > yMax) {
+ newPriMax = blk->yMin;
+ gotPriMax = gTrue;
+ }
+ }
+ break;
+ }
+ if (gotPriMin) {
+ if (newPriMin > xMin) {
+ newPriMin = xMin;
+ }
+ if (newPriMin > priMin) {
+ priMin = newPriMin;
+ }
+ }
+ if (gotPriMax) {
+ if (newPriMax < xMax) {
+ newPriMax = xMax;
+ }
+ if (newPriMax < priMax) {
+ priMax = newPriMax;
+ }
+ }
+}
+
+int TextBlock::cmpXYPrimaryRot(const void *p1, const void *p2) {
+ TextBlock *blk1 = *(TextBlock **)p1;
+ TextBlock *blk2 = *(TextBlock **)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (blk1->page->primaryRot) {
+ case 0:
+ if ((cmp = blk1->xMin - blk2->xMin) == 0) {
+ cmp = blk1->yMin - blk2->yMin;
+ }
+ break;
+ case 1:
+ if ((cmp = blk1->yMin - blk2->yMin) == 0) {
+ cmp = blk2->xMax - blk1->xMax;
+ }
+ break;
+ case 2:
+ if ((cmp = blk2->xMax - blk1->xMax) == 0) {
+ cmp = blk2->yMin - blk1->yMin;
+ }
+ break;
+ case 3:
+ if ((cmp = blk2->yMax - blk1->yMax) == 0) {
+ cmp = blk1->xMax - blk2->xMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextBlock::cmpYXPrimaryRot(const void *p1, const void *p2) {
+ TextBlock *blk1 = *(TextBlock **)p1;
+ TextBlock *blk2 = *(TextBlock **)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (blk1->page->primaryRot) {
+ case 0:
+ if ((cmp = blk1->yMin - blk2->yMin) == 0) {
+ cmp = blk1->xMin - blk2->xMin;
+ }
+ break;
+ case 1:
+ if ((cmp = blk2->xMax - blk1->xMax) == 0) {
+ cmp = blk1->yMin - blk2->yMin;
+ }
+ break;
+ case 2:
+ if ((cmp = blk2->yMin - blk1->yMin) == 0) {
+ cmp = blk2->xMax - blk1->xMax;
+ }
+ break;
+ case 3:
+ if ((cmp = blk1->xMax - blk2->xMax) == 0) {
+ cmp = blk2->yMax - blk1->yMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextBlock::primaryCmp(TextBlock *blk) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - blk->xMin;
+ break;
+ case 1:
+ cmp = yMin - blk->yMin;
+ break;
+ case 2:
+ cmp = blk->xMax - xMax;
+ break;
+ case 3:
+ cmp = blk->yMax - yMax;
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+double TextBlock::secondaryDelta(TextBlock *blk) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = blk->yMin - yMax;
+ break;
+ case 1:
+ delta = xMin - blk->xMax;
+ break;
+ case 2:
+ delta = yMin - blk->yMax;
+ break;
+ case 3:
+ delta = blk->xMin - xMax;
+ break;
+ }
+ return delta;
+}
+
+GBool TextBlock::isBelow(TextBlock *blk) {
+ GBool below;
+
+ below = gFalse; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ below = xMin >= blk->priMin && xMax <= blk->priMax &&
+ yMin > blk->yMin;
+ break;
+ case 1:
+ below = yMin >= blk->priMin && yMax <= blk->priMax &&
+ xMax < blk->xMax;
+ break;
+ case 2:
+ below = xMin >= blk->priMin && xMax <= blk->priMax &&
+ yMax < blk->yMax;
+ break;
+ case 3:
+ below = yMin >= blk->priMin && yMax <= blk->priMax &&
+ xMin > blk->xMin;
+ break;
+ }
+
+ return below;
+}
+
+GBool TextBlock::isBeforeByRule1(TextBlock *blk1) {
+ GBool before = gFalse;
+ GBool overlap = gFalse;
+
+ switch (this->page->primaryRot) {
+ case 0:
+ case 2:
+ overlap = ((this->ExMin <= blk1->ExMin) &&
+ (blk1->ExMin <= this->ExMax)) ||
+ ((blk1->ExMin <= this->ExMin) &&
+ (this->ExMin <= blk1->ExMax));
+ break;
+ case 1:
+ case 3:
+ overlap = ((this->EyMin <= blk1->EyMin) &&
+ (blk1->EyMin <= this->EyMax)) ||
+ ((blk1->EyMin <= this->EyMin) &&
+ (this->EyMin <= blk1->EyMax));
+ break;
+ }
+ switch (this->page->primaryRot) {
+ case 0:
+ before = overlap && this->EyMin < blk1->EyMin;
+ break;
+ case 1:
+ before = overlap && this->ExMax > blk1->ExMax;
+ break;
+ case 2:
+ before = overlap && this->EyMax > blk1->EyMax;
+ break;
+ case 3:
+ before = overlap && this->ExMin < blk1->ExMin;
+ break;
+ }
+ return before;
+}
+
+GBool TextBlock::isBeforeByRule2(TextBlock *blk1) {
+ double cmp = 0;
+ int rotLR = rot;
+
+ if (!page->primaryLR) {
+ rotLR = (rotLR + 2) % 4;
+ }
+
+ switch (rotLR) {
+ case 0:
+ cmp = ExMax - blk1->ExMin;
+ break;
+ case 1:
+ cmp = EyMin - blk1->EyMax;
+ break;
+ case 2:
+ cmp = blk1->ExMax - ExMin;
+ break;
+ case 3:
+ cmp = blk1->EyMin - EyMax;
+ break;
+ }
+ return cmp <= 0;
+}
+
+// Sort into reading order by performing a topological sort using the rules
+// given in "High Performance Document Layout Analysis", T.M. Breuel, 2003.
+// See http://pubs.iupr.org/#2003-breuel-sdiut
+// Topological sort is done by depth first search, see
+// http://en.wikipedia.org/wiki/Topological_sorting
+int TextBlock::visitDepthFirst(TextBlock *blkList, int pos1,
+ TextBlock **sorted, int sortPos,
+ GBool* visited) {
+ int pos2;
+ TextBlock *blk1, *blk2, *blk3;
+ GBool before;
+
+ if (visited[pos1]) {
+ return sortPos;
+ }
+
+ blk1 = this;
+
+#if 0 // for debugging
+ printf("visited: %d %.2f..%.2f %.2f..%.2f\n",
+ sortPos, blk1->ExMin, blk1->ExMax, blk1->EyMin, blk1->EyMax);
+#endif
+ visited[pos1] = gTrue;
+ pos2 = -1;
+ for (blk2 = blkList; blk2; blk2 = blk2->next) {
+ pos2++;
+ if (visited[pos2]) {
+ // skip visited nodes
+ continue;
+ }
+ before = gFalse;
+
+ // is blk2 before blk1? (for table entries)
+ if (blk1->tableId >= 0 && blk1->tableId == blk2->tableId) {
+ if (page->primaryLR) {
+ if (blk2->xMax <= blk1->xMin &&
+ blk2->yMin <= blk1->yMax &&
+ blk2->yMax >= blk1->yMin)
+ before = gTrue;
+ } else {
+ if (blk2->xMin >= blk1->xMax &&
+ blk2->yMin <= blk1->yMax &&
+ blk2->yMax >= blk1->yMin)
+ before = gTrue;
+ }
+
+ if (blk2->yMax <= blk1->yMin)
+ before = gTrue;
+ } else {
+ if (blk2->isBeforeByRule1(blk1)) {
+ // Rule (1) blk1 and blk2 overlap, and blk2 is above blk1.
+ before = gTrue;
+#if 0 // for debugging
+ printf("rule1: %.2f..%.2f %.2f..%.2f %.2f..%.2f %.2f..%.2f\n",
+ blk2->ExMin, blk2->ExMax, blk2->EyMin, blk2->EyMax,
+ blk1->ExMin, blk1->ExMax, blk1->EyMin, blk1->EyMax);
+#endif
+ } else if (blk2->isBeforeByRule2(blk1)) {
+ // Rule (2) blk2 left of blk1, and no intervening blk3
+ // such that blk1 is before blk3 by rule 1,
+ // and blk3 is before blk2 by rule 1.
+ before = gTrue;
+ for (blk3 = blkList; blk3; blk3 = blk3->next) {
+ if (blk3 == blk2 || blk3 == blk1) {
+ continue;
+ }
+ if (blk1->isBeforeByRule1(blk3) &&
+ blk3->isBeforeByRule1(blk2)) {
+ before = gFalse;
+ break;
+ }
+ }
+#if 0 // for debugging
+ if (before) {
+ printf("rule2: %.2f..%.2f %.2f..%.2f %.2f..%.2f %.2f..%.2f\n",
+ blk1->ExMin, blk1->ExMax, blk1->EyMin, blk1->EyMax,
+ blk2->ExMin, blk2->ExMax, blk2->EyMin, blk2->EyMax);
+ }
+#endif
+ }
+ }
+ if (before) {
+ // blk2 is before blk1, so it needs to be visited
+ // before we can add blk1 to the sorted list.
+ sortPos = blk2->visitDepthFirst(blkList, pos2, sorted, sortPos, visited);
+ }
+ }
+#if 0 // for debugging
+ printf("sorted: %d %.2f..%.2f %.2f..%.2f\n",
+ sortPos, blk1->ExMin, blk1->ExMax, blk1->EyMin, blk1->EyMax);
+#endif
+ sorted[sortPos++] = blk1;
+ return sortPos;
+}
+
+//------------------------------------------------------------------------
+// TextFlow
+//------------------------------------------------------------------------
+
+TextFlow::TextFlow(TextPage *pageA, TextBlock *blk) {
+ page = pageA;
+ xMin = blk->xMin;
+ xMax = blk->xMax;
+ yMin = blk->yMin;
+ yMax = blk->yMax;
+ priMin = blk->priMin;
+ priMax = blk->priMax;
+ blocks = lastBlk = blk;
+ next = NULL;
+}
+
+TextFlow::~TextFlow() {
+ TextBlock *blk;
+
+ while (blocks) {
+ blk = blocks;
+ blocks = blocks->next;
+ delete blk;
+ }
+}
+
+void TextFlow::addBlock(TextBlock *blk) {
+ if (lastBlk) {
+ lastBlk->next = blk;
+ } else {
+ blocks = blk;
+ }
+ lastBlk = blk;
+ if (blk->xMin < xMin) {
+ xMin = blk->xMin;
+ }
+ if (blk->xMax > xMax) {
+ xMax = blk->xMax;
+ }
+ if (blk->yMin < yMin) {
+ yMin = blk->yMin;
+ }
+ if (blk->yMax > yMax) {
+ yMax = blk->yMax;
+ }
+}
+
+GBool TextFlow::blockFits(TextBlock *blk, TextBlock *prevBlk) {
+ GBool fits;
+
+ // lower blocks must use smaller fonts
+ if (blk->lines->words->fontSize > lastBlk->lines->words->fontSize) {
+ return gFalse;
+ }
+
+ fits = gFalse; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ fits = blk->xMin >= priMin && blk->xMax <= priMax;
+ break;
+ case 1:
+ fits = blk->yMin >= priMin && blk->yMax <= priMax;
+ break;
+ case 2:
+ fits = blk->xMin >= priMin && blk->xMax <= priMax;
+ break;
+ case 3:
+ fits = blk->yMin >= priMin && blk->yMax <= priMax;
+ break;
+ }
+ return fits;
+}
+
+#if TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextWordList
+//------------------------------------------------------------------------
+
+TextWordList::TextWordList(TextPage *text, GBool physLayout) {
+ TextFlow *flow;
+ TextBlock *blk;
+ TextLine *line;
+ TextWord *word;
+ TextWord **wordArray;
+ int nWords, i;
+
+ words = new GooList();
+
+ if (text->rawOrder) {
+ for (word = text->rawWords; word; word = word->next) {
+ words->append(word);
+ }
+
+ } else if (physLayout) {
+ // this is inefficient, but it's also the least useful of these
+ // three cases
+ nWords = 0;
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ ++nWords;
+ }
+ }
+ }
+ }
+ wordArray = (TextWord **)gmallocn(nWords, sizeof(TextWord *));
+ i = 0;
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ wordArray[i++] = word;
+ }
+ }
+ }
+ }
+ qsort(wordArray, nWords, sizeof(TextWord *), &TextWord::cmpYX);
+ for (i = 0; i < nWords; ++i) {
+ words->append(wordArray[i]);
+ }
+ gfree(wordArray);
+
+ } else {
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ words->append(word);
+ }
+ }
+ }
+ }
+ }
+}
+
+TextWordList::~TextWordList() {
+ delete words;
+}
+
+int TextWordList::getLength() {
+ return words->getLength();
+}
+
+TextWord *TextWordList::get(int idx) {
+ if (idx < 0 || idx >= words->getLength()) {
+ return NULL;
+ }
+ return (TextWord *)words->get(idx);
+}
+
+#endif // TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextPage
+//------------------------------------------------------------------------
+
+TextPage::TextPage(GBool rawOrderA) {
+ int rot;
+
+ refCnt = 1;
+ rawOrder = rawOrderA;
+ curWord = NULL;
+ charPos = 0;
+ curFont = NULL;
+ curFontSize = 0;
+ nest = 0;
+ nTinyChars = 0;
+ lastCharOverlap = gFalse;
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ pools[rot] = new TextPool();
+ }
+ }
+ flows = NULL;
+ blocks = NULL;
+ rawWords = NULL;
+ rawLastWord = NULL;
+ fonts = new GooList();
+ lastFindXMin = lastFindYMin = 0;
+ haveLastFind = gFalse;
+ underlines = new GooList();
+ links = new GooList();
+ mergeCombining = gTrue;
+}
+
+TextPage::~TextPage() {
+ int rot;
+
+ clear();
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ delete pools[rot];
+ }
+ }
+ delete fonts;
+ deleteGooList(underlines, TextUnderline);
+ deleteGooList(links, TextLink);
+}
+
+void TextPage::incRefCnt() {
+ refCnt++;
+}
+
+void TextPage::decRefCnt() {
+ if (--refCnt == 0)
+ delete this;
+}
+
+void TextPage::startPage(GfxState *state) {
+ clear();
+ if (state) {
+ pageWidth = state->getPageWidth();
+ pageHeight = state->getPageHeight();
+ } else {
+ pageWidth = pageHeight = 0;
+ }
+}
+
+void TextPage::endPage() {
+ if (curWord) {
+ endWord();
+ }
+}
+
+void TextPage::clear() {
+ int rot;
+ TextFlow *flow;
+ TextWord *word;
+
+ if (curWord) {
+ delete curWord;
+ curWord = NULL;
+ }
+ if (rawOrder) {
+ while (rawWords) {
+ word = rawWords;
+ rawWords = rawWords->next;
+ delete word;
+ }
+ } else {
+ for (rot = 0; rot < 4; ++rot) {
+ delete pools[rot];
+ }
+ while (flows) {
+ flow = flows;
+ flows = flows->next;
+ delete flow;
+ }
+ gfree(blocks);
+ }
+ deleteGooList(fonts, TextFontInfo);
+ deleteGooList(underlines, TextUnderline);
+ deleteGooList(links, TextLink);
+
+ curWord = NULL;
+ charPos = 0;
+ curFont = NULL;
+ curFontSize = 0;
+ nest = 0;
+ nTinyChars = 0;
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ pools[rot] = new TextPool();
+ }
+ }
+ flows = NULL;
+ blocks = NULL;
+ rawWords = NULL;
+ rawLastWord = NULL;
+ fonts = new GooList();
+ underlines = new GooList();
+ links = new GooList();
+}
+
+void TextPage::updateFont(GfxState *state) {
+ GfxFont *gfxFont;
+ double *fm;
+ char *name;
+ int code, mCode, letterCode, anyCode;
+ double w;
+ int i;
+
+ // get the font info object
+ curFont = NULL;
+ for (i = 0; i < fonts->getLength(); ++i) {
+ curFont = (TextFontInfo *)fonts->get(i);
+ if (curFont->matches(state)) {
+ break;
+ }
+ curFont = NULL;
+ }
+ if (!curFont) {
+ curFont = new TextFontInfo(state);
+ fonts->append(curFont);
+ }
+
+ // adjust the font size
+ gfxFont = state->getFont();
+ curFontSize = state->getTransformedFontSize();
+ if (gfxFont && gfxFont->getType() == fontType3) {
+ // This is a hack which makes it possible to deal with some Type 3
+ // fonts. The problem is that it's impossible to know what the
+ // base coordinate system used in the font is without actually
+ // rendering the font. This code tries to guess by looking at the
+ // width of the character 'm' (which breaks if the font is a
+ // subset that doesn't contain 'm').
+ mCode = letterCode = anyCode = -1;
+ for (code = 0; code < 256; ++code) {
+ name = ((Gfx8BitFont *)gfxFont)->getCharName(code);
+ int nameLen = name ? strlen(name) : 0;
+ GBool nameOneChar = nameLen == 1 || (nameLen > 1 && name[1] == '\0');
+ if (nameOneChar && name[0] == 'm') {
+ mCode = code;
+ }
+ if (letterCode < 0 && nameOneChar &&
+ ((name[0] >= 'A' && name[0] <= 'Z') ||
+ (name[0] >= 'a' && name[0] <= 'z'))) {
+ letterCode = code;
+ }
+ if (anyCode < 0 && name &&
+ ((Gfx8BitFont *)gfxFont)->getWidth(code) > 0) {
+ anyCode = code;
+ }
+ }
+ if (mCode >= 0 &&
+ (w = ((Gfx8BitFont *)gfxFont)->getWidth(mCode)) > 0) {
+ // 0.6 is a generic average 'm' width -- yes, this is a hack
+ curFontSize *= w / 0.6;
+ } else if (letterCode >= 0 &&
+ (w = ((Gfx8BitFont *)gfxFont)->getWidth(letterCode)) > 0) {
+ // even more of a hack: 0.5 is a generic letter width
+ curFontSize *= w / 0.5;
+ } else if (anyCode >= 0 &&
+ (w = ((Gfx8BitFont *)gfxFont)->getWidth(anyCode)) > 0) {
+ // better than nothing: 0.5 is a generic character width
+ curFontSize *= w / 0.5;
+ }
+ fm = gfxFont->getFontMatrix();
+ if (fm[0] != 0) {
+ curFontSize *= fabs(fm[3] / fm[0]);
+ }
+ }
+}
+
+void TextPage::beginWord(GfxState *state) {
+ GfxFont *gfxFont;
+ double *fontm;
+ double m[4], m2[4];
+ int rot;
+
+ // This check is needed because Type 3 characters can contain
+ // text-drawing operations (when TextPage is being used via
+ // {X,Win}SplashOutputDev rather than TextOutputDev).
+ if (curWord) {
+ ++nest;
+ return;
+ }
+
+ // compute the rotation
+ state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
+ gfxFont = state->getFont();
+ if (gfxFont && gfxFont->getType() == fontType3) {
+ fontm = state->getFont()->getFontMatrix();
+ m2[0] = fontm[0] * m[0] + fontm[1] * m[2];
+ m2[1] = fontm[0] * m[1] + fontm[1] * m[3];
+ m2[2] = fontm[2] * m[0] + fontm[3] * m[2];
+ m2[3] = fontm[2] * m[1] + fontm[3] * m[3];
+ m[0] = m2[0];
+ m[1] = m2[1];
+ m[2] = m2[2];
+ m[3] = m2[3];
+ }
+ if (fabs(m[0] * m[3]) > fabs(m[1] * m[2])) {
+ rot = (m[0] > 0 || m[3] < 0) ? 0 : 2;
+ } else {
+ rot = (m[2] > 0) ? 1 : 3;
+ }
+
+ // for vertical writing mode, the lines are effectively rotated 90
+ // degrees
+ if (gfxFont && gfxFont->getWMode()) {
+ rot = (rot + 1) & 3;
+ }
+
+ curWord = new TextWord(state, rot, curFontSize);
+}
+
+void TextPage::addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen) {
+ double x1, y1, w1, h1, dx2, dy2, base, sp, delta;
+ GBool overlap;
+ int i;
+ int wMode;
+ Matrix mat;
+
+ // subtract char and word spacing from the dx,dy values
+ sp = state->getCharSpace();
+ if (c == (CharCode)0x20) {
+ sp += state->getWordSpace();
+ }
+ state->textTransformDelta(sp * state->getHorizScaling(), 0, &dx2, &dy2);
+ dx -= dx2;
+ dy -= dy2;
+ state->transformDelta(dx, dy, &w1, &h1);
+
+ // throw away chars that aren't inside the page bounds
+ // (and also do a sanity check on the character size)
+ state->transform(x, y, &x1, &y1);
+ if (x1 + w1 < 0 || x1 > pageWidth ||
+ y1 + h1 < 0 || y1 > pageHeight ||
+ x1 != x1 || y1 != y1 || // IEEE way of checking for isnan
+ w1 != w1 || h1 != h1) {
+ charPos += nBytes;
+ return;
+ }
+
+ // check the tiny chars limit
+ if (!globalParams->getTextKeepTinyChars() &&
+ fabs(w1) < 3 && fabs(h1) < 3) {
+ if (++nTinyChars > 50000) {
+ charPos += nBytes;
+ return;
+ }
+ }
+
+ // break words at space character
+ if (uLen == 1 && u[0] == (Unicode)0x20) {
+ charPos += nBytes;
+ endWord();
+ return;
+ }
+
+ state->getFontTransMat(&mat.m[0], &mat.m[1], &mat.m[2], &mat.m[3]);
+ mat.m[4] = x1;
+ mat.m[5] = y1;
+
+ if (mergeCombining && curWord && uLen == 1 &&
+ curWord->addCombining(state, curFont, curFontSize, x1, y1, w1, h1, charPos, nBytes, c,
+ u[0], mat)) {
+ charPos += nBytes;
+ return;
+ }
+
+ // start a new word if:
+ // (1) this character doesn't fall in the right place relative to
+ // the end of the previous word (this places upper and lower
+ // constraints on the position deltas along both the primary
+ // and secondary axes), or
+ // (2) this character overlaps the previous one (duplicated text), or
+ // (3) the previous character was an overlap (we want each duplicated
+ // character to be in a word by itself at this stage),
+ // (4) the font size has changed
+ // (5) the WMode changed
+ if (curWord && curWord->len > 0) {
+ base = sp = delta = 0; // make gcc happy
+ switch (curWord->rot) {
+ case 0:
+ base = y1;
+ sp = x1 - curWord->xMax;
+ delta = x1 - curWord->edge[curWord->len - 1];
+ break;
+ case 1:
+ base = x1;
+ sp = y1 - curWord->yMax;
+ delta = y1 - curWord->edge[curWord->len - 1];
+ break;
+ case 2:
+ base = y1;
+ sp = curWord->xMin - x1;
+ delta = curWord->edge[curWord->len - 1] - x1;
+ break;
+ case 3:
+ base = x1;
+ sp = curWord->yMin - y1;
+ delta = curWord->edge[curWord->len - 1] - y1;
+ break;
+ }
+ overlap = fabs(delta) < dupMaxPriDelta * curWord->fontSize &&
+ fabs(base - curWord->base) < dupMaxSecDelta * curWord->fontSize;
+ wMode = curFont->getWMode();
+ if (overlap || lastCharOverlap ||
+ sp < -minDupBreakOverlap * curWord->fontSize ||
+ sp > minWordBreakSpace * curWord->fontSize ||
+ fabs(base - curWord->base) > 0.5 ||
+ curFontSize != curWord->fontSize ||
+ wMode != curWord->wMode) {
+ endWord();
+ }
+ lastCharOverlap = overlap;
+ } else {
+ lastCharOverlap = gFalse;
+ }
+
+ if (uLen != 0) {
+ // start a new word if needed
+ if (!curWord) {
+ beginWord(state);
+ }
+
+ // page rotation and/or transform matrices can cause text to be
+ // drawn in reverse order -- in this case, swap the begin/end
+ // coordinates and break text into individual chars
+ if ((curWord->rot == 0 && w1 < 0) ||
+ (curWord->rot == 1 && h1 < 0) ||
+ (curWord->rot == 2 && w1 > 0) ||
+ (curWord->rot == 3 && h1 > 0)) {
+ endWord();
+ beginWord(state);
+ x1 += w1;
+ y1 += h1;
+ w1 = -w1;
+ h1 = -h1;
+ }
+
+ // add the characters to the current word
+ w1 /= uLen;
+ h1 /= uLen;
+ for (i = 0; i < uLen; ++i) {
+ curWord->addChar(state, curFont, x1 + i*w1, y1 + i*h1, w1, h1, charPos, nBytes, c, u[i], mat);
+ }
+ }
+ charPos += nBytes;
+}
+
+void TextPage::incCharCount(int nChars) {
+ charPos += nChars;
+}
+
+void TextPage::endWord() {
+ // This check is needed because Type 3 characters can contain
+ // text-drawing operations (when TextPage is being used via
+ // {X,Win}SplashOutputDev rather than TextOutputDev).
+ if (nest > 0) {
+ --nest;
+ return;
+ }
+
+ if (curWord) {
+ addWord(curWord);
+ curWord = NULL;
+ }
+}
+
+void TextPage::addWord(TextWord *word) {
+ // throw away zero-length words -- they don't have valid xMin/xMax
+ // values, and they're useless anyway
+ if (word->len == 0) {
+ delete word;
+ return;
+ }
+
+ if (rawOrder) {
+ if (rawLastWord) {
+ rawLastWord->next = word;
+ } else {
+ rawWords = word;
+ }
+ rawLastWord = word;
+ } else {
+ pools[word->rot]->addWord(word);
+ }
+}
+
+void TextPage::addUnderline(double x0, double y0, double x1, double y1) {
+ underlines->append(new TextUnderline(x0, y0, x1, y1));
+}
+
+void TextPage::addLink(int xMin, int yMin, int xMax, int yMax, AnnotLink *link) {
+ links->append(new TextLink(xMin, yMin, xMax, yMax, link));
+}
+
+void TextPage::coalesce(GBool physLayout, double fixedPitch, GBool doHTML) {
+ UnicodeMap *uMap;
+ TextPool *pool;
+ TextWord *word0, *word1, *word2;
+ TextLine *line;
+ TextBlock *blkList, *blk, *lastBlk, *blk0, *blk1, *blk2;
+ TextFlow *flow, *lastFlow;
+ TextUnderline *underline;
+ TextLink *link;
+ int rot, poolMinBaseIdx, baseIdx, startBaseIdx, endBaseIdx;
+ double minBase, maxBase, newMinBase, newMaxBase;
+ double fontSize, colSpace1, colSpace2, lineSpace, intraLineSpace, blkSpace;
+ GBool found;
+ int count[4];
+ int lrCount;
+ int col1, col2;
+ int i, j, n;
+
+ if (rawOrder) {
+ primaryRot = 0;
+ primaryLR = gTrue;
+ return;
+ }
+
+ uMap = globalParams->getTextEncoding();
+ blkList = NULL;
+ lastBlk = NULL;
+ nBlocks = 0;
+ primaryRot = 0;
+
+#if 0 // for debugging
+ printf("*** initial words ***\n");
+ for (rot = 0; rot < 4; ++rot) {
+ pool = pools[rot];
+ for (baseIdx = pool->minBaseIdx; baseIdx <= pool->maxBaseIdx; ++baseIdx) {
+ for (word0 = pool->getPool(baseIdx); word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f rot=%d link=%p '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, rot*90, word0->link);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+#if 0 //~ for debugging
+ for (i = 0; i < underlines->getLength(); ++i) {
+ underline = (TextUnderline *)underlines->get(i);
+ printf("underline: x=%g..%g y=%g..%g horiz=%d\n",
+ underline->x0, underline->x1, underline->y0, underline->y1,
+ underline->horiz);
+ }
+#endif
+
+ if (doHTML) {
+
+ //----- handle underlining
+ for (i = 0; i < underlines->getLength(); ++i) {
+ underline = (TextUnderline *)underlines->get(i);
+ if (underline->horiz) {
+ // rot = 0
+ if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) {
+ startBaseIdx = pools[0]->getBaseIdx(underline->y0 + minUnderlineGap);
+ endBaseIdx = pools[0]->getBaseIdx(underline->y0 + maxUnderlineGap);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) {
+ //~ need to check the y value against the word baseline
+ if (underline->x0 < word0->xMin + underlineSlack &&
+ word0->xMax - underlineSlack < underline->x1) {
+ word0->underlined = gTrue;
+ }
+ }
+ }
+ }
+
+ // rot = 2
+ if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) {
+ startBaseIdx = pools[2]->getBaseIdx(underline->y0 - maxUnderlineGap);
+ endBaseIdx = pools[2]->getBaseIdx(underline->y0 - minUnderlineGap);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) {
+ if (underline->x0 < word0->xMin + underlineSlack &&
+ word0->xMax - underlineSlack < underline->x1) {
+ word0->underlined = gTrue;
+ }
+ }
+ }
+ }
+ } else {
+ // rot = 1
+ if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) {
+ startBaseIdx = pools[1]->getBaseIdx(underline->x0 - maxUnderlineGap);
+ endBaseIdx = pools[1]->getBaseIdx(underline->x0 - minUnderlineGap);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) {
+ if (underline->y0 < word0->yMin + underlineSlack &&
+ word0->yMax - underlineSlack < underline->y1) {
+ word0->underlined = gTrue;
+ }
+ }
+ }
+ }
+
+ // rot = 3
+ if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) {
+ startBaseIdx = pools[3]->getBaseIdx(underline->x0 + minUnderlineGap);
+ endBaseIdx = pools[3]->getBaseIdx(underline->x0 + maxUnderlineGap);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) {
+ if (underline->y0 < word0->yMin + underlineSlack &&
+ word0->yMax - underlineSlack < underline->y1) {
+ word0->underlined = gTrue;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //----- handle links
+ for (i = 0; i < links->getLength(); ++i) {
+ link = (TextLink *)links->get(i);
+
+ // rot = 0
+ if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) {
+ startBaseIdx = pools[0]->getBaseIdx(link->yMin);
+ endBaseIdx = pools[0]->getBaseIdx(link->yMax);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) {
+ if (link->xMin < word0->xMin + hyperlinkSlack &&
+ word0->xMax - hyperlinkSlack < link->xMax &&
+ link->yMin < word0->yMin + hyperlinkSlack &&
+ word0->yMax - hyperlinkSlack < link->yMax) {
+ word0->link = link->link;
+ }
+ }
+ }
+ }
+
+ // rot = 2
+ if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) {
+ startBaseIdx = pools[2]->getBaseIdx(link->yMin);
+ endBaseIdx = pools[2]->getBaseIdx(link->yMax);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) {
+ if (link->xMin < word0->xMin + hyperlinkSlack &&
+ word0->xMax - hyperlinkSlack < link->xMax &&
+ link->yMin < word0->yMin + hyperlinkSlack &&
+ word0->yMax - hyperlinkSlack < link->yMax) {
+ word0->link = link->link;
+ }
+ }
+ }
+ }
+
+ // rot = 1
+ if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) {
+ startBaseIdx = pools[1]->getBaseIdx(link->xMin);
+ endBaseIdx = pools[1]->getBaseIdx(link->xMax);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) {
+ if (link->yMin < word0->yMin + hyperlinkSlack &&
+ word0->yMax - hyperlinkSlack < link->yMax &&
+ link->xMin < word0->xMin + hyperlinkSlack &&
+ word0->xMax - hyperlinkSlack < link->xMax) {
+ word0->link = link->link;
+ }
+ }
+ }
+ }
+
+ // rot = 3
+ if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) {
+ startBaseIdx = pools[3]->getBaseIdx(link->xMin);
+ endBaseIdx = pools[3]->getBaseIdx(link->xMax);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) {
+ if (link->yMin < word0->yMin + hyperlinkSlack &&
+ word0->yMax - hyperlinkSlack < link->yMax &&
+ link->xMin < word0->xMin + hyperlinkSlack &&
+ word0->xMax - hyperlinkSlack < link->xMax) {
+ word0->link = link->link;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //----- assemble the blocks
+
+ //~ add an outer loop for writing mode (vertical text)
+
+ // build blocks for each rotation value
+ for (rot = 0; rot < 4; ++rot) {
+ pool = pools[rot];
+ poolMinBaseIdx = pool->minBaseIdx;
+ count[rot] = 0;
+
+ // add blocks until no more words are left
+ while (1) {
+
+ // find the first non-empty line in the pool
+ for (;
+ poolMinBaseIdx <= pool->maxBaseIdx &&
+ !pool->getPool(poolMinBaseIdx);
+ ++poolMinBaseIdx) ;
+ if (poolMinBaseIdx > pool->maxBaseIdx) {
+ break;
+ }
+
+ // look for the left-most word in the first four lines of the
+ // pool -- this avoids starting with a superscript word
+ startBaseIdx = poolMinBaseIdx;
+ for (baseIdx = poolMinBaseIdx + 1;
+ baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx;
+ ++baseIdx) {
+ if (!pool->getPool(baseIdx)) {
+ continue;
+ }
+ if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx))
+ < 0) {
+ startBaseIdx = baseIdx;
+ }
+ }
+
+ // create a new block
+ word0 = pool->getPool(startBaseIdx);
+ pool->setPool(startBaseIdx, word0->next);
+ word0->next = NULL;
+ blk = new TextBlock(this, rot);
+ blk->addWord(word0);
+
+ fontSize = word0->fontSize;
+ minBase = maxBase = word0->base;
+ colSpace1 = minColSpacing1 * fontSize;
+ colSpace2 = minColSpacing2 * fontSize;
+ lineSpace = maxLineSpacingDelta * fontSize;
+ intraLineSpace = maxIntraLineDelta * fontSize;
+
+ // add words to the block
+ do {
+ found = gFalse;
+
+ // look for words on the line above the current top edge of
+ // the block
+ newMinBase = minBase;
+ for (baseIdx = pool->getBaseIdx(minBase);
+ baseIdx >= pool->getBaseIdx(minBase - lineSpace);
+ --baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base < minBase &&
+ word1->base >= minBase - lineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin)
+ : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta1 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ newMinBase = word2->base;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+ minBase = newMinBase;
+
+ // look for words on the line below the current bottom edge of
+ // the block
+ newMaxBase = maxBase;
+ for (baseIdx = pool->getBaseIdx(maxBase);
+ baseIdx <= pool->getBaseIdx(maxBase + lineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base > maxBase &&
+ word1->base <= maxBase + lineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin)
+ : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta1 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ newMaxBase = word2->base;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+ maxBase = newMaxBase;
+
+ // look for words that are on lines already in the block, and
+ // that overlap the block horizontally
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin < blk->xMax + colSpace1 &&
+ word1->xMax > blk->xMin - colSpace1)
+ : (word1->yMin < blk->yMax + colSpace1 &&
+ word1->yMax > blk->yMin - colSpace1)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta2 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+
+ // only check for outlying words (the next two chunks of code)
+ // if we didn't find anything else
+ if (found) {
+ continue;
+ }
+
+ // scan down the left side of the block, looking for words
+ // that are near (but not overlapping) the block; if there are
+ // three or fewer, add them to the block
+ n = 0;
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMax <= blk->xMin &&
+ word1->xMax > blk->xMin - colSpace2)
+ : (word1->yMax <= blk->yMin &&
+ word1->yMax > blk->yMin - colSpace2)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ ++n;
+ break;
+ }
+ word1 = word1->next;
+ }
+ }
+ if (n > 0 && n <= 3) {
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMax <= blk->xMin &&
+ word1->xMax > blk->xMin - colSpace2)
+ : (word1->yMax <= blk->yMin &&
+ word1->yMax > blk->yMin - colSpace2)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ if (word2->base < minBase) {
+ minBase = word2->base;
+ } else if (word2->base > maxBase) {
+ maxBase = word2->base;
+ }
+ found = gTrue;
+ break;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+ }
+
+ // scan down the right side of the block, looking for words
+ // that are near (but not overlapping) the block; if there are
+ // three or fewer, add them to the block
+ n = 0;
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin >= blk->xMax &&
+ word1->xMin < blk->xMax + colSpace2)
+ : (word1->yMin >= blk->yMax &&
+ word1->yMin < blk->yMax + colSpace2)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ ++n;
+ break;
+ }
+ word1 = word1->next;
+ }
+ }
+ if (n > 0 && n <= 3) {
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin >= blk->xMax &&
+ word1->xMin < blk->xMax + colSpace2)
+ : (word1->yMin >= blk->yMax &&
+ word1->yMin < blk->yMax + colSpace2)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ if (word2->base < minBase) {
+ minBase = word2->base;
+ } else if (word2->base > maxBase) {
+ maxBase = word2->base;
+ }
+ found = gTrue;
+ break;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+ }
+
+ } while (found);
+
+ //~ need to compute the primary writing mode (horiz/vert) in
+ //~ addition to primary rotation
+
+ // coalesce the block, and add it to the list
+ blk->coalesce(uMap, fixedPitch);
+ if (lastBlk) {
+ lastBlk->next = blk;
+ } else {
+ blkList = blk;
+ }
+ lastBlk = blk;
+ count[rot] += blk->charCount;
+ ++nBlocks;
+ }
+
+ if (count[rot] > count[primaryRot]) {
+ primaryRot = rot;
+ }
+ }
+
+#if 0 // for debugging
+ printf("*** rotation ***\n");
+ for (rot = 0; rot < 4; ++rot) {
+ printf(" %d: %6d\n", rot, count[rot]);
+ }
+ printf(" primary rot = %d\n", primaryRot);
+ printf("\n");
+#endif
+
+#if 0 // for debugging
+ printf("*** blocks ***\n");
+ for (blk = blkList; blk; blk = blk->next) {
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f\n",
+ line->xMin, line->xMax, line->yMin, line->yMax, line->base);
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+ // determine the primary direction
+ lrCount = 0;
+ for (blk = blkList; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word0 = line->words; word0; word0 = word0->next) {
+ for (i = 0; i < word0->len; ++i) {
+ if (unicodeTypeL(word0->text[i])) {
+ ++lrCount;
+ } else if (unicodeTypeR(word0->text[i])) {
+ --lrCount;
+ }
+ }
+ }
+ }
+ }
+ primaryLR = lrCount >= 0;
+
+#if 0 // for debugging
+ printf("*** direction ***\n");
+ printf("lrCount = %d\n", lrCount);
+ printf("primaryLR = %d\n", primaryLR);
+#endif
+
+ //----- column assignment
+
+ // sort blocks into xy order for column assignment
+ if (blocks)
+ gfree (blocks);
+ if (physLayout && fixedPitch) {
+
+ blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
+ for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
+ blocks[i] = blk;
+ col1 = 0; // make gcc happy
+ switch (primaryRot) {
+ case 0:
+ col1 = (int)(blk->xMin / fixedPitch + 0.5);
+ break;
+ case 1:
+ col1 = (int)(blk->yMin / fixedPitch + 0.5);
+ break;
+ case 2:
+ col1 = (int)((pageWidth - blk->xMax) / fixedPitch + 0.5);
+ break;
+ case 3:
+ col1 = (int)((pageHeight - blk->yMax) / fixedPitch + 0.5);
+ break;
+ }
+ blk->col = col1;
+ for (line = blk->lines; line; line = line->next) {
+ for (j = 0; j <= line->len; ++j) {
+ line->col[j] += col1;
+ }
+ }
+ }
+
+ } else {
+
+ // sort blocks into xy order for column assignment
+ blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
+ for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
+ blocks[i] = blk;
+ }
+ qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
+
+ // column assignment
+ for (i = 0; i < nBlocks; ++i) {
+ blk0 = blocks[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ blk1 = blocks[j];
+ col2 = 0; // make gcc happy
+ switch (primaryRot) {
+ case 0:
+ if (blk0->xMin > blk1->xMax) {
+ col2 = blk1->col + blk1->nColumns + 3;
+ } else if (blk1->xMax == blk1->xMin) {
+ col2 = blk1->col;
+ } else {
+ col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
+ (blk1->xMax - blk1->xMin)) *
+ blk1->nColumns);
+ }
+ break;
+ case 1:
+ if (blk0->yMin > blk1->yMax) {
+ col2 = blk1->col + blk1->nColumns + 3;
+ } else if (blk1->yMax == blk1->yMin) {
+ col2 = blk1->col;
+ } else {
+ col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
+ (blk1->yMax - blk1->yMin)) *
+ blk1->nColumns);
+ }
+ break;
+ case 2:
+ if (blk0->xMax < blk1->xMin) {
+ col2 = blk1->col + blk1->nColumns + 3;
+ } else if (blk1->xMin == blk1->xMax) {
+ col2 = blk1->col;
+ } else {
+ col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
+ (blk1->xMin - blk1->xMax)) *
+ blk1->nColumns);
+ }
+ break;
+ case 3:
+ if (blk0->yMax < blk1->yMin) {
+ col2 = blk1->col + blk1->nColumns + 3;
+ } else if (blk1->yMin == blk1->yMax) {
+ col2 = blk1->col;
+ } else {
+ col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
+ (blk1->yMin - blk1->yMax)) *
+ blk1->nColumns);
+ }
+ break;
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ blk0->col = col1;
+ for (line = blk0->lines; line; line = line->next) {
+ for (j = 0; j <= line->len; ++j) {
+ line->col[j] += col1;
+ }
+ }
+ }
+
+ }
+
+#if 0 // for debugging
+ printf("*** blocks, after column assignment ***\n");
+ for (blk = blkList; blk; blk = blk->next) {
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f col=%d nCols=%d\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col,
+ blk->nColumns);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line: col[0]=%d\n", line->col[0]);
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+ //----- reading order sort
+
+ // compute space on left and right sides of each block
+ for (i = 0; i < nBlocks; ++i) {
+ blk0 = blocks[i];
+ for (j = 0; j < nBlocks; ++j) {
+ blk1 = blocks[j];
+ if (blk1 != blk0) {
+ blk0->updatePriMinMax(blk1);
+ }
+ }
+ }
+
+#if 0 // for debugging
+ printf("PAGE\n");
+#endif
+
+ int sortPos = 0;
+ GBool *visited = (GBool *)gmallocn(nBlocks, sizeof(GBool));
+ for (i = 0; i < nBlocks; i++) {
+ visited[i] = gFalse;
+ }
+
+ double bxMin0, byMin0, bxMin1, byMin1;
+ int numTables = 0;
+ int tableId = -1;
+ int correspondenceX, correspondenceY;
+ double xCentre1, yCentre1, xCentre2, yCentre2;
+ double xCentre3, yCentre3, xCentre4, yCentre4;
+ double deltaX, deltaY;
+ TextBlock *fblk2 = NULL, *fblk3 = NULL, *fblk4 = NULL;
+
+ for (blk1 = blkList; blk1; blk1 = blk1->next) {
+ blk1->ExMin = blk1->xMin;
+ blk1->ExMax = blk1->xMax;
+ blk1->EyMin = blk1->yMin;
+ blk1->EyMax = blk1->yMax;
+
+ bxMin0 = DBL_MAX;
+ byMin0 = DBL_MAX;
+ bxMin1 = DBL_MAX;
+ byMin1 = DBL_MAX;
+
+ fblk2 = NULL;
+ fblk3 = NULL;
+ fblk4 = NULL;
+
+ /* find fblk2, fblk3 and fblk4 so that
+ * fblk2 is on the right of blk1 and overlap with blk1 in y axis
+ * fblk3 is under blk1 and overlap with blk1 in x axis
+ * fblk4 is under blk1 and on the right of blk1
+ * and they are closest to blk1
+ */
+ for (blk2 = blkList; blk2; blk2 = blk2->next) {
+ if (blk2 != blk1) {
+ if (blk2->yMin <= blk1->yMax &&
+ blk2->yMax >= blk1->yMin &&
+ blk2->xMin > blk1->xMax &&
+ blk2->xMin < bxMin0) {
+ bxMin0 = blk2->xMin;
+ fblk2 = blk2;
+ } else if (blk2->xMin <= blk1->xMax &&
+ blk2->xMax >= blk1->xMin &&
+ blk2->yMin > blk1->yMax &&
+ blk2->yMin < byMin0) {
+ byMin0 = blk2->yMin;
+ fblk3 = blk2;
+ } else if (blk2->xMin > blk1->xMax &&
+ blk2->xMin < bxMin1 &&
+ blk2->yMin > blk1->yMax &&
+ blk2->yMin < byMin1) {
+ bxMin1 = blk2->xMin;
+ byMin1 = blk2->yMin;
+ fblk4 = blk2;
+ }
+ }
+ }
+
+ /* fblk4 can not overlap with fblk3 in x and with fblk2 in y
+ * fblk2 can not overlap with fblk3 in x and y
+ * fblk4 has to overlap with fblk3 in y and with fblk2 in x
+ */
+ if (fblk2 != NULL &&
+ fblk3 != NULL &&
+ fblk4 != NULL) {
+ if (((fblk3->xMin <= fblk4->xMax && fblk3->xMax >= fblk4->xMin) ||
+ (fblk2->yMin <= fblk4->yMax && fblk2->yMax >= fblk4->yMin) ||
+ (fblk2->xMin <= fblk3->xMax && fblk2->xMax >= fblk3->xMin) ||
+ (fblk2->yMin <= fblk3->yMax && fblk2->yMax >= fblk3->yMin)) ||
+ !(fblk4->xMin <= fblk2->xMax && fblk4->xMax >= fblk2->xMin &&
+ fblk4->yMin <= fblk3->yMax && fblk4->yMax >= fblk3->yMin)) {
+ fblk2 = NULL;
+ fblk3 = NULL;
+ fblk4 = NULL;
+ }
+ }
+
+ // if we found any then look whether they form a table
+ if (fblk2 != NULL &&
+ fblk3 != NULL &&
+ fblk4 != NULL) {
+ tableId = -1;
+ correspondenceX = 0;
+ correspondenceY = 0;
+ deltaX = 0.0;
+ deltaY = 0.0;
+
+ if (blk1->lines && blk1->lines->words)
+ deltaX = blk1->lines->words->getFontSize();
+ if (fblk2->lines && fblk2->lines->words)
+ deltaX = deltaX < fblk2->lines->words->getFontSize() ?
+ deltaX : fblk2->lines->words->getFontSize();
+ if (fblk3->lines && fblk3->lines->words)
+ deltaX = deltaX < fblk3->lines->words->getFontSize() ?
+ deltaX : fblk3->lines->words->getFontSize();
+ if (fblk4->lines && fblk4->lines->words)
+ deltaX = deltaX < fblk4->lines->words->getFontSize() ?
+ deltaX : fblk4->lines->words->getFontSize();
+
+ deltaY = deltaX;
+
+ deltaX *= minColSpacing1;
+ deltaY *= maxIntraLineDelta;
+
+ xCentre1 = (blk1->xMax + blk1->xMin) / 2.0;
+ yCentre1 = (blk1->yMax + blk1->yMin) / 2.0;
+ xCentre2 = (fblk2->xMax + fblk2->xMin) / 2.0;
+ yCentre2 = (fblk2->yMax + fblk2->yMin) / 2.0;
+ xCentre3 = (fblk3->xMax + fblk3->xMin) / 2.0;
+ yCentre3 = (fblk3->yMax + fblk3->yMin) / 2.0;
+ xCentre4 = (fblk4->xMax + fblk4->xMin) / 2.0;
+ yCentre4 = (fblk4->yMax + fblk4->yMin) / 2.0;
+
+ // are blocks centrally aligned in x ?
+ if (fabs (xCentre1 - xCentre3) <= deltaX &&
+ fabs (xCentre2 - xCentre4) <= deltaX)
+ correspondenceX++;
+
+ // are blocks centrally aligned in y ?
+ if (fabs (yCentre1 - yCentre2) <= deltaY &&
+ fabs (yCentre3 - yCentre4) <= deltaY)
+ correspondenceY++;
+
+ // are blocks aligned to the left ?
+ if (fabs (blk1->xMin - fblk3->xMin) <= deltaX &&
+ fabs (fblk2->xMin - fblk4->xMin) <= deltaX)
+ correspondenceX++;
+
+ // are blocks aligned to the right ?
+ if (fabs (blk1->xMax - fblk3->xMax) <= deltaX &&
+ fabs (fblk2->xMax - fblk4->xMax) <= deltaX)
+ correspondenceX++;
+
+ // are blocks aligned to the top ?
+ if (fabs (blk1->yMin - fblk2->yMin) <= deltaY &&
+ fabs (fblk3->yMin - fblk4->yMin) <= deltaY)
+ correspondenceY++;
+
+ // are blocks aligned to the bottom ?
+ if (fabs (blk1->yMax - fblk2->yMax) <= deltaY &&
+ fabs (fblk3->yMax - fblk4->yMax) <= deltaY)
+ correspondenceY++;
+
+ // are blocks aligned in x and y ?
+ if (correspondenceX > 0 &&
+ correspondenceY > 0) {
+
+ // find maximal tableId
+ tableId = tableId < fblk4->tableId ? fblk4->tableId : tableId;
+ tableId = tableId < fblk3->tableId ? fblk3->tableId : tableId;
+ tableId = tableId < fblk2->tableId ? fblk2->tableId : tableId;
+ tableId = tableId < blk1->tableId ? blk1->tableId : tableId;
+
+ // if the tableId is -1, then we found new table
+ if (tableId < 0) {
+ tableId = numTables;
+ numTables++;
+ }
+
+ blk1->tableId = tableId;
+ fblk2->tableId = tableId;
+ fblk3->tableId = tableId;
+ fblk4->tableId = tableId;
+ }
+ }
+ }
+
+ /* set extended bounding boxes of all table entries
+ * so that they contain whole table
+ * (we need to process whole table size when comparing it
+ * with regular text blocks)
+ */
+ PDFRectangle *envelopes = new PDFRectangle [numTables];
+ TextBlock **ending_blocks = new TextBlock* [numTables];
+
+ for (i = 0; i < numTables; i++) {
+ envelopes[i].x1 = DBL_MAX;
+ envelopes[i].x2 = DBL_MIN;
+ envelopes[i].y1 = DBL_MAX;
+ envelopes[i].y2 = DBL_MIN;
+ }
+
+ for (blk1 = blkList; blk1; blk1 = blk1->next) {
+ if (blk1->tableId >= 0) {
+ if (blk1->ExMin < envelopes[blk1->tableId].x1) {
+ envelopes[blk1->tableId].x1 = blk1->ExMin;
+ if (!blk1->page->primaryLR)
+ ending_blocks[blk1->tableId] = blk1;
+ }
+
+ if (blk1->ExMax > envelopes[blk1->tableId].x2) {
+ envelopes[blk1->tableId].x2 = blk1->ExMax;
+ if (blk1->page->primaryLR)
+ ending_blocks[blk1->tableId] = blk1;
+ }
+
+ envelopes[blk1->tableId].y1 = blk1->EyMin < envelopes[blk1->tableId].y1 ?
+ blk1->EyMin : envelopes[blk1->tableId].y1;
+ envelopes[blk1->tableId].y2 = blk1->EyMax > envelopes[blk1->tableId].y2 ?
+ blk1->EyMax : envelopes[blk1->tableId].y2;
+ }
+ }
+
+ for (blk1 = blkList; blk1; blk1 = blk1->next) {
+ if (blk1->tableId >= 0 &&
+ blk1->xMin <= ending_blocks[blk1->tableId]->xMax &&
+ blk1->xMax >= ending_blocks[blk1->tableId]->xMin) {
+ blk1->tableEnd = gTrue;
+ }
+ }
+
+ for (blk1 = blkList; blk1; blk1 = blk1->next) {
+ if (blk1->tableId >= 0) {
+ blk1->ExMin = envelopes[blk1->tableId].x1;
+ blk1->ExMax = envelopes[blk1->tableId].x2;
+ blk1->EyMin = envelopes[blk1->tableId].y1;
+ blk1->EyMax = envelopes[blk1->tableId].y2;
+ }
+ }
+ delete[] envelopes;
+ delete[] ending_blocks;
+
+
+ /* set extended bounding boxes of all other blocks
+ * so that they extend in x without hitting neighbours
+ */
+ for (blk1 = blkList; blk1; blk1 = blk1->next) {
+ if (!(blk1->tableId >= 0)) {
+ double xMax = DBL_MAX;
+ double xMin = DBL_MIN;
+
+ for (blk2 = blkList; blk2; blk2 = blk2->next) {
+ if (blk2 == blk1)
+ continue;
+
+ if (blk1->yMin <= blk2->yMax && blk1->yMax >= blk2->yMin) {
+ if (blk2->xMin < xMax && blk2->xMin > blk1->xMax)
+ xMax = blk2->xMin;
+
+ if (blk2->xMax > xMin && blk2->xMax < blk1->xMin)
+ xMin = blk2->xMax;
+ }
+ }
+
+ for (blk2 = blkList; blk2; blk2 = blk2->next) {
+ if (blk2 == blk1)
+ continue;
+
+ if (blk2->xMax > blk1->ExMax &&
+ blk2->xMax <= xMax &&
+ blk2->yMin >= blk1->yMax) {
+ blk1->ExMax = blk2->xMax;
+ }
+
+ if (blk2->xMin < blk1->ExMin &&
+ blk2->xMin >= xMin &&
+ blk2->yMin >= blk1->yMax)
+ blk1->ExMin = blk2->xMin;
+ }
+ }
+ }
+
+ i = -1;
+ for (blk1 = blkList; blk1; blk1 = blk1->next) {
+ i++;
+ sortPos = blk1->visitDepthFirst(blkList, i, blocks, sortPos, visited);
+ }
+ if (visited) {
+ gfree(visited);
+ }
+
+#if 0 // for debugging
+ printf("*** blocks, after ro sort ***\n");
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f space=%.2f..%.2f\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax,
+ blk->priMin, blk->priMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line:\n");
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (j = 0; j < word0->len; ++j) {
+ fputc(word0->text[j] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ printf("\n");
+ fflush(stdout);
+#endif
+
+ // build the flows
+ //~ this needs to be adjusted for writing mode (vertical text)
+ //~ this also needs to account for right-to-left column ordering
+ flow = NULL;
+ while (flows) {
+ flow = flows;
+ flows = flows->next;
+ delete flow;
+ }
+ flows = lastFlow = NULL;
+ // assume blocks are already in reading order,
+ // and construct flows accordingly.
+ for (i = 0; i < nBlocks; i++) {
+ blk = blocks[i];
+ blk->next = NULL;
+ if (flow) {
+ blk1 = blocks[i - 1];
+ blkSpace = maxBlockSpacing * blk1->lines->words->fontSize;
+ if (blk1->secondaryDelta(blk) <= blkSpace &&
+ blk->isBelow(blk1) &&
+ flow->blockFits(blk, blk1)) {
+ flow->addBlock(blk);
+ continue;
+ }
+ }
+ flow = new TextFlow(this, blk);
+ if (lastFlow) {
+ lastFlow->next = flow;
+ } else {
+ flows = flow;
+ }
+ lastFlow = flow;
+ }
+
+#if 0 // for debugging
+ printf("*** flows ***\n");
+ for (flow = flows; flow; flow = flow->next) {
+ printf("flow: x=%.2f..%.2f y=%.2f..%.2f pri:%.2f..%.2f\n",
+ flow->xMin, flow->xMax, flow->yMin, flow->yMax,
+ flow->priMin, flow->priMax);
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ printf(" block: rot=%d x=%.2f..%.2f y=%.2f..%.2f pri=%.2f..%.2f\n",
+ blk->rot, blk->ExMin, blk->ExMax, blk->EyMin, blk->EyMax,
+ blk->priMin, blk->priMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line:\n");
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+ if (uMap) {
+ uMap->decRefCnt();
+ }
+}
+
+GBool TextPage::findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ GBool wholeWord,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ TextBlock *blk;
+ TextLine *line;
+ Unicode *s2, *txt;
+ Unicode *p;
+ int txtSize, m, i, j, k;
+ double xStart, yStart, xStop, yStop;
+ double xMin0, yMin0, xMax0, yMax0;
+ double xMin1, yMin1, xMax1, yMax1;
+ GBool found;
+
+ //~ needs to handle right-to-left text
+
+ if (rawOrder) {
+ return gFalse;
+ }
+
+ // convert the search string to uppercase
+ if (!caseSensitive) {
+ s2 = unicodeNormalizeNFKC(s, len, &len, NULL);
+ for (i = 0; i < len; ++i) {
+ s2[i] = unicodeToUpper(s2[i]);
+ }
+ } else {
+ s2 = unicodeNormalizeNFKC(s, len, &len, NULL);
+ }
+
+ txt = NULL;
+ txtSize = 0;
+
+ xStart = yStart = xStop = yStop = 0;
+ if (startAtLast && haveLastFind) {
+ xStart = lastFindXMin;
+ yStart = lastFindYMin;
+ } else if (!startAtTop) {
+ xStart = *xMin;
+ yStart = *yMin;
+ }
+ if (stopAtLast && haveLastFind) {
+ xStop = lastFindXMin;
+ yStop = lastFindYMin;
+ } else if (!stopAtBottom) {
+ xStop = *xMax;
+ yStop = *yMax;
+ }
+
+ found = gFalse;
+ xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy
+ xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy
+
+ for (i = backward ? nBlocks - 1 : 0;
+ backward ? i >= 0 : i < nBlocks;
+ i += backward ? -1 : 1) {
+ blk = blocks[i];
+
+ // check: is the block above the top limit?
+ // (this only works if the page's primary rotation is zero --
+ // otherwise the blocks won't be sorted in the useful order)
+ if (!startAtTop && primaryRot == 0 &&
+ (backward ? blk->yMin > yStart : blk->yMax < yStart)) {
+ continue;
+ }
+
+ // check: is the block below the bottom limit?
+ // (this only works if the page's primary rotation is zero --
+ // otherwise the blocks won't be sorted in the useful order)
+ if (!stopAtBottom && primaryRot == 0 &&
+ (backward ? blk->yMax < yStop : blk->yMin > yStop)) {
+ break;
+ }
+
+ for (line = blk->lines; line; line = line->next) {
+
+ // check: is the line above the top limit?
+ // (this only works if the page's primary rotation is zero --
+ // otherwise the lines won't be sorted in the useful order)
+ if (!startAtTop && primaryRot == 0 &&
+ (backward ? line->yMin > yStart : line->yMin < yStart)) {
+ continue;
+ }
+
+ // check: is the line below the bottom limit?
+ // (this only works if the page's primary rotation is zero --
+ // otherwise the lines won't be sorted in the useful order)
+ if (!stopAtBottom && primaryRot == 0 &&
+ (backward ? line->yMin < yStop : line->yMin > yStop)) {
+ continue;
+ }
+
+ if (!line->normalized)
+ line->normalized = unicodeNormalizeNFKC(line->text, line->len,
+ &line->normalized_len,
+ &line->normalized_idx);
+ // convert the line to uppercase
+ m = line->normalized_len;
+ if (!caseSensitive) {
+ if (m > txtSize) {
+ txt = (Unicode *)greallocn(txt, m, sizeof(Unicode));
+ txtSize = m;
+ }
+ for (k = 0; k < m; ++k) {
+ txt[k] = unicodeToUpper(line->normalized[k]);
+ }
+ } else {
+ txt = line->normalized;
+ }
+
+ // search each position in this line
+ j = backward ? m - len : 0;
+ p = txt + j;
+ while (backward ? j >= 0 : j <= m - len) {
+ if (!wholeWord ||
+ ((j == 0 || !unicodeTypeAlphaNum(txt[j - 1])) &&
+ (j + len == m || !unicodeTypeAlphaNum(txt[j + len])))) {
+
+ // compare the strings
+ for (k = 0; k < len; ++k) {
+ if (p[k] != s2[k]) {
+ break;
+ }
+ }
+
+ // found it
+ if (k == len) {
+ // where s2 matches a subsequence of a compatibility equivalence
+ // decomposition, highlight the entire glyph, since we don't know
+ // the internal layout of subglyph components
+ int normStart = line->normalized_idx[j];
+ int normAfterEnd = line->normalized_idx[j + len - 1] + 1;
+ switch (line->rot) {
+ case 0:
+ xMin1 = line->edge[normStart];
+ xMax1 = line->edge[normAfterEnd];
+ yMin1 = line->yMin;
+ yMax1 = line->yMax;
+ break;
+ case 1:
+ xMin1 = line->xMin;
+ xMax1 = line->xMax;
+ yMin1 = line->edge[normStart];
+ yMax1 = line->edge[normAfterEnd];
+ break;
+ case 2:
+ xMin1 = line->edge[normAfterEnd];
+ xMax1 = line->edge[normStart];
+ yMin1 = line->yMin;
+ yMax1 = line->yMax;
+ break;
+ case 3:
+ xMin1 = line->xMin;
+ xMax1 = line->xMax;
+ yMin1 = line->edge[normAfterEnd];
+ yMax1 = line->edge[normStart];
+ break;
+ }
+ if (backward) {
+ if ((startAtTop ||
+ yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
+ (stopAtBottom ||
+ yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
+ if (!found ||
+ yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
+ xMin0 = xMin1;
+ xMax0 = xMax1;
+ yMin0 = yMin1;
+ yMax0 = yMax1;
+ found = gTrue;
+ }
+ }
+ } else {
+ if ((startAtTop ||
+ yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
+ (stopAtBottom ||
+ yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
+ if (!found ||
+ yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
+ xMin0 = xMin1;
+ xMax0 = xMax1;
+ yMin0 = yMin1;
+ yMax0 = yMax1;
+ found = gTrue;
+ }
+ }
+ }
+ }
+ }
+ if (backward) {
+ --j;
+ --p;
+ } else {
+ ++j;
+ ++p;
+ }
+ }
+ }
+ }
+
+ gfree(s2);
+ if (!caseSensitive) {
+ gfree(txt);
+ }
+
+ if (found) {
+ *xMin = xMin0;
+ *xMax = xMax0;
+ *yMin = yMin0;
+ *yMax = yMax0;
+ lastFindXMin = xMin0;
+ lastFindYMin = yMin0;
+ haveLastFind = gTrue;
+ return gTrue;
+ }
+
+ return gFalse;
+}
+
+GooString *TextPage::getText(double xMin, double yMin,
+ double xMax, double yMax) {
+ GooString *s;
+ UnicodeMap *uMap;
+ TextBlock *blk;
+ TextLine *line;
+ TextLineFrag *frags;
+ int nFrags, fragsSize;
+ TextLineFrag *frag;
+ char space[8], eol[16];
+ int spaceLen, eolLen;
+ int lastRot;
+ double x, y, delta;
+ int col, idx0, idx1, i, j;
+ GBool multiLine, oneRot;
+
+ s = new GooString();
+
+ // get the output encoding
+ if (!(uMap = globalParams->getTextEncoding())) {
+ return s;
+ }
+
+ if (rawOrder) {
+ TextWord* word;
+ char mbc[16];
+ int mbc_len;
+
+ for (word = rawWords; word && word <= rawLastWord; word = word->next) {
+ for (j = 0; j < word->getLength(); ++j) {
+ double gXMin, gXMax, gYMin, gYMax;
+ word->getCharBBox(j, &gXMin, &gYMin, &gXMax, &gYMax);
+ if (xMin <= gXMin && gXMax <= xMax && yMin <= gYMin && gYMax <= yMax)
+ {
+ mbc_len = uMap->mapUnicode( *(word->getChar(j)), mbc, sizeof(mbc) );
+ s->append(mbc, mbc_len);
+ }
+ }
+ }
+ return s;
+ }
+
+ spaceLen = uMap->mapUnicode(0x20, space, sizeof(space));
+ eolLen = 0; // make gcc happy
+ switch (globalParams->getTextEOL()) {
+ case eolUnix:
+ eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol));
+ break;
+ case eolDOS:
+ eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol));
+ eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen);
+ break;
+ case eolMac:
+ eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol));
+ break;
+ }
+
+ //~ writing mode (horiz/vert)
+
+ // collect the line fragments that are in the rectangle
+ fragsSize = 256;
+ frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag));
+ nFrags = 0;
+ lastRot = -1;
+ oneRot = gTrue;
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ if (xMin < blk->xMax && blk->xMin < xMax &&
+ yMin < blk->yMax && blk->yMin < yMax) {
+ for (line = blk->lines; line; line = line->next) {
+ if (xMin < line->xMax && line->xMin < xMax &&
+ yMin < line->yMax && line->yMin < yMax) {
+ idx0 = idx1 = -1;
+ switch (line->rot) {
+ case 0:
+ y = 0.5 * (line->yMin + line->yMax);
+ if (yMin < y && y < yMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 1:
+ x = 0.5 * (line->xMin + line->xMax);
+ if (xMin < x && x < xMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 2:
+ y = 0.5 * (line->yMin + line->yMax);
+ if (yMin < y && y < yMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 3:
+ x = 0.5 * (line->xMin + line->xMax);
+ if (xMin < x && x < xMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ }
+ if (idx0 >= 0 && idx1 >= 0) {
+ if (nFrags == fragsSize) {
+ fragsSize *= 2;
+ frags = (TextLineFrag *)
+ greallocn(frags, fragsSize, sizeof(TextLineFrag));
+ }
+ frags[nFrags].init(line, idx0, idx1 - idx0 + 1);
+ ++nFrags;
+ if (lastRot >= 0 && line->rot != lastRot) {
+ oneRot = gFalse;
+ }
+ lastRot = line->rot;
+ }
+ }
+ }
+ }
+ }
+
+ // sort the fragments and generate the string
+ if (nFrags > 0) {
+
+ for (i = 0; i < nFrags; ++i) {
+ frags[i].computeCoords(oneRot);
+ }
+ assignColumns(frags, nFrags, oneRot);
+
+ // if all lines in the region have the same rotation, use it;
+ // otherwise, use the page's primary rotation
+ if (oneRot) {
+ qsort(frags, nFrags, sizeof(TextLineFrag),
+ &TextLineFrag::cmpYXLineRot);
+ } else {
+ qsort(frags, nFrags, sizeof(TextLineFrag),
+ &TextLineFrag::cmpYXPrimaryRot);
+ }
+ i = 0;
+ while (i < nFrags) {
+ delta = maxIntraLineDelta * frags[i].line->words->fontSize;
+ for (j = i+1;
+ j < nFrags && fabs(frags[j].base - frags[i].base) < delta;
+ ++j) ;
+ qsort(frags + i, j - i, sizeof(TextLineFrag),
+ oneRot ? &TextLineFrag::cmpXYColumnLineRot
+ : &TextLineFrag::cmpXYColumnPrimaryRot);
+ i = j;
+ }
+
+ col = 0;
+ multiLine = gFalse;
+ for (i = 0; i < nFrags; ++i) {
+ frag = &frags[i];
+
+ // insert a return
+ if (frag->col < col ||
+ (i > 0 && fabs(frag->base - frags[i-1].base) >
+ maxIntraLineDelta * frags[i-1].line->words->fontSize)) {
+ s->append(eol, eolLen);
+ col = 0;
+ multiLine = gTrue;
+ }
+
+ // column alignment
+ for (; col < frag->col; ++col) {
+ s->append(space, spaceLen);
+ }
+
+ // get the fragment text
+ col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s);
+ }
+
+ if (multiLine) {
+ s->append(eol, eolLen);
+ }
+ }
+
+ gfree(frags);
+ uMap->decRefCnt();
+
+ return s;
+}
+
+class TextSelectionVisitor {
+public:
+ TextSelectionVisitor (TextPage *page);
+ virtual ~TextSelectionVisitor () { }
+ virtual void visitBlock (TextBlock *block,
+ TextLine *begin,
+ TextLine *end,
+ PDFRectangle *selection) = 0;
+ virtual void visitLine (TextLine *line,
+ TextWord *begin,
+ TextWord *end,
+ int edge_begin,
+ int edge_end,
+ PDFRectangle *selection) = 0;
+ virtual void visitWord (TextWord *word, int begin, int end,
+ PDFRectangle *selection) = 0;
+
+protected:
+ TextPage *page;
+};
+
+TextSelectionVisitor::TextSelectionVisitor (TextPage *page)
+ : page(page)
+{
+}
+
+
+class TextSelectionDumper : public TextSelectionVisitor {
+public:
+ TextSelectionDumper(TextPage *page);
+ virtual ~TextSelectionDumper();
+
+ virtual void visitBlock (TextBlock *block,
+ TextLine *begin,
+ TextLine *end,
+ PDFRectangle *selection) { };
+ virtual void visitLine (TextLine *line,
+ TextWord *begin,
+ TextWord *end,
+ int edge_begin,
+ int edge_end,
+ PDFRectangle *selection);
+ virtual void visitWord (TextWord *word, int begin, int end,
+ PDFRectangle *selection);
+ void endPage();
+
+ GooString *getText(void);
+ GooList **takeWordList(int *nLines);
+
+private:
+
+ void startLine();
+ void finishLine();
+
+ GooList **lines;
+ int nLines, linesSize;
+ GooList *words;
+ int tableId;
+ TextBlock *currentBlock;
+};
+
+TextSelectionDumper::TextSelectionDumper(TextPage *page)
+ : TextSelectionVisitor(page)
+{
+ linesSize = 256;
+ lines = (GooList **)gmallocn(linesSize, sizeof(GooList *));
+ nLines = 0;
+
+ tableId = -1;
+ currentBlock = NULL;
+ words = NULL;
+}
+
+TextSelectionDumper::~TextSelectionDumper()
+{
+ for (int i = 0; i < nLines; i++)
+ deleteGooList(lines[i], TextWordSelection);
+ gfree(lines);
+}
+
+void TextSelectionDumper::startLine()
+{
+ finishLine();
+ words = new GooList();
+}
+
+void TextSelectionDumper::finishLine()
+{
+ if (nLines == linesSize) {
+ linesSize *= 2;
+ lines = (GooList **)grealloc(lines, linesSize * sizeof(GooList *));
+ }
+
+ if (words && words->getLength() > 0)
+ lines[nLines++] = words;
+ else if (words)
+ delete words;
+ words = NULL;
+}
+
+void TextSelectionDumper::visitLine (TextLine *line,
+ TextWord *begin,
+ TextWord *end,
+ int edge_begin,
+ int edge_end,
+ PDFRectangle *selection)
+{
+ TextLineFrag frag;
+
+ frag.init(line, edge_begin, edge_end - edge_begin);
+
+ if (tableId >= 0 && frag.line->blk->tableId < 0) {
+ finishLine();
+
+ tableId = -1;
+ currentBlock = NULL;
+ }
+
+ if (frag.line->blk->tableId >= 0) { // a table
+ if (tableId == -1) {
+ tableId = frag.line->blk->tableId;
+ currentBlock = frag.line->blk;
+ }
+
+ if (currentBlock == frag.line->blk) { // the same block
+ startLine();
+ } else { // another block
+ if (currentBlock->tableEnd) { // previous block ended its row
+ startLine();
+ }
+ currentBlock = frag.line->blk;
+ }
+ } else { // not a table
+ startLine();
+ }
+}
+
+void TextSelectionDumper::visitWord (TextWord *word, int begin, int end,
+ PDFRectangle *selection)
+{
+ words->append(new TextWordSelection(word, begin, end));
+}
+
+void TextSelectionDumper::endPage()
+{
+ finishLine();
+}
+
+GooString *TextSelectionDumper::getText (void)
+{
+ GooString *text;
+ int i, j;
+ UnicodeMap *uMap;
+ char space[8], eol[16];
+ int spaceLen, eolLen;
+
+ text = new GooString();
+
+ if (!(uMap = globalParams->getTextEncoding()))
+ return text;
+
+ spaceLen = uMap->mapUnicode(0x20, space, sizeof(space));
+ eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol));
+
+ for (i = 0; i < nLines; i++) {
+ GooList *lineWords = lines[i];
+ for (j = 0; j < lineWords->getLength(); j++) {
+ TextWordSelection *sel = (TextWordSelection *)lineWords->get(j);
+
+ page->dumpFragment (sel->word->text + sel->begin, sel->end - sel->begin, uMap, text);
+ if (j < lineWords->getLength() - 1)
+ text->append(space, spaceLen);
+ }
+ if (i < nLines - 1)
+ text->append(eol, eolLen);
+ }
+
+ uMap->decRefCnt();
+
+ return text;
+}
+
+GooList **TextSelectionDumper::takeWordList(int *nLinesOut)
+{
+ GooList **returnValue = lines;
+
+ *nLinesOut = nLines;
+ if (nLines == 0)
+ return NULL;
+
+ nLines = 0;
+ lines = NULL;
+
+ return returnValue;
+}
+
+class TextSelectionSizer : public TextSelectionVisitor {
+public:
+ TextSelectionSizer(TextPage *page, double scale);
+ ~TextSelectionSizer() { }
+
+ virtual void visitBlock (TextBlock *block,
+ TextLine *begin,
+ TextLine *end,
+ PDFRectangle *selection) { };
+ virtual void visitLine (TextLine *line,
+ TextWord *begin,
+ TextWord *end,
+ int edge_begin,
+ int edge_end,
+ PDFRectangle *selection);
+ virtual void visitWord (TextWord *word, int begin, int end,
+ PDFRectangle *selection) { };
+
+ GooList *getRegion () { return list; }
+
+private:
+ GooList *list;
+ double scale;
+};
+
+TextSelectionSizer::TextSelectionSizer(TextPage *page, double scale)
+ : TextSelectionVisitor(page),
+ scale(scale)
+{
+ list = new GooList();
+}
+
+void TextSelectionSizer::visitLine (TextLine *line,
+ TextWord *begin,
+ TextWord *end,
+ int edge_begin,
+ int edge_end,
+ PDFRectangle *selection)
+{
+ PDFRectangle *rect;
+ double x1, y1, x2, y2, margin;
+
+ margin = (line->yMax - line->yMin) / 8;
+ x1 = line->edge[edge_begin];
+ y1 = line->yMin - margin;
+ x2 = line->edge[edge_end];
+ y2 = line->yMax + margin;
+
+ rect = new PDFRectangle (floor (x1 * scale),
+ floor (y1 * scale),
+ ceil (x2 * scale),
+ ceil (y2 * scale));
+ list->append (rect);
+}
+
+
+class TextSelectionPainter : public TextSelectionVisitor {
+public:
+ TextSelectionPainter(TextPage *page,
+ double scale,
+ int rotation,
+ OutputDev *out,
+ GfxColor *box_color,
+ GfxColor *glyph_color);
+ ~TextSelectionPainter();
+
+ virtual void visitBlock (TextBlock *block,
+ TextLine *begin,
+ TextLine *end,
+ PDFRectangle *selection) { };
+ virtual void visitLine (TextLine *line,
+ TextWord *begin,
+ TextWord *end,
+ int edge_begin,
+ int edge_end,
+ PDFRectangle *selection);
+ virtual void visitWord (TextWord *word, int begin, int end,
+ PDFRectangle *selection);
+ void endPage();
+
+private:
+ OutputDev *out;
+ GfxColor *box_color, *glyph_color;
+ GfxState *state;
+ GooList *selectionList;
+ Matrix ctm, ictm;
+};
+
+TextSelectionPainter::TextSelectionPainter(TextPage *page,
+ double scale,
+ int rotation,
+ OutputDev *out,
+ GfxColor *box_color,
+ GfxColor *glyph_color)
+ : TextSelectionVisitor(page),
+ out(out),
+ box_color(box_color),
+ glyph_color(glyph_color)
+{
+ PDFRectangle box(0, 0, page->pageWidth, page->pageHeight);
+
+ selectionList = new GooList();
+ state = new GfxState(72 * scale, 72 * scale, &box, rotation, gFalse);
+
+ state->getCTM(&ctm);
+ ctm.invertTo(&ictm);
+
+ out->startPage(0, state, NULL);
+ out->setDefaultCTM (state->getCTM());
+
+ state->setFillColorSpace(new GfxDeviceRGBColorSpace());
+ state->setFillColor(box_color);
+ out->updateFillColor(state);
+}
+
+TextSelectionPainter::~TextSelectionPainter()
+{
+ deleteGooList(selectionList, TextWordSelection);
+ delete state;
+}
+
+void TextSelectionPainter::visitLine (TextLine *line,
+ TextWord *begin,
+ TextWord *end,
+ int edge_begin,
+ int edge_end,
+ PDFRectangle *selection)
+{
+ double x1, y1, x2, y2, margin;
+
+ margin = (line->yMax - line->yMin) / 8;
+ x1 = floor (line->edge[edge_begin]);
+ y1 = floor (line->yMin - margin);
+ x2 = ceil (line->edge[edge_end]);
+ y2 = ceil (line->yMax + margin);
+
+ ctm.transform(line->edge[edge_begin], line->yMin - margin, &x1, &y1);
+ ctm.transform(line->edge[edge_end], line->yMax + margin, &x2, &y2);
+
+ x1 = floor (x1);
+ y1 = floor (y1);
+ x2 = ceil (x2);
+ y2 = ceil (y2);
+
+ ictm.transform(x1, y1, &x1, &y1);
+ ictm.transform(x2, y2, &x2, &y2);
+
+ state->moveTo(x1, y1);
+ state->lineTo(x2, y1);
+ state->lineTo(x2, y2);
+ state->lineTo(x1, y2);
+ state->closePath();
+}
+
+void TextSelectionPainter::visitWord (TextWord *word, int begin, int end,
+ PDFRectangle *selection)
+{
+ selectionList->append(new TextWordSelection(word, begin, end));
+}
+
+void TextSelectionPainter::endPage()
+{
+ out->fill(state);
+
+ out->saveState(state);
+ out->clip(state);
+
+ state->clearPath();
+
+ state->setFillColor(glyph_color);
+ out->updateFillColor(state);
+
+ for (int i = 0; i < selectionList->getLength(); i++) {
+ TextWordSelection *sel = (TextWordSelection *) selectionList->get(i);
+ int begin = sel->begin;
+
+ while (begin < sel->end) {
+ TextFontInfo *font = sel->word->font[begin];
+ font->gfxFont->incRefCnt();
+ Matrix *mat = &sel->word->textMat[begin];
+
+ state->setTextMat(mat->m[0], mat->m[1], mat->m[2], mat->m[3], 0, 0);
+ state->setFont(font->gfxFont, 1);
+ out->updateFont(state);
+
+ int fEnd = begin + 1;
+ while (fEnd < sel->end && font->matches(sel->word->font[fEnd]) &&
+ mat->m[0] == sel->word->textMat[fEnd].m[0] &&
+ mat->m[1] == sel->word->textMat[fEnd].m[1] &&
+ mat->m[2] == sel->word->textMat[fEnd].m[2] &&
+ mat->m[3] == sel->word->textMat[fEnd].m[3])
+ fEnd++;
+
+ /* The only purpose of this string is to let the output device query
+ * it's length. Might want to change this interface later. */
+ GooString *string = new GooString ((char *) sel->word->charcode, fEnd - begin);
+ out->beginString(state, string);
+
+ for (int i = begin; i < fEnd; i++) {
+ if (i != begin && sel->word->charPos[i] == sel->word->charPos[i - 1])
+ continue;
+
+ out->drawChar(state, sel->word->textMat[i].m[4], sel->word->textMat[i].m[5], 0, 0, 0, 0,
+ sel->word->charcode[i], 1, NULL, 0);
+ }
+ out->endString(state);
+ delete string;
+ begin = fEnd;
+ }
+ }
+
+ out->restoreState(state);
+ out->endPage ();
+}
+
+void TextWord::visitSelection(TextSelectionVisitor *visitor,
+ PDFRectangle *selection,
+ SelectionStyle style)
+{
+ int i, begin, end;
+ double mid;
+
+ begin = len;
+ end = 0;
+ for (i = 0; i < len; i++) {
+ mid = (edge[i] + edge[i + 1]) / 2;
+ if (selection->x1 < mid || selection->x2 < mid)
+ if (i < begin)
+ begin = i;
+ if (mid < selection->x1 || mid < selection->x2)
+ end = i + 1;
+ }
+
+ /* Skip empty selection. */
+ if (end <= begin)
+ return;
+
+ visitor->visitWord (this, begin, end, selection);
+}
+
+void TextLine::visitSelection(TextSelectionVisitor *visitor,
+ PDFRectangle *selection,
+ SelectionStyle style) {
+ TextWord *p, *begin, *end, *current;
+ int i, edge_begin, edge_end;
+ PDFRectangle child_selection;
+
+ begin = NULL;
+ end = NULL;
+ current = NULL;
+ for (p = words; p != NULL; p = p->next) {
+ if (blk->page->primaryLR) {
+ if ((selection->x1 < p->xMax) ||
+ (selection->x2 < p->xMax))
+ if (begin == NULL)
+ begin = p;
+
+ if (((selection->x1 > p->xMin) ||
+ (selection->x2 > p->xMin)) && (begin != NULL)) {
+ end = p->next;
+ current = p;
+ }
+ } else {
+ if ((selection->x1 > p->xMin) ||
+ (selection->x2 > p->xMin))
+ if (begin == NULL)
+ begin = p;
+
+ if (((selection->x1 < p->xMax) ||
+ (selection->x2 < p->xMax)) && (begin != NULL)) {
+ end = p->next;
+ current = p;
+ }
+ }
+ }
+
+ if (!current)
+ current = begin;
+
+ child_selection = *selection;
+ if (style == selectionStyleWord) {
+ child_selection.x1 = begin ? begin->xMin : xMin;
+ if (end && end->xMax != -1) {
+ child_selection.x2 = current->xMax;
+ } else {
+ child_selection.x2 = xMax;
+ }
+ }
+
+ edge_begin = len;
+ edge_end = 0;
+ for (i = 0; i < len; i++) {
+ double mid = (edge[i] + edge[i + 1]) / 2;
+ if (child_selection.x1 < mid || child_selection.x2 < mid)
+ if (i < edge_begin)
+ edge_begin = i;
+ if (mid < child_selection.x2 || mid < child_selection.x1)
+ edge_end = i + 1;
+ }
+
+ /* Skip empty selection. */
+ if (edge_end <= edge_begin)
+ return;
+
+ visitor->visitLine (this, begin, end, edge_begin, edge_end,
+ &child_selection);
+
+ for (p = begin; p != end; p = p->next)
+ p->visitSelection (visitor, &child_selection, style);
+}
+
+void TextBlock::visitSelection(TextSelectionVisitor *visitor,
+ PDFRectangle *selection,
+ SelectionStyle style) {
+ PDFRectangle child_selection;
+ double x[2], y[2], d, best_d[2];
+ TextLine *p, *best_line[2];
+ int i, count = 0, best_count[2], start, stop;
+ GBool all[2];
+
+ x[0] = selection->x1;
+ y[0] = selection->y1;
+ x[1] = selection->x2;
+ y[1] = selection->y2;
+
+ for (i = 0; i < 2; i++) {
+ // the first/last lines are often not nearest
+ // the corners, so we have to force them to be
+ // selected when the selection runs outside this
+ // block.
+ if (page->primaryLR) {
+ all[i] = x[i] >= this->xMax && y[i] >= this->yMax;
+ if (x[i] <= this->xMin && y[i] <= this->yMin) {
+ best_line[i] = this->lines;
+ best_count[i] = 1;
+ } else {
+ best_line[i] = NULL;
+ best_count[i] = 0;
+ }
+ } else {
+ all[i] = x[i] <= this->xMin && y[i] >= this->yMax;
+ if (x[i] >= this->xMax && y[i] <= this->yMin) {
+ best_line[i] = this->lines;
+ best_count[i] = 1;
+ } else {
+ best_line[i] = NULL;
+ best_count[i] = 0;
+ }
+ }
+ best_d[i] = 0;
+ }
+
+ // find the nearest line to the selection points
+ // using the manhattan distance.
+ for (p = this->lines; p; p = p->next) {
+ count++;
+ for (i = 0; i < 2; i++) {
+ d = fmax(p->xMin - x[i], 0.0) +
+ fmax(x[i] - p->xMax, 0.0) +
+ fmax(p->yMin - y[i], 0.0) +
+ fmax(y[i] - p->yMax, 0.0);
+ if (!best_line[i] || all[i] ||
+ d < best_d[i]) {
+ best_line[i] = p;
+ best_count[i] = count;
+ best_d[i] = d;
+ }
+ }
+ }
+ // assert: best is always set.
+ if (!best_line[0] || !best_line[1]) {
+ return;
+ }
+
+ // Now decide which point was first.
+ if (best_count[0] < best_count[1] ||
+ (best_count[0] == best_count[1] &&
+ y[0] < y[1])) {
+ start = 0;
+ stop = 1;
+ } else {
+ start = 1;
+ stop = 0;
+ }
+
+ visitor->visitBlock(this, best_line[start], best_line[stop], selection);
+
+ for (p = best_line[start]; p; p = p->next) {
+ if (page->primaryLR) {
+ child_selection.x1 = p->xMin;
+ child_selection.x2 = p->xMax;
+ } else {
+ child_selection.x1 = p->xMax;
+ child_selection.x2 = p->xMin;
+ }
+ child_selection.y1 = p->yMin;
+ child_selection.y2 = p->yMax;
+ if (style == selectionStyleLine) {
+ if (p == best_line[start]) {
+ child_selection.x1 = 0;
+ child_selection.y1 = 0;
+ }
+ if (p == best_line[stop]) {
+ child_selection.x2 = page->pageWidth;
+ child_selection.y2 = page->pageHeight;
+ }
+ } else {
+ if (p == best_line[start]) {
+ child_selection.x1 = fmax(p->xMin, fmin(p->xMax, x[start]));
+ child_selection.y1 = fmax(p->yMin, fmin(p->yMax, y[start]));
+ }
+ if (p == best_line[stop]) {
+ child_selection.x2 = fmax(p->xMin, fmin(p->xMax, x[stop]));
+ child_selection.y2 = fmax(p->yMin, fmin(p->yMax, y[stop]));
+ }
+ }
+ p->visitSelection(visitor, &child_selection, style);
+ if (p == best_line[stop]) {
+ return;
+ }
+ }
+}
+
+void TextPage::visitSelection(TextSelectionVisitor *visitor,
+ PDFRectangle *selection,
+ SelectionStyle style)
+{
+ PDFRectangle child_selection;
+ double x[2], y[2], d, best_d[2];
+ double xMin, yMin, xMax, yMax;
+ TextFlow *flow, *best_flow[2];
+ TextBlock *blk, *best_block[2];
+ int i, count = 0, best_count[2], start, stop;
+
+ if (!flows)
+ return;
+
+ x[0] = selection->x1;
+ y[0] = selection->y1;
+ x[1] = selection->x2;
+ y[1] = selection->y2;
+
+ xMin = pageWidth;
+ yMin = pageHeight;
+ xMax = 0.0;
+ yMax = 0.0;
+
+ for (i = 0; i < 2; i++) {
+ best_block[i] = NULL;
+ best_flow[i] = NULL;
+ best_count[i] = 0;
+ best_d[i] = 0;
+ }
+
+ // find the nearest blocks to the selection points
+ // using the manhattan distance.
+ for (flow = flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ count++;
+ // the first/last blocks in reading order are
+ // often not the closest to the page corners;
+ // track the corners, force those blocks to
+ // be selected if the selection runs across
+ // multiple pages.
+ xMin = fmin(xMin, blk->xMin);
+ yMin = fmin(yMin, blk->yMin);
+ xMax = fmax(xMax, blk->xMax);
+ yMax = fmax(yMax, blk->yMax);
+ for (i = 0; i < 2; i++) {
+ d = fmax(blk->xMin - x[i], 0.0) +
+ fmax(x[i] - blk->xMax, 0.0) +
+ fmax(blk->yMin - y[i], 0.0) +
+ fmax(y[i] - blk->yMax, 0.0);
+ if (!best_block[i] ||
+ d < best_d[i] ||
+ (!blk->next && !flow->next &&
+ x[i] >= fmin(xMax, pageWidth) &&
+ y[i] >= fmin(yMax, pageHeight))) {
+ best_block[i] = blk;
+ best_flow[i] = flow;
+ best_count[i] = count;
+ best_d[i] = d;
+ }
+ }
+ }
+ }
+ for (i = 0; i < 2; i++) {
+ if (primaryLR) {
+ if (x[i] < xMin && y[i] < yMin) {
+ best_block[i] = flows->blocks;
+ best_flow[i] = flows;
+ best_count[i] = 1;
+ }
+ } else {
+ if (x[i] > xMax && y[i] < yMin) {
+ best_block[i] = flows->blocks;
+ best_flow[i] = flows;
+ best_count[i] = 1;
+ }
+ }
+ }
+ // assert: best is always set.
+ if (!best_block[0] || !best_block[1]) {
+ return;
+ }
+
+ // Now decide which point was first.
+ if (best_count[0] < best_count[1] ||
+ (best_count[0] == best_count[1] && y[0] < y[1])) {
+ start = 0;
+ stop = 1;
+ } else {
+ start = 1;
+ stop = 0;
+ }
+
+ for (flow = best_flow[start]; flow; flow = flow->next) {
+ if (flow == best_flow[start]) {
+ blk = best_block[start];
+ } else {
+ blk = flow->blocks;
+ }
+ for (; blk; blk = blk->next) {
+ if (primaryLR) {
+ child_selection.x1 = blk->xMin;
+ child_selection.x2 = blk->xMax;
+ } else {
+ child_selection.x1 = blk->xMax;
+ child_selection.x2 = blk->xMin;
+ }
+ child_selection.y1 = blk->yMin;
+ child_selection.y2 = blk->yMax;
+ if (blk == best_block[start]) {
+ child_selection.x1 = fmax(blk->xMin, fmin(blk->xMax, x[start]));
+ child_selection.y1 = fmax(blk->yMin, fmin(blk->yMax, y[start]));
+ }
+ if (blk == best_block[stop]) {
+ child_selection.x2 = fmax(blk->xMin, fmin(blk->xMax, x[stop]));
+ child_selection.y2 = fmax(blk->yMin, fmin(blk->yMax, y[stop]));
+ blk->visitSelection(visitor, &child_selection, style);
+ return;
+ }
+ blk->visitSelection(visitor, &child_selection, style);
+ }
+ }
+}
+
+void TextPage::drawSelection(OutputDev *out,
+ double scale,
+ int rotation,
+ PDFRectangle *selection,
+ SelectionStyle style,
+ GfxColor *glyph_color, GfxColor *box_color)
+{
+ TextSelectionPainter painter(this, scale, rotation,
+ out, box_color, glyph_color);
+
+ visitSelection(&painter, selection, style);
+ painter.endPage();
+}
+
+GooList *TextPage::getSelectionRegion(PDFRectangle *selection,
+ SelectionStyle style,
+ double scale) {
+ TextSelectionSizer sizer(this, scale);
+
+ visitSelection(&sizer, selection, style);
+
+ return sizer.getRegion();
+}
+
+GooString *TextPage::getSelectionText(PDFRectangle *selection,
+ SelectionStyle style)
+{
+ TextSelectionDumper dumper(this);
+
+ visitSelection(&dumper, selection, style);
+ dumper.endPage();
+
+ return dumper.getText();
+}
+
+GooList **TextPage::getSelectionWords(PDFRectangle *selection,
+ SelectionStyle style,
+ int *nLines)
+{
+ TextSelectionDumper dumper(this);
+
+ visitSelection(&dumper, selection, style);
+ dumper.endPage();
+
+ return dumper.takeWordList(nLines);
+}
+
+GBool TextPage::findCharRange(int pos, int length,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ TextBlock *blk;
+ TextLine *line;
+ TextWord *word;
+ double xMin0, xMax0, yMin0, yMax0;
+ double xMin1, xMax1, yMin1, yMax1;
+ GBool first;
+ int i, j0, j1;
+
+ if (rawOrder) {
+ return gFalse;
+ }
+
+ //~ this doesn't correctly handle ranges split across multiple lines
+ //~ (the highlighted region is the bounding box of all the parts of
+ //~ the range)
+ first = gTrue;
+ xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy
+ xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ if (pos < word->charPos[word->len] &&
+ pos + length > word->charPos[0]) {
+ for (j0 = 0;
+ j0 < word->len && pos >= word->charPos[j0 + 1];
+ ++j0) ;
+ for (j1 = word->len - 1;
+ j1 > j0 && pos + length <= word->charPos[j1];
+ --j1) ;
+ switch (line->rot) {
+ case 0:
+ xMin1 = word->edge[j0];
+ xMax1 = word->edge[j1 + 1];
+ yMin1 = word->yMin;
+ yMax1 = word->yMax;
+ break;
+ case 1:
+ xMin1 = word->xMin;
+ xMax1 = word->xMax;
+ yMin1 = word->edge[j0];
+ yMax1 = word->edge[j1 + 1];
+ break;
+ case 2:
+ xMin1 = word->edge[j1 + 1];
+ xMax1 = word->edge[j0];
+ yMin1 = word->yMin;
+ yMax1 = word->yMax;
+ break;
+ case 3:
+ xMin1 = word->xMin;
+ xMax1 = word->xMax;
+ yMin1 = word->edge[j1 + 1];
+ yMax1 = word->edge[j0];
+ break;
+ }
+ if (first || xMin1 < xMin0) {
+ xMin0 = xMin1;
+ }
+ if (first || xMax1 > xMax0) {
+ xMax0 = xMax1;
+ }
+ if (first || yMin1 < yMin0) {
+ yMin0 = yMin1;
+ }
+ if (first || yMax1 > yMax0) {
+ yMax0 = yMax1;
+ }
+ first = gFalse;
+ }
+ }
+ }
+ }
+ if (!first) {
+ *xMin = xMin0;
+ *xMax = xMax0;
+ *yMin = yMin0;
+ *yMax = yMax0;
+ return gTrue;
+ }
+ return gFalse;
+}
+
+void TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
+ GBool physLayout) {
+ UnicodeMap *uMap;
+ TextFlow *flow;
+ TextBlock *blk;
+ TextLine *line;
+ TextLineFrag *frags;
+ TextWord *word;
+ int nFrags, fragsSize;
+ TextLineFrag *frag;
+ char space[8], eol[16], eop[8];
+ int spaceLen, eolLen, eopLen;
+ GBool pageBreaks;
+ GooString *s;
+ double delta;
+ int col, i, j, d, n;
+
+ // get the output encoding
+ if (!(uMap = globalParams->getTextEncoding())) {
+ return;
+ }
+ spaceLen = uMap->mapUnicode(0x20, space, sizeof(space));
+ eolLen = 0; // make gcc happy
+ switch (globalParams->getTextEOL()) {
+ case eolUnix:
+ eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol));
+ break;
+ case eolDOS:
+ eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol));
+ eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen);
+ break;
+ case eolMac:
+ eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol));
+ break;
+ }
+ eopLen = uMap->mapUnicode(0x0c, eop, sizeof(eop));
+ pageBreaks = globalParams->getTextPageBreaks();
+
+ //~ writing mode (horiz/vert)
+
+ // output the page in raw (content stream) order
+ if (rawOrder) {
+
+ for (word = rawWords; word; word = word->next) {
+ s = new GooString();
+ dumpFragment(word->text, word->len, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+ if (word->next &&
+ fabs(word->next->base - word->base) <
+ maxIntraLineDelta * word->fontSize &&
+ word->next->xMin >
+ word->xMax - minDupBreakOverlap * word->fontSize) {
+ if (word->next->xMin > word->xMax + minWordSpacing * word->fontSize) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ }
+ } else {
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ }
+
+ // output the page, maintaining the original physical layout
+ } else if (physLayout) {
+
+ // collect the line fragments for the page and sort them
+ fragsSize = 256;
+ frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag));
+ nFrags = 0;
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ for (line = blk->lines; line; line = line->next) {
+ if (nFrags == fragsSize) {
+ fragsSize *= 2;
+ frags = (TextLineFrag *)greallocn(frags,
+ fragsSize, sizeof(TextLineFrag));
+ }
+ frags[nFrags].init(line, 0, line->len);
+ frags[nFrags].computeCoords(gTrue);
+ ++nFrags;
+ }
+ }
+ qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot);
+ i = 0;
+ while (i < nFrags) {
+ delta = maxIntraLineDelta * frags[i].line->words->fontSize;
+ for (j = i+1;
+ j < nFrags && fabs(frags[j].base - frags[i].base) < delta;
+ ++j) ;
+ qsort(frags + i, j - i, sizeof(TextLineFrag),
+ &TextLineFrag::cmpXYColumnPrimaryRot);
+ i = j;
+ }
+
+#if 0 // for debugging
+ printf("*** line fragments ***\n");
+ for (i = 0; i < nFrags; ++i) {
+ frag = &frags[i];
+ printf("frag: x=%.2f..%.2f y=%.2f..%.2f base=%.2f '",
+ frag->xMin, frag->xMax, frag->yMin, frag->yMax, frag->base);
+ for (n = 0; n < frag->len; ++n) {
+ fputc(frag->line->text[frag->start + n] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ printf("\n");
+#endif
+
+ // generate output
+ col = 0;
+ for (i = 0; i < nFrags; ++i) {
+ frag = &frags[i];
+
+ // column alignment
+ for (; col < frag->col; ++col) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ }
+
+ // print the line
+ s = new GooString();
+ col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+
+ // print one or more returns if necessary
+ if (i == nFrags - 1 ||
+ frags[i+1].col < col ||
+ fabs(frags[i+1].base - frag->base) >
+ maxIntraLineDelta * frag->line->words->fontSize) {
+ if (i < nFrags - 1) {
+ d = (int)((frags[i+1].base - frag->base) /
+ frag->line->words->fontSize);
+ if (d < 1) {
+ d = 1;
+ } else if (d > 5) {
+ d = 5;
+ }
+ } else {
+ d = 1;
+ }
+ for (; d > 0; --d) {
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ col = 0;
+ }
+ }
+
+ gfree(frags);
+
+ // output the page, "undoing" the layout
+ } else {
+ for (flow = flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ n = line->len;
+ if (line->hyphenated && (line->next || blk->next)) {
+ --n;
+ }
+ s = new GooString();
+ dumpFragment(line->text, n, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+ // output a newline when a hyphen is not suppressed
+ if (n == line->len) {
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ }
+ }
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ }
+
+ // end of page
+ if (pageBreaks) {
+ (*outputFunc)(outputStream, eop, eopLen);
+ }
+
+ uMap->decRefCnt();
+}
+
+void TextPage::setMergeCombining(GBool merge) {
+ mergeCombining = merge;
+}
+
+void TextPage::assignColumns(TextLineFrag *frags, int nFrags, GBool oneRot) {
+ TextLineFrag *frag0, *frag1;
+ int rot, col1, col2, i, j, k;
+
+ // all text in the region has the same rotation -- recompute the
+ // column numbers based only on the text in the region
+ if (oneRot) {
+ qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpXYLineRot);
+ rot = frags[0].line->rot;
+ for (i = 0; i < nFrags; ++i) {
+ frag0 = &frags[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ frag1 = &frags[j];
+ col2 = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ if (frag0->xMin >= frag1->xMax) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->xMin >= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 1:
+ if (frag0->yMin >= frag1->yMax) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->yMin >= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 2:
+ if (frag0->xMax <= frag1->xMin) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->xMax <= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 3:
+ if (frag0->yMax <= frag1->yMin) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->yMax <= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ frag0->col = col1;
+ }
+
+ // the region includes text at different rotations -- use the
+ // globally assigned column numbers, offset by the minimum column
+ // number (i.e., shift everything over to column 0)
+ } else {
+ col1 = frags[0].col;
+ for (i = 1; i < nFrags; ++i) {
+ if (frags[i].col < col1) {
+ col1 = frags[i].col;
+ }
+ }
+ for (i = 0; i < nFrags; ++i) {
+ frags[i].col -= col1;
+ }
+ }
+}
+
+int TextPage::dumpFragment(Unicode *text, int len, UnicodeMap *uMap,
+ GooString *s) {
+ char lre[8], rle[8], popdf[8], buf[8];
+ int lreLen, rleLen, popdfLen, n;
+ int nCols, i, j, k;
+
+ nCols = 0;
+
+ if (uMap->isUnicode()) {
+
+ lreLen = uMap->mapUnicode(0x202a, lre, sizeof(lre));
+ rleLen = uMap->mapUnicode(0x202b, rle, sizeof(rle));
+ popdfLen = uMap->mapUnicode(0x202c, popdf, sizeof(popdf));
+
+ if (primaryLR) {
+
+ i = 0;
+ while (i < len) {
+ // output a left-to-right section
+ for (j = i; j < len && !unicodeTypeR(text[j]); ++j) ;
+ for (k = i; k < j; ++k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ i = j;
+ // output a right-to-left section
+ for (j = i;
+ j < len && !(unicodeTypeL(text[j]) || unicodeTypeNum(text[j]));
+ ++j) ;
+ if (j > i) {
+ s->append(rle, rleLen);
+ for (k = j - 1; k >= i; --k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ s->append(popdf, popdfLen);
+ i = j;
+ }
+ }
+
+ } else {
+
+ // Note: This code treats numeric characters (European and
+ // Arabic/Indic) as left-to-right, which isn't strictly correct
+ // (incurs extra LRE/POPDF pairs), but does produce correct
+ // visual formatting.
+ s->append(rle, rleLen);
+ i = len - 1;
+ while (i >= 0) {
+ // output a right-to-left section
+ for (j = i;
+ j >= 0 && !(unicodeTypeL(text[j]) || unicodeTypeNum(text[j]));
+ --j) ;
+ for (k = i; k > j; --k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ i = j;
+ // output a left-to-right section
+ for (j = i; j >= 0 && !unicodeTypeR(text[j]); --j) ;
+ if (j < i) {
+ s->append(lre, lreLen);
+ for (k = j + 1; k <= i; ++k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ s->append(popdf, popdfLen);
+ i = j;
+ }
+ }
+ s->append(popdf, popdfLen);
+
+ }
+
+ } else {
+ for (i = 0; i < len; ++i) {
+ n = uMap->mapUnicode(text[i], buf, sizeof(buf));
+ s->append(buf, n);
+ nCols += n;
+ }
+ }
+
+ return nCols;
+}
+
+#if TEXTOUT_WORD_LIST
+TextWordList *TextPage::makeWordList(GBool physLayout) {
+ return new TextWordList(this, physLayout);
+}
+#endif
+
+//------------------------------------------------------------------------
+// ActualText
+//------------------------------------------------------------------------
+ActualText::ActualText(TextPage *out) {
+ out->incRefCnt();
+ text = out;
+ actualText = NULL;
+ actualTextNBytes = 0;
+}
+
+ActualText::~ActualText() {
+ if (actualText)
+ delete actualText;
+ text->decRefCnt();
+}
+
+void ActualText::addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen) {
+ if (!actualText) {
+ text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
+ return;
+ }
+
+ // Inside ActualText span.
+ if (!actualTextNBytes) {
+ actualTextX0 = x;
+ actualTextY0 = y;
+ }
+ actualTextX1 = x + dx;
+ actualTextY1 = y + dy;
+ actualTextNBytes += nBytes;
+}
+
+void ActualText::begin(GfxState *state, GooString *text) {
+ if (actualText)
+ delete actualText;
+ actualText = new GooString(text);
+ actualTextNBytes = 0;
+}
+
+void ActualText::end(GfxState *state) {
+ // ActualText span closed. Output the span text and the
+ // extents of all the glyphs inside the span
+
+ if (actualTextNBytes) {
+ Unicode *uni = NULL;
+ int length;
+
+ // now that we have the position info for all of the text inside
+ // the marked content span, we feed the "ActualText" back through
+ // text->addChar()
+ length = TextStringToUCS4(actualText, &uni);
+ text->addChar(state, actualTextX0, actualTextY0,
+ actualTextX1 - actualTextX0, actualTextY1 - actualTextY0,
+ 0, actualTextNBytes, uni, length);
+ gfree(uni);
+ }
+
+ delete actualText;
+ actualText = NULL;
+ actualTextNBytes = 0;
+}
+
+//------------------------------------------------------------------------
+// TextOutputDev
+//------------------------------------------------------------------------
+
+static void TextOutputDev_outputToFile(void *stream, const char *text, int len) {
+ fwrite(text, 1, len, (FILE *)stream);
+}
+
+TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA,
+ double fixedPitchA, GBool rawOrderA,
+ GBool append) {
+ text = NULL;
+ physLayout = physLayoutA;
+ fixedPitch = physLayout ? fixedPitchA : 0;
+ rawOrder = rawOrderA;
+ doHTML = gFalse;
+ ok = gTrue;
+
+ // open file
+ needClose = gFalse;
+ if (fileName) {
+ if (!strcmp(fileName, "-")) {
+ outputStream = stdout;
+#ifdef _WIN32
+ // keep DOS from munging the end-of-line characters
+ setmode(fileno(stdout), O_BINARY);
+#endif
+ } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) {
+ needClose = gTrue;
+ } else {
+ error(errIO, -1, "Couldn't open text file '{0:s}'", fileName);
+ ok = gFalse;
+ actualText = NULL;
+ return;
+ }
+ outputFunc = &TextOutputDev_outputToFile;
+ } else {
+ outputStream = NULL;
+ }
+
+ // set up text object
+ text = new TextPage(rawOrderA);
+ actualText = new ActualText(text);
+}
+
+TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream,
+ GBool physLayoutA, double fixedPitchA,
+ GBool rawOrderA) {
+ outputFunc = func;
+ outputStream = stream;
+ needClose = gFalse;
+ physLayout = physLayoutA;
+ fixedPitch = physLayout ? fixedPitchA : 0;
+ rawOrder = rawOrderA;
+ doHTML = gFalse;
+ text = new TextPage(rawOrderA);
+ actualText = new ActualText(text);
+ ok = gTrue;
+}
+
+TextOutputDev::~TextOutputDev() {
+ if (needClose) {
+#ifdef MACOS
+ ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
+#endif
+ fclose((FILE *)outputStream);
+ }
+ if (text) {
+ text->decRefCnt();
+ }
+ delete actualText;
+}
+
+void TextOutputDev::startPage(int pageNum, GfxState *state, XRef *xref) {
+ text->startPage(state);
+}
+
+void TextOutputDev::endPage() {
+ text->endPage();
+ text->coalesce(physLayout, fixedPitch, doHTML);
+ if (outputStream) {
+ text->dump(outputStream, outputFunc, physLayout);
+ }
+}
+
+void TextOutputDev::restoreState(GfxState *state) {
+ text->updateFont(state);
+}
+
+void TextOutputDev::updateFont(GfxState *state) {
+ text->updateFont(state);
+}
+
+void TextOutputDev::beginString(GfxState *state, GooString *s) {
+}
+
+void TextOutputDev::endString(GfxState *state) {
+}
+
+void TextOutputDev::drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode c, int nBytes, Unicode *u, int uLen) {
+ actualText->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
+}
+
+void TextOutputDev::incCharCount(int nChars) {
+ text->incCharCount(nChars);
+}
+
+void TextOutputDev::beginActualText(GfxState *state, GooString *text)
+{
+ actualText->begin(state, text);
+}
+
+void TextOutputDev::endActualText(GfxState *state)
+{
+ actualText->end(state);
+}
+
+void TextOutputDev::stroke(GfxState *state) {
+ GfxPath *path;
+ GfxSubpath *subpath;
+ double x[2], y[2];
+
+ if (!doHTML) {
+ return;
+ }
+ path = state->getPath();
+ if (path->getNumSubpaths() != 1) {
+ return;
+ }
+ subpath = path->getSubpath(0);
+ if (subpath->getNumPoints() != 2) {
+ return;
+ }
+ state->transform(subpath->getX(0), subpath->getY(0), &x[0], &y[0]);
+ state->transform(subpath->getX(1), subpath->getY(1), &x[1], &y[1]);
+
+ // look for a vertical or horizontal line
+ if (x[0] == x[1] || y[0] == y[1]) {
+ text->addUnderline(x[0], y[0], x[1], y[1]);
+ }
+}
+
+void TextOutputDev::fill(GfxState *state) {
+ GfxPath *path;
+ GfxSubpath *subpath;
+ double x[5], y[5];
+ double rx0, ry0, rx1, ry1, t;
+ int i;
+
+ if (!doHTML) {
+ return;
+ }
+ path = state->getPath();
+ if (path->getNumSubpaths() != 1) {
+ return;
+ }
+ subpath = path->getSubpath(0);
+ if (subpath->getNumPoints() != 5) {
+ return;
+ }
+ for (i = 0; i < 5; ++i) {
+ if (subpath->getCurve(i)) {
+ return;
+ }
+ state->transform(subpath->getX(i), subpath->getY(i), &x[i], &y[i]);
+ }
+
+ // look for a rectangle
+ if (x[0] == x[1] && y[1] == y[2] && x[2] == x[3] && y[3] == y[4] &&
+ x[0] == x[4] && y[0] == y[4]) {
+ rx0 = x[0];
+ ry0 = y[0];
+ rx1 = x[2];
+ ry1 = y[1];
+ } else if (y[0] == y[1] && x[1] == x[2] && y[2] == y[3] && x[3] == x[4] &&
+ x[0] == x[4] && y[0] == y[4]) {
+ rx0 = x[0];
+ ry0 = y[0];
+ rx1 = x[1];
+ ry1 = y[2];
+ } else {
+ return;
+ }
+ if (rx1 < rx0) {
+ t = rx0;
+ rx0 = rx1;
+ rx1 = t;
+ }
+ if (ry1 < ry0) {
+ t = ry0;
+ ry0 = ry1;
+ ry1 = t;
+ }
+
+ // skinny horizontal rectangle
+ if (ry1 - ry0 < rx1 - rx0) {
+ if (ry1 - ry0 < maxUnderlineWidth) {
+ ry0 = 0.5 * (ry0 + ry1);
+ text->addUnderline(rx0, ry0, rx1, ry0);
+ }
+
+ // skinny vertical rectangle
+ } else {
+ if (rx1 - rx0 < maxUnderlineWidth) {
+ rx0 = 0.5 * (rx0 + rx1);
+ text->addUnderline(rx0, ry0, rx0, ry1);
+ }
+ }
+}
+
+void TextOutputDev::eoFill(GfxState *state) {
+ if (!doHTML) {
+ return;
+ }
+ fill(state);
+}
+
+void TextOutputDev::processLink(AnnotLink *link) {
+ double x1, y1, x2, y2;
+ int xMin, yMin, xMax, yMax, x, y;
+
+ if (!doHTML) {
+ return;
+ }
+ link->getRect(&x1, &y1, &x2, &y2);
+ cvtUserToDev(x1, y1, &x, &y);
+ xMin = xMax = x;
+ yMin = yMax = y;
+ cvtUserToDev(x1, y2, &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ cvtUserToDev(x2, y1, &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ cvtUserToDev(x2, y2, &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ text->addLink(xMin, yMin, xMax, yMax, link);
+}
+
+GBool TextOutputDev::findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ GBool wholeWord,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ return text->findText(s, len, startAtTop, stopAtBottom,
+ startAtLast, stopAtLast,
+ caseSensitive, backward, wholeWord,
+ xMin, yMin, xMax, yMax);
+}
+
+GooString *TextOutputDev::getText(double xMin, double yMin,
+ double xMax, double yMax) {
+ return text->getText(xMin, yMin, xMax, yMax);
+}
+
+void TextOutputDev::drawSelection(OutputDev *out,
+ double scale,
+ int rotation,
+ PDFRectangle *selection,
+ SelectionStyle style,
+ GfxColor *glyph_color, GfxColor *box_color) {
+ text->drawSelection(out, scale, rotation, selection, style, glyph_color, box_color);
+}
+
+GooList *TextOutputDev::getSelectionRegion(PDFRectangle *selection,
+ SelectionStyle style,
+ double scale) {
+ return text->getSelectionRegion(selection, style, scale);
+}
+
+GooString *TextOutputDev::getSelectionText(PDFRectangle *selection,
+ SelectionStyle style)
+{
+ return text->getSelectionText(selection, style);
+}
+
+GBool TextOutputDev::findCharRange(int pos, int length,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ return text->findCharRange(pos, length, xMin, yMin, xMax, yMax);
+}
+
+void TextOutputDev::setMergeCombining(GBool merge) {
+ text->setMergeCombining(merge);
+}
+
+#if TEXTOUT_WORD_LIST
+TextWordList *TextOutputDev::makeWordList() {
+ return text->makeWordList(physLayout);
+}
+#endif
+
+TextPage *TextOutputDev::takeText() {
+ TextPage *ret;
+
+ ret = text;
+ text = new TextPage(rawOrder);
+ return ret;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/TextOutputDev.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/TextOutputDev.h
new file mode 100644
index 00000000000..2aab94f5d15
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/TextOutputDev.h
@@ -0,0 +1,880 @@
+//========================================================================
+//
+// TextOutputDev.h
+//
+// Copyright 1997-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005-2007 Kristian Høgsberg <krh@redhat.com>
+// Copyright (C) 2006 Ed Catmur <ed@catmur.co.uk>
+// Copyright (C) 2007, 2008, 2011, 2013 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2007 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2008, 2010, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Brian Ewins <brian.ewins@gmail.com>
+// Copyright (C) 2012, 2013, 2015 Jason Crain <jason@aquaticape.us>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef TEXTOUTPUTDEV_H
+#define TEXTOUTPUTDEV_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include <stdio.h>
+#include "goo/gtypes.h"
+#include "GfxFont.h"
+#include "GfxState.h"
+#include "OutputDev.h"
+
+class GooString;
+class GooList;
+class Gfx;
+class GfxFont;
+class GfxState;
+class UnicodeMap;
+class AnnotLink;
+
+class TextWord;
+class TextPool;
+class TextLine;
+class TextLineFrag;
+class TextBlock;
+class TextFlow;
+class TextWordList;
+class TextPage;
+class TextSelectionVisitor;
+
+//------------------------------------------------------------------------
+
+typedef void (*TextOutputFunc)(void *stream, const char *text, int len);
+
+enum SelectionStyle {
+ selectionStyleGlyph,
+ selectionStyleWord,
+ selectionStyleLine
+};
+
+//------------------------------------------------------------------------
+// TextFontInfo
+//------------------------------------------------------------------------
+
+class TextFontInfo {
+public:
+
+ TextFontInfo(GfxState *state);
+ ~TextFontInfo();
+
+ GBool matches(GfxState *state);
+ GBool matches(TextFontInfo *fontInfo);
+
+ // Get the font ascent, or a default value if the font is not set
+ double getAscent();
+
+ // Get the font descent, or a default value if the font is not set
+ double getDescent();
+
+ // Get the writing mode (0 or 1), or 0 if the font is not set
+ int getWMode();
+
+#if TEXTOUT_WORD_LIST
+ // Get the font name (which may be NULL).
+ GooString *getFontName() { return fontName; }
+
+ // Get font descriptor flags.
+ GBool isFixedWidth() { return flags & fontFixedWidth; }
+ GBool isSerif() { return flags & fontSerif; }
+ GBool isSymbolic() { return flags & fontSymbolic; }
+ GBool isItalic() { return flags & fontItalic; }
+ GBool isBold() { return flags & fontBold; }
+#endif
+
+private:
+
+ GfxFont *gfxFont;
+#if TEXTOUT_WORD_LIST
+ GooString *fontName;
+ int flags;
+#endif
+
+ friend class TextWord;
+ friend class TextPage;
+ friend class TextSelectionPainter;
+};
+
+//------------------------------------------------------------------------
+// TextWord
+//------------------------------------------------------------------------
+
+class TextWord {
+public:
+
+ // Constructor.
+ TextWord(GfxState *state, int rotA, double fontSize);
+
+ // Destructor.
+ ~TextWord();
+
+ // Add a character to the word.
+ void addChar(GfxState *state, TextFontInfo *fontA, double x, double y,
+ double dx, double dy, int charPosA, int charLen,
+ CharCode c, Unicode u, const Matrix &textMatA);
+
+ // Attempt to add a character to the word as a combining character.
+ // Either character u or the last character in the word must be an
+ // acute, dieresis, or other combining character. Returns true if
+ // the character was added.
+ GBool addCombining(GfxState *state, TextFontInfo *fontA, double fontSizeA, double x, double y,
+ double dx, double dy, int charPosA, int charLen,
+ CharCode c, Unicode u, const Matrix &textMatA);
+
+ // Merge <word> onto the end of <this>.
+ void merge(TextWord *word);
+
+ // Compares <this> to <word>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a primary-axis comparison, e.g., x ordering if rot=0.
+ int primaryCmp(TextWord *word);
+
+ // Return the distance along the primary axis between <this> and
+ // <word>.
+ double primaryDelta(TextWord *word);
+
+ static int cmpYX(const void *p1, const void *p2);
+
+ void visitSelection(TextSelectionVisitor *visitor,
+ PDFRectangle *selection,
+ SelectionStyle style);
+
+ // Get the TextFontInfo object associated with a character.
+ TextFontInfo *getFontInfo(int idx) { return font[idx]; }
+
+ // Get the next TextWord on the linked list.
+ TextWord *getNext() { return next; }
+
+#if TEXTOUT_WORD_LIST
+ int getLength() { return len; }
+ const Unicode *getChar(int idx) { return &text[idx]; }
+ GooString *getText();
+ GooString *getFontName(int idx) { return font[idx]->fontName; }
+ void getColor(double *r, double *g, double *b)
+ { *r = colorR; *g = colorG; *b = colorB; }
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ void getCharBBox(int charIdx, double *xMinA, double *yMinA,
+ double *xMaxA, double *yMaxA);
+ double getFontSize() { return fontSize; }
+ int getRotation() { return rot; }
+ int getCharPos() { return charPos[0]; }
+ int getCharLen() { return charPos[len] - charPos[0]; }
+ GBool getSpaceAfter() { return spaceAfter; }
+#endif
+ GBool isUnderlined() { return underlined; }
+ AnnotLink *getLink() { return link; }
+ double getEdge(int i) { return edge[i]; }
+ double getBaseline () { return base; }
+ GBool hasSpaceAfter () { return spaceAfter; }
+ TextWord* nextWord () { return next; };
+private:
+ void ensureCapacity(int capacity);
+ void setInitialBounds(TextFontInfo *fontA, double x, double y);
+
+ int rot; // rotation, multiple of 90 degrees
+ // (0, 1, 2, or 3)
+ double xMin, xMax; // bounding box x coordinates
+ double yMin, yMax; // bounding box y coordinates
+ double base; // baseline x or y coordinate
+ Unicode *text; // the text
+ CharCode *charcode; // glyph indices
+ double *edge; // "near" edge x or y coord of each char
+ // (plus one extra entry for the last char)
+ int *charPos; // character position (within content stream)
+ // of each char (plus one extra entry for
+ // the last char)
+ int len; // length of text/edge/charPos/font arrays
+ int size; // size of text/edge/charPos/font arrays
+ TextFontInfo **font; // font information for each char
+ Matrix *textMat; // transformation matrix for each char
+ double fontSize; // font size
+ GBool spaceAfter; // set if there is a space between this
+ // word and the next word on the line
+ TextWord *next; // next word in line
+ int wMode; // horizontal (0) or vertical (1) writing mode
+
+#if TEXTOUT_WORD_LIST
+ double colorR, // word color
+ colorG,
+ colorB;
+#endif
+
+ GBool underlined;
+ AnnotLink *link;
+
+ friend class TextPool;
+ friend class TextLine;
+ friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
+ friend class TextPage;
+
+ friend class TextSelectionPainter;
+ friend class TextSelectionDumper;
+};
+
+//------------------------------------------------------------------------
+// TextPool
+//------------------------------------------------------------------------
+
+class TextPool {
+public:
+
+ TextPool();
+ ~TextPool();
+
+ TextWord *getPool(int baseIdx) { return pool[baseIdx - minBaseIdx]; }
+ void setPool(int baseIdx, TextWord *p) { pool[baseIdx - minBaseIdx] = p; }
+
+ int getBaseIdx(double base);
+
+ void addWord(TextWord *word);
+
+private:
+
+ int minBaseIdx; // min baseline bucket index
+ int maxBaseIdx; // max baseline bucket index
+ TextWord **pool; // array of linked lists, one for each
+ // baseline value (multiple of 4 pts)
+ TextWord *cursor; // pointer to last-accessed word
+ int cursorBaseIdx; // baseline bucket index of last-accessed word
+
+ friend class TextBlock;
+ friend class TextPage;
+};
+
+struct TextFlowData;
+
+//------------------------------------------------------------------------
+// TextLine
+//------------------------------------------------------------------------
+
+class TextLine {
+public:
+
+ TextLine(TextBlock *blkA, int rotA, double baseA);
+ ~TextLine();
+
+ void addWord(TextWord *word);
+
+ // Return the distance along the primary axis between <this> and
+ // <line>.
+ double primaryDelta(TextLine *line);
+
+ // Compares <this> to <line>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a primary-axis comparison, e.g., x ordering if rot=0.
+ int primaryCmp(TextLine *line);
+
+ // Compares <this> to <line>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a secondary-axis comparison of the baselines, e.g., y
+ // ordering if rot=0.
+ int secondaryCmp(TextLine *line);
+
+ int cmpYX(TextLine *line);
+
+ static int cmpXY(const void *p1, const void *p2);
+
+ void coalesce(UnicodeMap *uMap);
+
+ void visitSelection(TextSelectionVisitor *visitor,
+ PDFRectangle *selection,
+ SelectionStyle style);
+
+ // Get the head of the linked list of TextWords.
+ TextWord *getWords() { return words; }
+
+ // Get the next TextLine on the linked list.
+ TextLine *getNext() { return next; }
+
+ // Returns true if the last char of the line is a hyphen.
+ GBool isHyphenated() { return hyphenated; }
+
+private:
+
+ TextBlock *blk; // parent block
+ int rot; // text rotation
+ double xMin, xMax; // bounding box x coordinates
+ double yMin, yMax; // bounding box y coordinates
+ double base; // baseline x or y coordinate
+ TextWord *words; // words in this line
+ TextWord *lastWord; // last word in this line
+ Unicode *text; // Unicode text of the line, including
+ // spaces between words
+ double *edge; // "near" edge x or y coord of each char
+ // (plus one extra entry for the last char)
+ int *col; // starting column number of each Unicode char
+ int len; // number of Unicode chars
+ int convertedLen; // total number of converted characters
+ GBool hyphenated; // set if last char is a hyphen
+ TextLine *next; // next line in block
+ Unicode *normalized; // normalized form of Unicode text
+ int normalized_len; // number of normalized Unicode chars
+ int *normalized_idx; // indices of normalized chars into Unicode text
+
+ friend class TextLineFrag;
+ friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
+ friend class TextPage;
+
+ friend class TextSelectionPainter;
+ friend class TextSelectionSizer;
+ friend class TextSelectionDumper;
+};
+
+//------------------------------------------------------------------------
+// TextBlock
+//------------------------------------------------------------------------
+
+class TextBlock {
+public:
+
+ TextBlock(TextPage *pageA, int rotA);
+ ~TextBlock();
+
+ void addWord(TextWord *word);
+
+ void coalesce(UnicodeMap *uMap, double fixedPitch);
+
+ // Update this block's priMin and priMax values, looking at <blk>.
+ void updatePriMinMax(TextBlock *blk);
+
+ static int cmpXYPrimaryRot(const void *p1, const void *p2);
+
+ static int cmpYXPrimaryRot(const void *p1, const void *p2);
+
+ int primaryCmp(TextBlock *blk);
+
+ double secondaryDelta(TextBlock *blk);
+
+ // Returns true if <this> is below <blk>, relative to the page's
+ // primary rotation.
+ GBool isBelow(TextBlock *blk);
+
+ void visitSelection(TextSelectionVisitor *visitor,
+ PDFRectangle *selection,
+ SelectionStyle style);
+
+ // Get the head of the linked list of TextLines.
+ TextLine *getLines() { return lines; }
+
+ // Get the next TextBlock on the linked list.
+ TextBlock *getNext() { return next; }
+
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+
+ int getLineCount() { return nLines; }
+
+private:
+
+ GBool isBeforeByRule1(TextBlock *blk1);
+ GBool isBeforeByRepeatedRule1(TextBlock *blkList, TextBlock *blk1);
+ GBool isBeforeByRule2(TextBlock *blk1);
+
+ int visitDepthFirst(TextBlock *blkList, int pos1,
+ TextBlock **sorted, int sortPos,
+ GBool* visited);
+
+ TextPage *page; // the parent page
+ int rot; // text rotation
+ double xMin, xMax; // bounding box x coordinates
+ double yMin, yMax; // bounding box y coordinates
+ double priMin, priMax; // whitespace bounding box along primary axis
+ double ExMin, ExMax; // extended bounding box x coordinates
+ double EyMin, EyMax; // extended bounding box y coordinates
+ int tableId; // id of table to which this block belongs
+ GBool tableEnd; // is this block at end of line of actual table
+
+ TextPool *pool; // pool of words (used only until lines
+ // are built)
+ TextLine *lines; // linked list of lines
+ TextLine *curLine; // most recently added line
+ int nLines; // number of lines
+ int charCount; // number of characters in the block
+ int col; // starting column
+ int nColumns; // number of columns in the block
+
+ TextBlock *next;
+ TextBlock *stackNext;
+
+ friend class TextLine;
+ friend class TextLineFrag;
+ friend class TextFlow;
+ friend class TextWordList;
+ friend class TextPage;
+ friend class TextSelectionPainter;
+ friend class TextSelectionDumper;
+};
+
+//------------------------------------------------------------------------
+// TextFlow
+//------------------------------------------------------------------------
+
+class TextFlow {
+public:
+
+ TextFlow(TextPage *pageA, TextBlock *blk);
+ ~TextFlow();
+
+ // Add a block to the end of this flow.
+ void addBlock(TextBlock *blk);
+
+ // Returns true if <blk> fits below <prevBlk> in the flow, i.e., (1)
+ // it uses a font no larger than the last block added to the flow,
+ // and (2) it fits within the flow's [priMin, priMax] along the
+ // primary axis.
+ GBool blockFits(TextBlock *blk, TextBlock *prevBlk);
+
+ // Get the head of the linked list of TextBlocks.
+ TextBlock *getBlocks() { return blocks; }
+
+ // Get the next TextFlow on the linked list.
+ TextFlow *getNext() { return next; }
+
+private:
+
+ TextPage *page; // the parent page
+ double xMin, xMax; // bounding box x coordinates
+ double yMin, yMax; // bounding box y coordinates
+ double priMin, priMax; // whitespace bounding box along primary axis
+ TextBlock *blocks; // blocks in flow
+ TextBlock *lastBlk; // last block in this flow
+ TextFlow *next;
+
+ friend class TextWordList;
+ friend class TextPage;
+};
+
+#if TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextWordList
+//------------------------------------------------------------------------
+
+class TextWordList {
+public:
+
+ // Build a flat word list, in content stream order (if
+ // text->rawOrder is true), physical layout order (if <physLayout>
+ // is true and text->rawOrder is false), or reading order (if both
+ // flags are false).
+ TextWordList(TextPage *text, GBool physLayout);
+
+ ~TextWordList();
+
+ // Return the number of words on the list.
+ int getLength();
+
+ // Return the <idx>th word from the list.
+ TextWord *get(int idx);
+
+private:
+
+ GooList *words; // [TextWord]
+};
+
+#endif // TEXTOUT_WORD_LIST
+
+class TextWordSelection {
+public:
+ TextWordSelection(TextWord *word, int begin, int end)
+ : word(word), begin(begin), end(end)
+ {
+ }
+
+ TextWord * getWord() const { return word; }
+ int getBegin() const { return begin; }
+ int getEnd() const { return end; }
+
+private:
+ TextWord *word;
+ int begin;
+ int end;
+
+ friend class TextSelectionPainter;
+ friend class TextSelectionDumper;
+};
+
+//------------------------------------------------------------------------
+// TextPage
+//------------------------------------------------------------------------
+
+class TextPage {
+public:
+
+ // Constructor.
+ TextPage(GBool rawOrderA);
+
+ void incRefCnt();
+ void decRefCnt();
+
+ // Start a new page.
+ void startPage(GfxState *state);
+
+ // End the current page.
+ void endPage();
+
+ // Update the current font.
+ void updateFont(GfxState *state);
+
+ // Begin a new word.
+ void beginWord(GfxState *state);
+
+ // Add a character to the current word.
+ void addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+
+ // Add <nChars> invisible characters.
+ void incCharCount(int nChars);
+
+ // End the current word, sorting it into the list of words.
+ void endWord();
+
+ // Add a word, sorting it into the list of words.
+ void addWord(TextWord *word);
+
+ // Add a (potential) underline.
+ void addUnderline(double x0, double y0, double x1, double y1);
+
+ // Add a hyperlink.
+ void addLink(int xMin, int yMin, int xMax, int yMax, AnnotLink *link);
+
+ // Coalesce strings that look like parts of the same line.
+ void coalesce(GBool physLayout, double fixedPitch, GBool doHTML);
+
+ // Find a string. If <startAtTop> is true, starts looking at the
+ // top of the page; else if <startAtLast> is true, starts looking
+ // immediately after the last find result; else starts looking at
+ // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the
+ // bottom of the page; else if <stopAtLast> is true, stops looking
+ // just before the last find result; else stops looking at
+ // <xMax>,<yMax>.
+ GBool findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ GBool wholeWord,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+ // Get the text which is inside the specified rectangle.
+ GooString *getText(double xMin, double yMin,
+ double xMax, double yMax);
+
+ void visitSelection(TextSelectionVisitor *visitor,
+ PDFRectangle *selection,
+ SelectionStyle style);
+
+ void drawSelection(OutputDev *out,
+ double scale,
+ int rotation,
+ PDFRectangle *selection,
+ SelectionStyle style,
+ GfxColor *glyph_color, GfxColor *box_color);
+
+ GooList *getSelectionRegion(PDFRectangle *selection,
+ SelectionStyle style,
+ double scale);
+
+ GooString *getSelectionText(PDFRectangle *selection,
+ SelectionStyle style);
+
+ GooList **getSelectionWords(PDFRectangle *selection,
+ SelectionStyle style,
+ int *nLines);
+
+ // Find a string by character position and length. If found, sets
+ // the text bounding rectangle and returns true; otherwise returns
+ // false.
+ GBool findCharRange(int pos, int length,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+ // Dump contents of page to a file.
+ void dump(void *outputStream, TextOutputFunc outputFunc,
+ GBool physLayout);
+
+ // Get the head of the linked list of TextFlows.
+ TextFlow *getFlows() { return flows; }
+
+ // If true, will combine characters when a base and combining
+ // character are drawn on eachother.
+ void setMergeCombining(GBool merge);
+
+#if TEXTOUT_WORD_LIST
+ // Build a flat word list, in content stream order (if
+ // this->rawOrder is true), physical layout order (if <physLayout>
+ // is true and this->rawOrder is false), or reading order (if both
+ // flags are false).
+ TextWordList *makeWordList(GBool physLayout);
+#endif
+
+private:
+
+ // Destructor.
+ ~TextPage();
+
+ void clear();
+ void assignColumns(TextLineFrag *frags, int nFrags, GBool rot);
+ int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GooString *s);
+
+ GBool rawOrder; // keep text in content stream order
+ GBool mergeCombining; // merge when combining and base characters
+ // are drawn on top of each other
+
+ double pageWidth, pageHeight; // width and height of current page
+ TextWord *curWord; // currently active string
+ int charPos; // next character position (within content
+ // stream)
+ TextFontInfo *curFont; // current font
+ double curFontSize; // current font size
+ int nest; // current nesting level (for Type 3 fonts)
+ int nTinyChars; // number of "tiny" chars seen so far
+ GBool lastCharOverlap; // set if the last added char overlapped the
+ // previous char
+
+ TextPool *pools[4]; // a "pool" of TextWords for each rotation
+ TextFlow *flows; // linked list of flows
+ TextBlock **blocks; // array of blocks, in yx order
+ int nBlocks; // number of blocks
+ int primaryRot; // primary rotation
+ GBool primaryLR; // primary direction (true means L-to-R,
+ // false means R-to-L)
+ TextWord *rawWords; // list of words, in raw order (only if
+ // rawOrder is set)
+ TextWord *rawLastWord; // last word on rawWords list
+
+ GooList *fonts; // all font info objects used on this
+ // page [TextFontInfo]
+
+ double lastFindXMin, // coordinates of the last "find" result
+ lastFindYMin;
+ GBool haveLastFind;
+
+ GooList *underlines; // [TextUnderline]
+ GooList *links; // [TextLink]
+
+ int refCnt;
+
+ friend class TextLine;
+ friend class TextLineFrag;
+ friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
+ friend class TextSelectionPainter;
+ friend class TextSelectionDumper;
+};
+
+//------------------------------------------------------------------------
+// ActualText
+//------------------------------------------------------------------------
+
+class ActualText {
+public:
+ // Create an ActualText
+ ActualText(TextPage *out);
+ ~ActualText();
+
+ void addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+ void begin(GfxState *state, GooString *text);
+ void end(GfxState *state);
+
+private:
+ TextPage *text;
+
+ GooString *actualText; // replacement text for the span
+ double actualTextX0;
+ double actualTextY0;
+ double actualTextX1;
+ double actualTextY1;
+ int actualTextNBytes;
+};
+
+
+//------------------------------------------------------------------------
+// TextOutputDev
+//------------------------------------------------------------------------
+
+class TextOutputDev: public OutputDev {
+public:
+
+ // Open a text output file. If <fileName> is NULL, no file is
+ // written (this is useful, e.g., for searching text). If
+ // <physLayoutA> is true, the original physical layout of the text
+ // is maintained. If <rawOrder> is true, the text is kept in
+ // content stream order.
+ TextOutputDev(char *fileName, GBool physLayoutA,
+ double fixedPitchA, GBool rawOrderA,
+ GBool append);
+
+ // Create a TextOutputDev which will write to a generic stream. If
+ // <physLayoutA> is true, the original physical layout of the text
+ // is maintained. If <rawOrder> is true, the text is kept in
+ // content stream order.
+ TextOutputDev(TextOutputFunc func, void *stream,
+ GBool physLayoutA, double fixedPitchA,
+ GBool rawOrderA);
+
+ // Destructor.
+ virtual ~TextOutputDev();
+
+ // Check if file was successfully created.
+ virtual GBool isOk() { return ok; }
+
+ //---- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gTrue; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gFalse; }
+
+ // Does this device need non-text content?
+ virtual GBool needNonText() { return gFalse; }
+
+ // Does this device require incCharCount to be called for text on
+ // non-shown layers?
+ virtual GBool needCharCount() { return gTrue; }
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state, XRef *xref);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- save/restore graphics state
+ virtual void restoreState(GfxState *state);
+
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+
+ //----- text drawing
+ virtual void beginString(GfxState *state, GooString *s);
+ virtual void endString(GfxState *state);
+ virtual void drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+ virtual void incCharCount(int nChars);
+ virtual void beginActualText(GfxState *state, GooString *text);
+ virtual void endActualText(GfxState *state);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+
+ //----- link borders
+ virtual void processLink(AnnotLink *link);
+
+ //----- special access
+
+ // Find a string. If <startAtTop> is true, starts looking at the
+ // top of the page; else if <startAtLast> is true, starts looking
+ // immediately after the last find result; else starts looking at
+ // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the
+ // bottom of the page; else if <stopAtLast> is true, stops looking
+ // just before the last find result; else stops looking at
+ // <xMax>,<yMax>.
+ GBool findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ GBool wholeWord,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+ // Get the text which is inside the specified rectangle.
+ GooString *getText(double xMin, double yMin,
+ double xMax, double yMax);
+
+ // Find a string by character position and length. If found, sets
+ // the text bounding rectangle and returns true; otherwise returns
+ // false.
+ GBool findCharRange(int pos, int length,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+ void drawSelection(OutputDev *out, double scale, int rotation,
+ PDFRectangle *selection,
+ SelectionStyle style,
+ GfxColor *glyph_color, GfxColor *box_color);
+
+ GooList *getSelectionRegion(PDFRectangle *selection,
+ SelectionStyle style,
+ double scale);
+
+ GooString *getSelectionText(PDFRectangle *selection,
+ SelectionStyle style);
+
+ // If true, will combine characters when a base and combining
+ // character are drawn on eachother.
+ void setMergeCombining(GBool merge);
+
+#if TEXTOUT_WORD_LIST
+ // Build a flat word list, in content stream order (if
+ // this->rawOrder is true), physical layout order (if
+ // this->physLayout is true and this->rawOrder is false), or reading
+ // order (if both flags are false).
+ TextWordList *makeWordList();
+#endif
+
+ // Returns the TextPage object for the last rasterized page,
+ // transferring ownership to the caller.
+ TextPage *takeText();
+
+ // Turn extra processing for HTML conversion on or off.
+ void enableHTMLExtras(GBool doHTMLA) { doHTML = doHTMLA; }
+
+private:
+
+ TextOutputFunc outputFunc; // output function
+ void *outputStream; // output stream
+ GBool needClose; // need to close the output file?
+ // (only if outputStream is a FILE*)
+ TextPage *text; // text for the current page
+ GBool physLayout; // maintain original physical layout when
+ // dumping text
+ double fixedPitch; // if physLayout is true and this is non-zero,
+ // assume fixed-pitch characters with this
+ // width
+ GBool rawOrder; // keep text in content stream order
+ GBool doHTML; // extra processing for HTML conversion
+ GBool ok; // set up ok?
+
+ ActualText *actualText;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF.cc
new file mode 100644
index 00000000000..46007b73006
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF.cc
@@ -0,0 +1,116 @@
+//========================================================================
+//
+// UTF.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include "goo/gmem.h"
+#include "PDFDocEncoding.h"
+#include "UTF.h"
+
+bool UnicodeIsValid(Unicode ucs4)
+{
+ return (ucs4 < 0x110000) &&
+ ((ucs4 & 0xfffff800) != 0xd800) &&
+ (ucs4 < 0xfdd0 || ucs4 > 0xfdef) &&
+ ((ucs4 & 0xfffe) != 0xfffe);
+}
+
+int UTF16toUCS4(const Unicode *utf16, int utf16Len, Unicode **ucs4)
+{
+ int i, n, len;
+ Unicode *u;
+
+ // count characters
+ len = 0;
+ for (i = 0; i < utf16Len; i++) {
+ if (utf16[i] >= 0xd800 && utf16[i] < 0xdc00 && i + 1 < utf16Len &&
+ utf16[i+1] >= 0xdc00 && utf16[i+1] < 0xe000) {
+ i++; /* surrogate pair */
+ }
+ len++;
+ }
+ if (ucs4 == NULL)
+ return len;
+
+ u = (Unicode*)gmallocn(len, sizeof(Unicode));
+ n = 0;
+ // convert string
+ for (i = 0; i < utf16Len; i++) {
+ if (utf16[i] >= 0xd800 && utf16[i] < 0xdc00) { /* surrogate pair */
+ if (i + 1 < utf16Len && utf16[i+1] >= 0xdc00 && utf16[i+1] < 0xe000) {
+ /* next code is a low surrogate */
+ u[n] = (((utf16[i] & 0x3ff) << 10) | (utf16[i+1] & 0x3ff)) + 0x10000;
+ ++i;
+ } else {
+ /* missing low surrogate
+ replace it with REPLACEMENT CHARACTER (U+FFFD) */
+ u[n] = 0xfffd;
+ }
+ } else if (utf16[i] >= 0xdc00 && utf16[i] < 0xe000) {
+ /* invalid low surrogate
+ replace it with REPLACEMENT CHARACTER (U+FFFD) */
+ u[n] = 0xfffd;
+ } else {
+ u[n] = utf16[i];
+ }
+ if (!UnicodeIsValid(u[n])) {
+ u[n] = 0xfffd;
+ }
+ n++;
+ }
+ *ucs4 = u;
+ return len;
+}
+
+int TextStringToUCS4(GooString *textStr, Unicode **ucs4)
+{
+ int i, len;
+ const char *s;
+ Unicode *u;
+
+ len = textStr->getLength();
+ s = textStr->getCString();
+ if (len == 0)
+ return 0;
+
+ if (textStr->hasUnicodeMarker()) {
+ Unicode *utf16;
+ len = len/2 - 1;
+ if (len > 0) {
+ utf16 = new Unicode[len];
+ for (i = 0 ; i < len; i++) {
+ utf16[i] = (s[2 + i*2] & 0xff) << 8 | (s[3 + i*2] & 0xff);
+ }
+ len = UTF16toUCS4(utf16, len, &u);
+ delete[] utf16;
+ } else {
+ u = NULL;
+ }
+ } else {
+ u = (Unicode*)gmallocn(len, sizeof(Unicode));
+ for (i = 0 ; i < len; i++) {
+ u[i] = pdfDocEncoding[s[i] & 0xff];
+ }
+ }
+ *ucs4 = u;
+ return len;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF.h
new file mode 100644
index 00000000000..248c168cca5
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF.h
@@ -0,0 +1,39 @@
+//========================================================================
+//
+// UTF.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+//
+//========================================================================
+
+#ifndef UTF_H
+#define UTF_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "goo/GooString.h"
+#include "CharTypes.h"
+
+// Convert a UTF-16 string to a UCS-4
+// utf16 - utf16 bytes
+// utf16_len - number of UTF-16 characters
+// ucs4_out - if not NULL, allocates and returns UCS-4 string. Free with gfree.
+// returns number of UCS-4 characters
+int UTF16toUCS4(const Unicode *utf16, int utf16_len, Unicode **ucs4_out);
+
+// Convert a PDF Text String to UCS-4
+// s - PDF text string
+// ucs4 - if the number of UCS-4 characters is > 0, allocates and
+// returns UCS-4 string. Free with gfree.
+// returns number of UCS-4 characters
+int TextStringToUCS4(GooString *textStr, Unicode **ucs4);
+
+// check if UCS-4 character is valid
+bool UnicodeIsValid(Unicode ucs4);
+
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF8.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF8.h
new file mode 100644
index 00000000000..34a07d4082f
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UTF8.h
@@ -0,0 +1,84 @@
+//========================================================================
+//
+// UTF8.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Koji Otani <sho@bbr.jp>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+static int mapUTF8(Unicode u, char *buf, int bufSize) {
+ if (u <= 0x0000007f) {
+ if (bufSize < 1) {
+ return 0;
+ }
+ buf[0] = (char)u;
+ return 1;
+ } else if (u <= 0x000007ff) {
+ if (bufSize < 2) {
+ return 0;
+ }
+ buf[0] = (char)(0xc0 + (u >> 6));
+ buf[1] = (char)(0x80 + (u & 0x3f));
+ return 2;
+ } else if (u <= 0x0000ffff) {
+ if (bufSize < 3) {
+ return 0;
+ }
+ buf[0] = (char)(0xe0 + (u >> 12));
+ buf[1] = (char)(0x80 + ((u >> 6) & 0x3f));
+ buf[2] = (char)(0x80 + (u & 0x3f));
+ return 3;
+ } else if (u <= 0x0010ffff) {
+ if (bufSize < 4) {
+ return 0;
+ }
+ buf[0] = (char)(0xf0 + (u >> 18));
+ buf[1] = (char)(0x80 + ((u >> 12) & 0x3f));
+ buf[2] = (char)(0x80 + ((u >> 6) & 0x3f));
+ buf[3] = (char)(0x80 + (u & 0x3f));
+ return 4;
+ } else {
+ return 0;
+ }
+}
+
+static int mapUCS2(Unicode u, char *buf, int bufSize) {
+ if (u <= 0xffff) {
+ if (bufSize < 2) {
+ return 0;
+ }
+ buf[0] = (char)((u >> 8) & 0xff);
+ buf[1] = (char)(u & 0xff);
+ return 2;
+ } else if (u < 0x110000) {
+ Unicode uu;
+
+ /* using surrogate pair */
+ if (bufSize < 4) {
+ return 0;
+ }
+ uu = ((u - 0x10000) >> 10) + 0xd800;
+ buf[0] = (char)((uu >> 8) & 0xff);
+ buf[1] = (char)(uu & 0xff);
+ uu = (u & 0x3ff)+0xdc00;
+ buf[2] = (char)((uu >> 8) & 0xff);
+ buf[3] = (char)(uu & 0xff);
+ return 4;
+ } else {
+ return 0;
+ }
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeCClassTables.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeCClassTables.h
new file mode 100644
index 00000000000..62f9ecc3657
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeCClassTables.h
@@ -0,0 +1,1827 @@
+// Copied from gunidecomp.h in GLib:
+// s/[G]_UNICODE_MAX_TABLE_INDEX/UNICODE_MAX_TABLE_INDEX/g
+// s/[g]uchar/Unicode/g
+// s/[g]int16/short/g
+// Can be regenerated from gen-unicode-tables.pl, also in GLib, with relevant
+// Unicode data tables from ftp.unicode.org.
+
+static const Unicode cclass_data[][256] = {
+ { /* page 3, index 0 */
+ 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
+ 230, 230, 230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216,
+ 220, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 202, 202, 220,
+ 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 1, 1, 1, 1, 1, 220,
+ 220, 220, 220, 230, 230, 230, 230, 230, 230, 230, 230, 240, 230, 220,
+ 220, 220, 230, 230, 230, 220, 220, 0, 230, 230, 230, 220, 220, 220, 220,
+ 230, 0, 0, 0, 0, 0, 234, 234, 233, 234, 234, 233, 230, 230, 230, 230,
+ 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 4, index 1 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 5, index 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 220, 230, 230, 230, 230, 220, 230, 230, 230, 222, 220, 230, 230, 230,
+ 230, 230, 230, 0, 220, 220, 220, 220, 220, 230, 230, 220, 230, 230, 222,
+ 228, 230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 20, 21, 22, 0, 23,
+ 0, 24, 25, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 6, index 3 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230,
+ 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34, 230, 230, 220, 220,
+ 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230,
+ 230, 230, 230, 220, 230, 0, 0, 230, 230, 0, 220, 230, 230, 220, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 7, index 4 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220, 220, 230,
+ 220, 230, 230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 9, index 5 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 9, 0, 0, 0, 230, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 10, index 6 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 11, index 7 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 12, index 8 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 13, index 9 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 14, index 10 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 107, 107, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 122, 122, 122, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 15, index 11 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 130, 0,
+ 132, 0, 0, 0, 0, 0, 130, 130, 130, 130, 0, 0, 130, 0, 230, 230, 9, 0,
+ 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0
+ },
+ { /* page 16, index 12 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 23, index 13 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 24, index 14 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 25, index 15 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 32, index 16 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 1, 1, 230, 230,
+ 230, 230, 1, 1, 1, 230, 230, 0, 0, 0, 0, 230, 0, 0, 0, 1, 1, 230, 220,
+ 230, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 48, index 17 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 228, 232, 222,
+ 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 251, index 18 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 254, index 19 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 465, index 20 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 216, 216, 1, 1, 1, 0, 0, 0, 226, 216, 216, 216, 216, 216,
+ 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220, 220, 220, 220, 0, 0,
+ 230, 230, 230, 230, 230, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }
+};
+
+static const short combining_class_table_part1[763] = {
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 /* page 3 */,
+ 1 /* page 4 */,
+ 2 /* page 5 */,
+ 3 /* page 6 */,
+ 4 /* page 7 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 5 /* page 9 */,
+ 6 /* page 10 */,
+ 7 /* page 11 */,
+ 8 /* page 12 */,
+ 9 /* page 13 */,
+ 10 /* page 14 */,
+ 11 /* page 15 */,
+ 12 /* page 16 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 13 /* page 23 */,
+ 14 /* page 24 */,
+ 15 /* page 25 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 16 /* page 32 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 17 /* page 48 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 18 /* page 251 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 19 /* page 254 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 20 /* page 465 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX
+};
+
+static const short combining_class_table_part2[768] = {
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX
+};
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeCompTables.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeCompTables.h
new file mode 100644
index 00000000000..68e2f86aee9
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeCompTables.h
@@ -0,0 +1,665 @@
+// Copied from gunicomp.h in GLib:
+// s/[G]_UNICODE_MAX_TABLE_INDEX/UNICODE_MAX_TABLE_INDEX/g
+// s/[g]uint16/unsigned short/g
+// s/[g]int16/short/g
+// Can be regenerated from gen-unicode-tables.pl, also in GLib, with relevant
+// Unicode data tables from ftp.unicode.org.
+
+#define COMPOSE_FIRST_START 1
+#define COMPOSE_FIRST_SINGLE_START 147
+#define COMPOSE_SECOND_START 357
+#define COMPOSE_SECOND_SINGLE_START 388
+
+#define COMPOSE_TABLE_LAST 48
+
+static const unsigned short compose_data[][256] = {
+ { /* page 0, index 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 148, 149, 0, 0, 1, 2, 3, 4, 5,
+ 150, 6, 7, 8, 151, 9, 10, 11, 12, 13, 14, 0, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 0, 0, 0, 0, 0, 0, 24, 25, 26, 27, 28, 152, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 0, 39, 40, 41, 42, 43, 44, 45, 46, 47, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 153, 154,
+ 50, 155, 0, 0, 51, 0, 0, 0, 0, 156, 0, 0, 0, 0, 52, 53, 157, 0, 158, 0,
+ 0, 0, 54, 0, 0, 0, 0, 0, 55, 0, 159, 160, 56, 161, 0, 0, 57, 0, 0, 0, 0,
+ 162, 0, 0, 0, 0, 58, 59, 163, 0, 164, 0, 0, 0, 60, 0, 0, 0
+ },
+ { /* page 1, index 1 */
+ 0, 0, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 165, 166, 0,
+ 0, 0, 0, 167, 168, 0, 0, 0, 0, 0, 0, 169, 170, 171, 172, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67,
+ 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 0, 0, 174,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 175, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0
+ },
+ { /* page 2, index 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, 178, 179, 180, 0, 0, 0, 0,
+ 181, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 3, index 3 */
+ 357, 358, 359, 360, 361, 0, 362, 363, 364, 365, 366, 367, 368, 0, 0, 369,
+ 0, 370, 0, 371, 372, 0, 0, 0, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 0, 374,
+ 375, 376, 377, 378, 379, 0, 0, 0, 0, 380, 381, 0, 382, 383, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 385, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0,
+ 72, 0, 73, 0, 74, 0, 0, 0, 0, 0, 75, 0, 184, 0, 0, 0, 76, 0, 0, 0, 77, 0,
+ 0, 185, 0, 186, 0, 0, 78, 0, 0, 0, 79, 0, 80, 0, 81, 0, 0, 0, 0, 0, 82,
+ 0, 83, 0, 0, 0, 84, 0, 0, 0, 85, 86, 87, 0, 0, 187, 0, 0, 0, 88, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 4, index 4 */
+ 0, 0, 0, 0, 0, 0, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 189, 0, 90,
+ 91, 190, 92, 0, 191, 0, 0, 0, 192, 0, 0, 0, 0, 93, 0, 0, 0, 193, 0, 0, 0,
+ 194, 0, 195, 0, 0, 94, 0, 0, 196, 0, 95, 96, 197, 97, 0, 198, 0, 0, 0,
+ 199, 0, 0, 0, 0, 98, 0, 0, 0, 200, 0, 0, 0, 201, 0, 202, 0, 0, 0, 0, 0,
+ 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 207, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 208, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 6, index 5 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 210, 0, 211, 0, 0, 0, 0, 0, 0, 0, 0, 388, 389, 390, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 213, 0,
+ 0, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 9, index 6 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 0,
+ 216, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 391,
+ 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 11, index 7 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 0,
+ 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 394, 395, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 396, 0, 0, 0, 0, 0, 0, 0, 102, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 12, index 8 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221,
+ 0, 0, 398, 0, 0, 0, 103, 0, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 399,
+ 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 13, index 9 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, 0, 0, 0, 0, 0, 104,
+ 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 402, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 403, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 105, 0, 0, 224, 0, 0, 405, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 16, index 10 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 30, index 11 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 226, 227, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 229, 0, 0,
+ 0, 0, 0, 0, 230, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 107, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 233, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 235, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 31, index 12 */
+ 108, 109, 236, 237, 238, 239, 240, 241, 110, 111, 242, 243, 244, 245,
+ 246, 247, 112, 113, 0, 0, 0, 0, 0, 0, 114, 115, 0, 0, 0, 0, 0, 0, 116,
+ 117, 248, 249, 250, 251, 252, 253, 118, 119, 254, 255, 256, 257, 258,
+ 259, 120, 121, 0, 0, 0, 0, 0, 0, 122, 123, 0, 0, 0, 0, 0, 0, 124, 125, 0,
+ 0, 0, 0, 0, 0, 126, 127, 0, 0, 0, 0, 0, 0, 128, 129, 0, 0, 0, 0, 0, 0, 0,
+ 130, 0, 0, 0, 0, 0, 0, 131, 132, 260, 261, 262, 263, 264, 265, 133, 134,
+ 266, 267, 268, 269, 270, 271, 272, 0, 0, 0, 273, 0, 0, 0, 0, 0, 0, 0,
+ 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0,
+ 0, 0, 0, 276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 277, 0, 0, 0, 0, 0, 0, 0, 136, 0
+ },
+ { /* page 33, index 13 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 278, 0, 279, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 0, 282, 0,
+ 283, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 34, index 14 */
+ 0, 0, 0, 284, 0, 0, 0, 0, 285, 0, 0, 286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 287, 0, 288, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 289, 0, 0, 0, 0, 0, 0, 290,
+ 0, 291, 0, 0, 292, 0, 0, 0, 0, 293, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 294, 0, 0, 295, 296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 297, 298, 0, 0, 299, 300, 0, 0, 301, 302, 303, 304, 0, 0, 0, 0,
+ 305, 306, 0, 0, 307, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 309, 310, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 311, 0, 0, 0, 0, 0, 312, 313, 0, 314,
+ 0, 0, 0, 0, 0, 0, 315, 316, 317, 318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ { /* page 48, index 15 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319, 0,
+ 0, 0, 0, 320, 0, 321, 0, 322, 0, 323, 0, 324, 0, 325, 0, 326, 0, 327, 0,
+ 328, 0, 329, 0, 330, 0, 331, 0, 0, 332, 0, 333, 0, 334, 0, 0, 0, 0, 0, 0,
+ 137, 0, 0, 138, 0, 0, 139, 0, 0, 140, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 386, 387,
+ 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 0, 336, 0, 0, 0, 0, 337, 0, 338, 0, 339,
+ 0, 340, 0, 341, 0, 342, 0, 343, 0, 344, 0, 345, 0, 346, 0, 347, 0, 348,
+ 0, 0, 349, 0, 350, 0, 351, 0, 0, 0, 0, 0, 0, 142, 0, 0, 143, 0, 0, 144,
+ 0, 0, 145, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 352, 353, 354, 355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 356, 0, 0
+ }
+};
+
+static const short compose_table[COMPOSE_TABLE_LAST + 1] = {
+ 0 /* page 0 */,
+ 1 /* page 1 */,
+ 2 /* page 2 */,
+ 3 /* page 3 */,
+ 4 /* page 4 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 5 /* page 6 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 6 /* page 9 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 7 /* page 11 */,
+ 8 /* page 12 */,
+ 9 /* page 13 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 10 /* page 16 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 11 /* page 30 */,
+ 12 /* page 31 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 13 /* page 33 */,
+ 14 /* page 34 */,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 0 + UNICODE_MAX_TABLE_INDEX,
+ 15 /* page 48 */
+};
+
+static const unsigned short compose_first_single[][2] = {
+ { 0x0338, 0x226e },
+ { 0x0338, 0x2260 },
+ { 0x0338, 0x226f },
+ { 0x0307, 0x1e1e },
+ { 0x0302, 0x0134 },
+ { 0x0307, 0x1e1f },
+ { 0x0304, 0x01de },
+ { 0x0301, 0x01fa },
+ { 0x0301, 0x1e08 },
+ { 0x0301, 0x1e2e },
+ { 0x0304, 0x022a },
+ { 0x0301, 0x01fe },
+ { 0x0304, 0x01df },
+ { 0x0301, 0x01fb },
+ { 0x0301, 0x1e09 },
+ { 0x0301, 0x1e2f },
+ { 0x0304, 0x022b },
+ { 0x0301, 0x01ff },
+ { 0x0307, 0x1e64 },
+ { 0x0307, 0x1e65 },
+ { 0x0307, 0x1e66 },
+ { 0x0307, 0x1e67 },
+ { 0x0301, 0x1e78 },
+ { 0x0301, 0x1e79 },
+ { 0x0308, 0x1e7a },
+ { 0x0308, 0x1e7b },
+ { 0x0307, 0x1e9b },
+ { 0x030c, 0x01ee },
+ { 0x0304, 0x01ec },
+ { 0x0304, 0x01ed },
+ { 0x0304, 0x01e0 },
+ { 0x0304, 0x01e1 },
+ { 0x0306, 0x1e1c },
+ { 0x0306, 0x1e1d },
+ { 0x0304, 0x0230 },
+ { 0x0304, 0x0231 },
+ { 0x030c, 0x01ef },
+ { 0x0314, 0x1fec },
+ { 0x0345, 0x1fb4 },
+ { 0x0345, 0x1fc4 },
+ { 0x0345, 0x1ff4 },
+ { 0x0308, 0x0407 },
+ { 0x0301, 0x0403 },
+ { 0x0308, 0x04de },
+ { 0x0301, 0x040c },
+ { 0x0308, 0x04e6 },
+ { 0x0308, 0x04f4 },
+ { 0x0308, 0x04f8 },
+ { 0x0308, 0x04ec },
+ { 0x0301, 0x0453 },
+ { 0x0308, 0x04df },
+ { 0x0301, 0x045c },
+ { 0x0308, 0x04e7 },
+ { 0x0308, 0x04f5 },
+ { 0x0308, 0x04f9 },
+ { 0x0308, 0x04ed },
+ { 0x0308, 0x0457 },
+ { 0x030f, 0x0476 },
+ { 0x030f, 0x0477 },
+ { 0x0308, 0x04da },
+ { 0x0308, 0x04db },
+ { 0x0308, 0x04ea },
+ { 0x0308, 0x04eb },
+ { 0x0654, 0x0624 },
+ { 0x0654, 0x0626 },
+ { 0x0654, 0x06c2 },
+ { 0x0654, 0x06d3 },
+ { 0x0654, 0x06c0 },
+ { 0x093c, 0x0929 },
+ { 0x093c, 0x0931 },
+ { 0x093c, 0x0934 },
+ { 0x0bd7, 0x0b94 },
+ { 0x0bbe, 0x0bcb },
+ { 0x0c56, 0x0c48 },
+ { 0x0cd5, 0x0cc0 },
+ { 0x0cd5, 0x0ccb },
+ { 0x0d3e, 0x0d4b },
+ { 0x0dca, 0x0ddd },
+ { 0x102e, 0x1026 },
+ { 0x0304, 0x1e38 },
+ { 0x0304, 0x1e39 },
+ { 0x0304, 0x1e5c },
+ { 0x0304, 0x1e5d },
+ { 0x0307, 0x1e68 },
+ { 0x0307, 0x1e69 },
+ { 0x0302, 0x1ec6 },
+ { 0x0302, 0x1ec7 },
+ { 0x0302, 0x1ed8 },
+ { 0x0302, 0x1ed9 },
+ { 0x0345, 0x1f82 },
+ { 0x0345, 0x1f83 },
+ { 0x0345, 0x1f84 },
+ { 0x0345, 0x1f85 },
+ { 0x0345, 0x1f86 },
+ { 0x0345, 0x1f87 },
+ { 0x0345, 0x1f8a },
+ { 0x0345, 0x1f8b },
+ { 0x0345, 0x1f8c },
+ { 0x0345, 0x1f8d },
+ { 0x0345, 0x1f8e },
+ { 0x0345, 0x1f8f },
+ { 0x0345, 0x1f92 },
+ { 0x0345, 0x1f93 },
+ { 0x0345, 0x1f94 },
+ { 0x0345, 0x1f95 },
+ { 0x0345, 0x1f96 },
+ { 0x0345, 0x1f97 },
+ { 0x0345, 0x1f9a },
+ { 0x0345, 0x1f9b },
+ { 0x0345, 0x1f9c },
+ { 0x0345, 0x1f9d },
+ { 0x0345, 0x1f9e },
+ { 0x0345, 0x1f9f },
+ { 0x0345, 0x1fa2 },
+ { 0x0345, 0x1fa3 },
+ { 0x0345, 0x1fa4 },
+ { 0x0345, 0x1fa5 },
+ { 0x0345, 0x1fa6 },
+ { 0x0345, 0x1fa7 },
+ { 0x0345, 0x1faa },
+ { 0x0345, 0x1fab },
+ { 0x0345, 0x1fac },
+ { 0x0345, 0x1fad },
+ { 0x0345, 0x1fae },
+ { 0x0345, 0x1faf },
+ { 0x0345, 0x1fb2 },
+ { 0x0345, 0x1fc2 },
+ { 0x0345, 0x1ff2 },
+ { 0x0345, 0x1fb7 },
+ { 0x0345, 0x1fc7 },
+ { 0x0345, 0x1ff7 },
+ { 0x0338, 0x219a },
+ { 0x0338, 0x219b },
+ { 0x0338, 0x21ae },
+ { 0x0338, 0x21cd },
+ { 0x0338, 0x21cf },
+ { 0x0338, 0x21ce },
+ { 0x0338, 0x2204 },
+ { 0x0338, 0x2209 },
+ { 0x0338, 0x220c },
+ { 0x0338, 0x2224 },
+ { 0x0338, 0x2226 },
+ { 0x0338, 0x2241 },
+ { 0x0338, 0x2244 },
+ { 0x0338, 0x2247 },
+ { 0x0338, 0x2249 },
+ { 0x0338, 0x226d },
+ { 0x0338, 0x2262 },
+ { 0x0338, 0x2270 },
+ { 0x0338, 0x2271 },
+ { 0x0338, 0x2274 },
+ { 0x0338, 0x2275 },
+ { 0x0338, 0x2278 },
+ { 0x0338, 0x2279 },
+ { 0x0338, 0x2280 },
+ { 0x0338, 0x2281 },
+ { 0x0338, 0x22e0 },
+ { 0x0338, 0x22e1 },
+ { 0x0338, 0x2284 },
+ { 0x0338, 0x2285 },
+ { 0x0338, 0x2288 },
+ { 0x0338, 0x2289 },
+ { 0x0338, 0x22e2 },
+ { 0x0338, 0x22e3 },
+ { 0x0338, 0x22ac },
+ { 0x0338, 0x22ad },
+ { 0x0338, 0x22ae },
+ { 0x0338, 0x22af },
+ { 0x0338, 0x22ea },
+ { 0x0338, 0x22eb },
+ { 0x0338, 0x22ec },
+ { 0x0338, 0x22ed },
+ { 0x3099, 0x3094 },
+ { 0x3099, 0x304c },
+ { 0x3099, 0x304e },
+ { 0x3099, 0x3050 },
+ { 0x3099, 0x3052 },
+ { 0x3099, 0x3054 },
+ { 0x3099, 0x3056 },
+ { 0x3099, 0x3058 },
+ { 0x3099, 0x305a },
+ { 0x3099, 0x305c },
+ { 0x3099, 0x305e },
+ { 0x3099, 0x3060 },
+ { 0x3099, 0x3062 },
+ { 0x3099, 0x3065 },
+ { 0x3099, 0x3067 },
+ { 0x3099, 0x3069 },
+ { 0x3099, 0x309e },
+ { 0x3099, 0x30f4 },
+ { 0x3099, 0x30ac },
+ { 0x3099, 0x30ae },
+ { 0x3099, 0x30b0 },
+ { 0x3099, 0x30b2 },
+ { 0x3099, 0x30b4 },
+ { 0x3099, 0x30b6 },
+ { 0x3099, 0x30b8 },
+ { 0x3099, 0x30ba },
+ { 0x3099, 0x30bc },
+ { 0x3099, 0x30be },
+ { 0x3099, 0x30c0 },
+ { 0x3099, 0x30c2 },
+ { 0x3099, 0x30c5 },
+ { 0x3099, 0x30c7 },
+ { 0x3099, 0x30c9 },
+ { 0x3099, 0x30f7 },
+ { 0x3099, 0x30f8 },
+ { 0x3099, 0x30f9 },
+ { 0x3099, 0x30fa },
+ { 0x3099, 0x30fe }
+};
+static const unsigned short compose_second_single[][2] = {
+ { 0x0627, 0x0622 },
+ { 0x0627, 0x0623 },
+ { 0x0627, 0x0625 },
+ { 0x09c7, 0x09cb },
+ { 0x09c7, 0x09cc },
+ { 0x0b47, 0x0b4b },
+ { 0x0b47, 0x0b48 },
+ { 0x0b47, 0x0b4c },
+ { 0x0bc6, 0x0bca },
+ { 0x0bc6, 0x0bcc },
+ { 0x0cc6, 0x0cca },
+ { 0x0cc6, 0x0cc7 },
+ { 0x0cc6, 0x0cc8 },
+ { 0x0d46, 0x0d4a },
+ { 0x0d46, 0x0d4c },
+ { 0x0dd9, 0x0dda },
+ { 0x0dd9, 0x0ddc },
+ { 0x0dd9, 0x0dde }
+};
+static const unsigned short compose_array[146][31] = {
+ { 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x0100, 0x0102, 0x0226, 0x00c4, 0x1ea2, 0x00c5, 0, 0x01cd, 0x0200, 0x0202, 0, 0, 0, 0x1ea0, 0, 0x1e00, 0, 0, 0x0104, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0x1e02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e04, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e06, 0, 0, 0, 0 },
+ { 0, 0x0106, 0x0108, 0, 0, 0, 0x010a, 0, 0, 0, 0, 0x010c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00c7, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0x1e0a, 0, 0, 0, 0, 0x010e, 0, 0, 0, 0, 0, 0x1e0c, 0, 0, 0, 0x1e10, 0, 0x1e12, 0, 0, 0x1e0e, 0, 0, 0, 0 },
+ { 0x00c8, 0x00c9, 0x00ca, 0x1ebc, 0x0112, 0x0114, 0x0116, 0x00cb, 0x1eba, 0, 0, 0x011a, 0x0204, 0x0206, 0, 0, 0, 0x1eb8, 0, 0, 0, 0x0228, 0x0118, 0x1e18, 0, 0x1e1a, 0, 0, 0, 0, 0 },
+ { 0, 0x01f4, 0x011c, 0, 0x1e20, 0x011e, 0x0120, 0, 0, 0, 0, 0x01e6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0122, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0x0124, 0, 0, 0, 0x1e22, 0x1e26, 0, 0, 0, 0x021e, 0, 0, 0, 0, 0, 0x1e24, 0, 0, 0, 0x1e28, 0, 0, 0x1e2a, 0, 0, 0, 0, 0, 0 },
+ { 0x00cc, 0x00cd, 0x00ce, 0x0128, 0x012a, 0x012c, 0x0130, 0x00cf, 0x1ec8, 0, 0, 0x01cf, 0x0208, 0x020a, 0, 0, 0, 0x1eca, 0, 0, 0, 0, 0x012e, 0, 0, 0x1e2c, 0, 0, 0, 0, 0 },
+ { 0, 0x1e30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01e8, 0, 0, 0, 0, 0, 0x1e32, 0, 0, 0, 0x0136, 0, 0, 0, 0, 0x1e34, 0, 0, 0, 0 },
+ { 0, 0x0139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x013d, 0, 0, 0, 0, 0, 0x1e36, 0, 0, 0, 0x013b, 0, 0x1e3c, 0, 0, 0x1e3a, 0, 0, 0, 0 },
+ { 0, 0x1e3e, 0, 0, 0, 0, 0x1e40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x01f8, 0x0143, 0, 0x00d1, 0, 0, 0x1e44, 0, 0, 0, 0, 0x0147, 0, 0, 0, 0, 0, 0x1e46, 0, 0, 0, 0x0145, 0, 0x1e4a, 0, 0, 0x1e48, 0, 0, 0, 0 },
+ { 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x014c, 0x014e, 0x022e, 0x00d6, 0x1ece, 0, 0x0150, 0x01d1, 0x020c, 0x020e, 0, 0, 0x01a0, 0x1ecc, 0, 0, 0, 0, 0x01ea, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x1e54, 0, 0, 0, 0, 0x1e56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x0154, 0, 0, 0, 0, 0x1e58, 0, 0, 0, 0, 0x0158, 0x0210, 0x0212, 0, 0, 0, 0x1e5a, 0, 0, 0, 0x0156, 0, 0, 0, 0, 0x1e5e, 0, 0, 0, 0 },
+ { 0, 0x015a, 0x015c, 0, 0, 0, 0x1e60, 0, 0, 0, 0, 0x0160, 0, 0, 0, 0, 0, 0x1e62, 0, 0, 0x0218, 0x015e, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0x1e6a, 0, 0, 0, 0, 0x0164, 0, 0, 0, 0, 0, 0x1e6c, 0, 0, 0x021a, 0x0162, 0, 0x1e70, 0, 0, 0x1e6e, 0, 0, 0, 0 },
+ { 0x00d9, 0x00da, 0x00db, 0x0168, 0x016a, 0x016c, 0, 0x00dc, 0x1ee6, 0x016e, 0x0170, 0x01d3, 0x0214, 0x0216, 0, 0, 0x01af, 0x1ee4, 0x1e72, 0, 0, 0, 0x0172, 0x1e76, 0, 0x1e74, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0x1e7c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e7e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1e80, 0x1e82, 0x0174, 0, 0, 0, 0x1e86, 0x1e84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0x1e8a, 0x1e8c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ef2, 0x00dd, 0x0176, 0x1ef8, 0x0232, 0, 0x1e8e, 0x0178, 0x1ef6, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ef4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x0179, 0x1e90, 0, 0, 0, 0x017b, 0, 0, 0, 0, 0x017d, 0, 0, 0, 0, 0, 0x1e92, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e94, 0, 0, 0, 0 },
+ { 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x0101, 0x0103, 0x0227, 0x00e4, 0x1ea3, 0x00e5, 0, 0x01ce, 0x0201, 0x0203, 0, 0, 0, 0x1ea1, 0, 0x1e01, 0, 0, 0x0105, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0x1e03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e05, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e07, 0, 0, 0, 0 },
+ { 0, 0x0107, 0x0109, 0, 0, 0, 0x010b, 0, 0, 0, 0, 0x010d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00e7, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0x1e0b, 0, 0, 0, 0, 0x010f, 0, 0, 0, 0, 0, 0x1e0d, 0, 0, 0, 0x1e11, 0, 0x1e13, 0, 0, 0x1e0f, 0, 0, 0, 0 },
+ { 0x00e8, 0x00e9, 0x00ea, 0x1ebd, 0x0113, 0x0115, 0x0117, 0x00eb, 0x1ebb, 0, 0, 0x011b, 0x0205, 0x0207, 0, 0, 0, 0x1eb9, 0, 0, 0, 0x0229, 0x0119, 0x1e19, 0, 0x1e1b, 0, 0, 0, 0, 0 },
+ { 0, 0x01f5, 0x011d, 0, 0x1e21, 0x011f, 0x0121, 0, 0, 0, 0, 0x01e7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0123, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0x0125, 0, 0, 0, 0x1e23, 0x1e27, 0, 0, 0, 0x021f, 0, 0, 0, 0, 0, 0x1e25, 0, 0, 0, 0x1e29, 0, 0, 0x1e2b, 0, 0x1e96, 0, 0, 0, 0 },
+ { 0x00ec, 0x00ed, 0x00ee, 0x0129, 0x012b, 0x012d, 0, 0x00ef, 0x1ec9, 0, 0, 0x01d0, 0x0209, 0x020b, 0, 0, 0, 0x1ecb, 0, 0, 0, 0, 0x012f, 0, 0, 0x1e2d, 0, 0, 0, 0, 0 },
+ { 0, 0, 0x0135, 0, 0, 0, 0, 0, 0, 0, 0, 0x01f0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x1e31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01e9, 0, 0, 0, 0, 0, 0x1e33, 0, 0, 0, 0x0137, 0, 0, 0, 0, 0x1e35, 0, 0, 0, 0 },
+ { 0, 0x013a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x013e, 0, 0, 0, 0, 0, 0x1e37, 0, 0, 0, 0x013c, 0, 0x1e3d, 0, 0, 0x1e3b, 0, 0, 0, 0 },
+ { 0, 0x1e3f, 0, 0, 0, 0, 0x1e41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x01f9, 0x0144, 0, 0x00f1, 0, 0, 0x1e45, 0, 0, 0, 0, 0x0148, 0, 0, 0, 0, 0, 0x1e47, 0, 0, 0, 0x0146, 0, 0x1e4b, 0, 0, 0x1e49, 0, 0, 0, 0 },
+ { 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x014d, 0x014f, 0x022f, 0x00f6, 0x1ecf, 0, 0x0151, 0x01d2, 0x020d, 0x020f, 0, 0, 0x01a1, 0x1ecd, 0, 0, 0, 0, 0x01eb, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x1e55, 0, 0, 0, 0, 0x1e57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x0155, 0, 0, 0, 0, 0x1e59, 0, 0, 0, 0, 0x0159, 0x0211, 0x0213, 0, 0, 0, 0x1e5b, 0, 0, 0, 0x0157, 0, 0, 0, 0, 0x1e5f, 0, 0, 0, 0 },
+ { 0, 0x015b, 0x015d, 0, 0, 0, 0x1e61, 0, 0, 0, 0, 0x0161, 0, 0, 0, 0, 0, 0x1e63, 0, 0, 0x0219, 0x015f, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0x1e6b, 0x1e97, 0, 0, 0, 0x0165, 0, 0, 0, 0, 0, 0x1e6d, 0, 0, 0x021b, 0x0163, 0, 0x1e71, 0, 0, 0x1e6f, 0, 0, 0, 0 },
+ { 0x00f9, 0x00fa, 0x00fb, 0x0169, 0x016b, 0x016d, 0, 0x00fc, 0x1ee7, 0x016f, 0x0171, 0x01d4, 0x0215, 0x0217, 0, 0, 0x01b0, 0x1ee5, 0x1e73, 0, 0, 0, 0x0173, 0x1e77, 0, 0x1e75, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0x1e7d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e7f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1e81, 0x1e83, 0x0175, 0, 0, 0, 0x1e87, 0x1e85, 0, 0x1e98, 0, 0, 0, 0, 0, 0, 0, 0x1e89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0x1e8b, 0x1e8d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ef3, 0x00fd, 0x0177, 0x1ef9, 0x0233, 0, 0x1e8f, 0x00ff, 0x1ef7, 0x1e99, 0, 0, 0, 0, 0, 0, 0, 0x1ef5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x017a, 0x1e91, 0, 0, 0, 0x017c, 0, 0, 0, 0, 0x017e, 0, 0, 0, 0, 0, 0x1e93, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e95, 0, 0, 0, 0 },
+ { 0x1fed, 0x0385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fc1, 0, 0, 0 },
+ { 0x1ea6, 0x1ea4, 0, 0x1eaa, 0, 0, 0, 0, 0x1ea8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x01fc, 0, 0, 0x01e2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ec0, 0x1ebe, 0, 0x1ec4, 0, 0, 0, 0, 0x1ec2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ed2, 0x1ed0, 0, 0x1ed6, 0, 0, 0, 0, 0x1ed4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x1e4c, 0, 0, 0x022c, 0, 0, 0x1e4e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x01db, 0x01d7, 0, 0, 0x01d5, 0, 0, 0, 0, 0, 0, 0x01d9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ea7, 0x1ea5, 0, 0x1eab, 0, 0, 0, 0, 0x1ea9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x01fd, 0, 0, 0x01e3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ec1, 0x1ebf, 0, 0x1ec5, 0, 0, 0, 0, 0x1ec3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ed3, 0x1ed1, 0, 0x1ed7, 0, 0, 0, 0, 0x1ed5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0x1e4d, 0, 0, 0x022d, 0, 0, 0x1e4f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x01dc, 0x01d8, 0, 0, 0x01d6, 0, 0, 0, 0, 0, 0, 0x01da, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1eb0, 0x1eae, 0, 0x1eb4, 0, 0, 0, 0, 0x1eb2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1eb1, 0x1eaf, 0, 0x1eb5, 0, 0, 0, 0, 0x1eb3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1e14, 0x1e16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1e15, 0x1e17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1e50, 0x1e52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1e51, 0x1e53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1edc, 0x1eda, 0, 0x1ee0, 0, 0, 0, 0, 0x1ede, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ee2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1edd, 0x1edb, 0, 0x1ee1, 0, 0, 0, 0, 0x1edf, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ee3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1eea, 0x1ee8, 0, 0x1eee, 0, 0, 0, 0, 0x1eec, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ef0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1eeb, 0x1ee9, 0, 0x1eef, 0, 0, 0, 0, 0x1eed, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ef1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1fba, 0x0386, 0, 0, 0x1fb9, 0x1fb8, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f08, 0x1f09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fbc, 0, 0 },
+ { 0x1fc8, 0x0388, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f18, 0x1f19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1fca, 0x0389, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f28, 0x1f29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fcc, 0, 0 },
+ { 0x1fda, 0x038a, 0, 0, 0x1fd9, 0x1fd8, 0, 0x03aa, 0, 0, 0, 0, 0, 0, 0x1f38, 0x1f39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ff8, 0x038c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f48, 0x1f49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1fea, 0x038e, 0, 0, 0x1fe9, 0x1fe8, 0, 0x03ab, 0, 0, 0, 0, 0, 0, 0, 0x1f59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1ffa, 0x038f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f68, 0x1f69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ffc, 0, 0 },
+ { 0x1f70, 0x03ac, 0, 0, 0x1fb1, 0x1fb0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f00, 0x1f01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fb6, 0x1fb3, 0, 0 },
+ { 0x1f72, 0x03ad, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f10, 0x1f11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f74, 0x03ae, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f20, 0x1f21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fc6, 0x1fc3, 0, 0 },
+ { 0x1f76, 0x03af, 0, 0, 0x1fd1, 0x1fd0, 0, 0x03ca, 0, 0, 0, 0, 0, 0, 0x1f30, 0x1f31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fd6, 0, 0, 0 },
+ { 0x1f78, 0x03cc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f40, 0x1f41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fe4, 0x1fe5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f7a, 0x03cd, 0, 0, 0x1fe1, 0x1fe0, 0, 0x03cb, 0, 0, 0, 0, 0, 0, 0x1f50, 0x1f51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fe6, 0, 0, 0 },
+ { 0x1f7c, 0x03ce, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f60, 0x1f61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ff6, 0x1ff3, 0, 0 },
+ { 0x1fd2, 0x0390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fd7, 0, 0, 0 },
+ { 0x1fe2, 0x03b0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fe7, 0, 0, 0 },
+ { 0, 0x03d3, 0, 0, 0, 0, 0, 0x03d4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0x04d0, 0, 0x04d2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x0400, 0, 0, 0, 0, 0x04d6, 0, 0x0401, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0x04c1, 0, 0x04dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x040d, 0, 0, 0, 0x04e2, 0x0419, 0, 0x04e4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0x04ee, 0x040e, 0, 0x04f0, 0, 0, 0x04f2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0x04d1, 0, 0x04d3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x0450, 0, 0, 0, 0, 0x04d7, 0, 0x0451, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0x04c2, 0, 0x04dd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x045d, 0, 0, 0, 0x04e3, 0x0439, 0, 0x04e5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0x04ef, 0x045e, 0, 0x04f1, 0, 0, 0x04f3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0x1eac, 0, 0, 0x1eb6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0x1ead, 0, 0, 0x1eb7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f02, 0x1f04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f06, 0x1f80, 0, 0 },
+ { 0x1f03, 0x1f05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f07, 0x1f81, 0, 0 },
+ { 0x1f0a, 0x1f0c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f0e, 0x1f88, 0, 0 },
+ { 0x1f0b, 0x1f0d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f0f, 0x1f89, 0, 0 },
+ { 0x1f12, 0x1f14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f13, 0x1f15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f1a, 0x1f1c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f1b, 0x1f1d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f22, 0x1f24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f26, 0x1f90, 0, 0 },
+ { 0x1f23, 0x1f25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f27, 0x1f91, 0, 0 },
+ { 0x1f2a, 0x1f2c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f2e, 0x1f98, 0, 0 },
+ { 0x1f2b, 0x1f2d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f2f, 0x1f99, 0, 0 },
+ { 0x1f32, 0x1f34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f36, 0, 0, 0 },
+ { 0x1f33, 0x1f35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f37, 0, 0, 0 },
+ { 0x1f3a, 0x1f3c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f3e, 0, 0, 0 },
+ { 0x1f3b, 0x1f3d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f3f, 0, 0, 0 },
+ { 0x1f42, 0x1f44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f43, 0x1f45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f4a, 0x1f4c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f4b, 0x1f4d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x1f52, 0x1f54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f56, 0, 0, 0 },
+ { 0x1f53, 0x1f55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f57, 0, 0, 0 },
+ { 0x1f5b, 0x1f5d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f5f, 0, 0, 0 },
+ { 0x1f62, 0x1f64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f66, 0x1fa0, 0, 0 },
+ { 0x1f63, 0x1f65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f67, 0x1fa1, 0, 0 },
+ { 0x1f6a, 0x1f6c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f6e, 0x1fa8, 0, 0 },
+ { 0x1f6b, 0x1f6d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1f6f, 0x1fa9, 0, 0 },
+ { 0x1fcd, 0x1fce, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fcf, 0, 0, 0 },
+ { 0x1fdd, 0x1fde, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fdf, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3070, 0x3071 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3073, 0x3074 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3076, 0x3077 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3079, 0x307a },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x307c, 0x307d },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30d0, 0x30d1 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30d3, 0x30d4 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30d6, 0x30d7 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30d9, 0x30da },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x30dc, 0x30dd }
+};
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeDecompTables.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeDecompTables.h
new file mode 100644
index 00000000000..4bc34b18d99
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeDecompTables.h
@@ -0,0 +1,8526 @@
+// Generated by gen-unicode-tables.py
+
+typedef struct {
+ Unicode character;
+ int length;
+ int offset;
+} decomposition;
+
+#define DECOMP_TABLE_LENGTH 5143
+
+static const decomposition decomp_table[] = {
+ { 0xa0, 1, 0 },
+ { 0xa8, 2, 1 },
+ { 0xaa, 1, 3 },
+ { 0xaf, 2, 4 },
+ { 0xb2, 1, 6 },
+ { 0xb3, 1, 7 },
+ { 0xb4, 2, 8 },
+ { 0xb5, 1, 10 },
+ { 0xb8, 2, 11 },
+ { 0xb9, 1, 13 },
+ { 0xba, 1, 14 },
+ { 0xbc, 3, 15 },
+ { 0xbd, 3, 18 },
+ { 0xbe, 3, 21 },
+ { 0xc0, 2, 24 },
+ { 0xc1, 2, 26 },
+ { 0xc2, 2, 28 },
+ { 0xc3, 2, 30 },
+ { 0xc4, 2, 32 },
+ { 0xc5, 2, 34 },
+ { 0xc7, 2, 36 },
+ { 0xc8, 2, 38 },
+ { 0xc9, 2, 40 },
+ { 0xca, 2, 42 },
+ { 0xcb, 2, 44 },
+ { 0xcc, 2, 46 },
+ { 0xcd, 2, 48 },
+ { 0xce, 2, 50 },
+ { 0xcf, 2, 52 },
+ { 0xd1, 2, 54 },
+ { 0xd2, 2, 56 },
+ { 0xd3, 2, 58 },
+ { 0xd4, 2, 60 },
+ { 0xd5, 2, 62 },
+ { 0xd6, 2, 64 },
+ { 0xd9, 2, 66 },
+ { 0xda, 2, 68 },
+ { 0xdb, 2, 70 },
+ { 0xdc, 2, 72 },
+ { 0xdd, 2, 74 },
+ { 0xe0, 2, 76 },
+ { 0xe1, 2, 78 },
+ { 0xe2, 2, 80 },
+ { 0xe3, 2, 82 },
+ { 0xe4, 2, 84 },
+ { 0xe5, 2, 86 },
+ { 0xe7, 2, 88 },
+ { 0xe8, 2, 90 },
+ { 0xe9, 2, 92 },
+ { 0xea, 2, 94 },
+ { 0xeb, 2, 96 },
+ { 0xec, 2, 98 },
+ { 0xed, 2, 100 },
+ { 0xee, 2, 102 },
+ { 0xef, 2, 104 },
+ { 0xf1, 2, 106 },
+ { 0xf2, 2, 108 },
+ { 0xf3, 2, 110 },
+ { 0xf4, 2, 112 },
+ { 0xf5, 2, 114 },
+ { 0xf6, 2, 116 },
+ { 0xf9, 2, 118 },
+ { 0xfa, 2, 120 },
+ { 0xfb, 2, 122 },
+ { 0xfc, 2, 124 },
+ { 0xfd, 2, 126 },
+ { 0xff, 2, 128 },
+ { 0x100, 2, 130 },
+ { 0x101, 2, 132 },
+ { 0x102, 2, 134 },
+ { 0x103, 2, 136 },
+ { 0x104, 2, 138 },
+ { 0x105, 2, 140 },
+ { 0x106, 2, 142 },
+ { 0x107, 2, 144 },
+ { 0x108, 2, 146 },
+ { 0x109, 2, 148 },
+ { 0x10a, 2, 150 },
+ { 0x10b, 2, 152 },
+ { 0x10c, 2, 154 },
+ { 0x10d, 2, 156 },
+ { 0x10e, 2, 158 },
+ { 0x10f, 2, 160 },
+ { 0x112, 2, 162 },
+ { 0x113, 2, 164 },
+ { 0x114, 2, 166 },
+ { 0x115, 2, 168 },
+ { 0x116, 2, 170 },
+ { 0x117, 2, 172 },
+ { 0x118, 2, 174 },
+ { 0x119, 2, 176 },
+ { 0x11a, 2, 178 },
+ { 0x11b, 2, 180 },
+ { 0x11c, 2, 182 },
+ { 0x11d, 2, 184 },
+ { 0x11e, 2, 186 },
+ { 0x11f, 2, 188 },
+ { 0x120, 2, 190 },
+ { 0x121, 2, 192 },
+ { 0x122, 2, 194 },
+ { 0x123, 2, 196 },
+ { 0x124, 2, 198 },
+ { 0x125, 2, 200 },
+ { 0x128, 2, 202 },
+ { 0x129, 2, 204 },
+ { 0x12a, 2, 206 },
+ { 0x12b, 2, 208 },
+ { 0x12c, 2, 210 },
+ { 0x12d, 2, 212 },
+ { 0x12e, 2, 214 },
+ { 0x12f, 2, 216 },
+ { 0x130, 2, 218 },
+ { 0x132, 2, 220 },
+ { 0x133, 2, 222 },
+ { 0x134, 2, 224 },
+ { 0x135, 2, 226 },
+ { 0x136, 2, 228 },
+ { 0x137, 2, 230 },
+ { 0x139, 2, 232 },
+ { 0x13a, 2, 234 },
+ { 0x13b, 2, 236 },
+ { 0x13c, 2, 238 },
+ { 0x13d, 2, 240 },
+ { 0x13e, 2, 242 },
+ { 0x13f, 2, 244 },
+ { 0x140, 2, 246 },
+ { 0x143, 2, 248 },
+ { 0x144, 2, 250 },
+ { 0x145, 2, 252 },
+ { 0x146, 2, 254 },
+ { 0x147, 2, 256 },
+ { 0x148, 2, 258 },
+ { 0x149, 2, 260 },
+ { 0x14c, 2, 262 },
+ { 0x14d, 2, 264 },
+ { 0x14e, 2, 266 },
+ { 0x14f, 2, 268 },
+ { 0x150, 2, 270 },
+ { 0x151, 2, 272 },
+ { 0x154, 2, 274 },
+ { 0x155, 2, 276 },
+ { 0x156, 2, 278 },
+ { 0x157, 2, 280 },
+ { 0x158, 2, 282 },
+ { 0x159, 2, 284 },
+ { 0x15a, 2, 286 },
+ { 0x15b, 2, 288 },
+ { 0x15c, 2, 290 },
+ { 0x15d, 2, 292 },
+ { 0x15e, 2, 294 },
+ { 0x15f, 2, 296 },
+ { 0x160, 2, 298 },
+ { 0x161, 2, 300 },
+ { 0x162, 2, 302 },
+ { 0x163, 2, 304 },
+ { 0x164, 2, 306 },
+ { 0x165, 2, 308 },
+ { 0x168, 2, 310 },
+ { 0x169, 2, 312 },
+ { 0x16a, 2, 314 },
+ { 0x16b, 2, 316 },
+ { 0x16c, 2, 318 },
+ { 0x16d, 2, 320 },
+ { 0x16e, 2, 322 },
+ { 0x16f, 2, 324 },
+ { 0x170, 2, 326 },
+ { 0x171, 2, 328 },
+ { 0x172, 2, 330 },
+ { 0x173, 2, 332 },
+ { 0x174, 2, 334 },
+ { 0x175, 2, 336 },
+ { 0x176, 2, 338 },
+ { 0x177, 2, 340 },
+ { 0x178, 2, 342 },
+ { 0x179, 2, 344 },
+ { 0x17a, 2, 346 },
+ { 0x17b, 2, 348 },
+ { 0x17c, 2, 350 },
+ { 0x17d, 2, 352 },
+ { 0x17e, 2, 354 },
+ { 0x17f, 1, 356 },
+ { 0x1a0, 2, 357 },
+ { 0x1a1, 2, 359 },
+ { 0x1af, 2, 361 },
+ { 0x1b0, 2, 363 },
+ { 0x1c4, 3, 365 },
+ { 0x1c5, 3, 368 },
+ { 0x1c6, 3, 371 },
+ { 0x1c7, 2, 374 },
+ { 0x1c8, 2, 376 },
+ { 0x1c9, 2, 378 },
+ { 0x1ca, 2, 380 },
+ { 0x1cb, 2, 382 },
+ { 0x1cc, 2, 384 },
+ { 0x1cd, 2, 386 },
+ { 0x1ce, 2, 388 },
+ { 0x1cf, 2, 390 },
+ { 0x1d0, 2, 392 },
+ { 0x1d1, 2, 394 },
+ { 0x1d2, 2, 396 },
+ { 0x1d3, 2, 398 },
+ { 0x1d4, 2, 400 },
+ { 0x1d5, 3, 402 },
+ { 0x1d6, 3, 405 },
+ { 0x1d7, 3, 408 },
+ { 0x1d8, 3, 411 },
+ { 0x1d9, 3, 414 },
+ { 0x1da, 3, 417 },
+ { 0x1db, 3, 420 },
+ { 0x1dc, 3, 423 },
+ { 0x1de, 3, 426 },
+ { 0x1df, 3, 429 },
+ { 0x1e0, 3, 432 },
+ { 0x1e1, 3, 435 },
+ { 0x1e2, 2, 438 },
+ { 0x1e3, 2, 440 },
+ { 0x1e6, 2, 442 },
+ { 0x1e7, 2, 444 },
+ { 0x1e8, 2, 446 },
+ { 0x1e9, 2, 448 },
+ { 0x1ea, 2, 450 },
+ { 0x1eb, 2, 452 },
+ { 0x1ec, 3, 454 },
+ { 0x1ed, 3, 457 },
+ { 0x1ee, 2, 460 },
+ { 0x1ef, 2, 462 },
+ { 0x1f0, 2, 464 },
+ { 0x1f1, 2, 466 },
+ { 0x1f2, 2, 468 },
+ { 0x1f3, 2, 470 },
+ { 0x1f4, 2, 472 },
+ { 0x1f5, 2, 474 },
+ { 0x1f8, 2, 476 },
+ { 0x1f9, 2, 478 },
+ { 0x1fa, 3, 480 },
+ { 0x1fb, 3, 483 },
+ { 0x1fc, 2, 486 },
+ { 0x1fd, 2, 488 },
+ { 0x1fe, 2, 490 },
+ { 0x1ff, 2, 492 },
+ { 0x200, 2, 494 },
+ { 0x201, 2, 496 },
+ { 0x202, 2, 498 },
+ { 0x203, 2, 500 },
+ { 0x204, 2, 502 },
+ { 0x205, 2, 504 },
+ { 0x206, 2, 506 },
+ { 0x207, 2, 508 },
+ { 0x208, 2, 510 },
+ { 0x209, 2, 512 },
+ { 0x20a, 2, 514 },
+ { 0x20b, 2, 516 },
+ { 0x20c, 2, 518 },
+ { 0x20d, 2, 520 },
+ { 0x20e, 2, 522 },
+ { 0x20f, 2, 524 },
+ { 0x210, 2, 526 },
+ { 0x211, 2, 528 },
+ { 0x212, 2, 530 },
+ { 0x213, 2, 532 },
+ { 0x214, 2, 534 },
+ { 0x215, 2, 536 },
+ { 0x216, 2, 538 },
+ { 0x217, 2, 540 },
+ { 0x218, 2, 542 },
+ { 0x219, 2, 544 },
+ { 0x21a, 2, 546 },
+ { 0x21b, 2, 548 },
+ { 0x21e, 2, 550 },
+ { 0x21f, 2, 552 },
+ { 0x226, 2, 554 },
+ { 0x227, 2, 556 },
+ { 0x228, 2, 558 },
+ { 0x229, 2, 560 },
+ { 0x22a, 3, 562 },
+ { 0x22b, 3, 565 },
+ { 0x22c, 3, 568 },
+ { 0x22d, 3, 571 },
+ { 0x22e, 2, 574 },
+ { 0x22f, 2, 576 },
+ { 0x230, 3, 578 },
+ { 0x231, 3, 581 },
+ { 0x232, 2, 584 },
+ { 0x233, 2, 586 },
+ { 0x2b0, 1, 588 },
+ { 0x2b1, 1, 589 },
+ { 0x2b2, 1, 590 },
+ { 0x2b3, 1, 591 },
+ { 0x2b4, 1, 592 },
+ { 0x2b5, 1, 593 },
+ { 0x2b6, 1, 594 },
+ { 0x2b7, 1, 595 },
+ { 0x2b8, 1, 596 },
+ { 0x2d8, 2, 597 },
+ { 0x2d9, 2, 599 },
+ { 0x2da, 2, 601 },
+ { 0x2db, 2, 603 },
+ { 0x2dc, 2, 605 },
+ { 0x2dd, 2, 607 },
+ { 0x2e0, 1, 609 },
+ { 0x2e1, 1, 610 },
+ { 0x2e2, 1, 356 },
+ { 0x2e3, 1, 611 },
+ { 0x2e4, 1, 612 },
+ { 0x340, 1, 613 },
+ { 0x341, 1, 614 },
+ { 0x343, 1, 615 },
+ { 0x344, 2, 616 },
+ { 0x374, 1, 618 },
+ { 0x37a, 2, 619 },
+ { 0x37e, 1, 621 },
+ { 0x384, 2, 8 },
+ { 0x385, 3, 622 },
+ { 0x386, 2, 625 },
+ { 0x387, 1, 627 },
+ { 0x388, 2, 628 },
+ { 0x389, 2, 630 },
+ { 0x38a, 2, 632 },
+ { 0x38c, 2, 634 },
+ { 0x38e, 2, 636 },
+ { 0x38f, 2, 638 },
+ { 0x390, 3, 640 },
+ { 0x3aa, 2, 643 },
+ { 0x3ab, 2, 645 },
+ { 0x3ac, 2, 647 },
+ { 0x3ad, 2, 649 },
+ { 0x3ae, 2, 651 },
+ { 0x3af, 2, 653 },
+ { 0x3b0, 3, 655 },
+ { 0x3ca, 2, 658 },
+ { 0x3cb, 2, 660 },
+ { 0x3cc, 2, 662 },
+ { 0x3cd, 2, 664 },
+ { 0x3ce, 2, 666 },
+ { 0x3d0, 1, 668 },
+ { 0x3d1, 1, 669 },
+ { 0x3d2, 1, 670 },
+ { 0x3d3, 2, 636 },
+ { 0x3d4, 2, 645 },
+ { 0x3d5, 1, 671 },
+ { 0x3d6, 1, 672 },
+ { 0x3f0, 1, 673 },
+ { 0x3f1, 1, 674 },
+ { 0x3f2, 1, 675 },
+ { 0x3f4, 1, 676 },
+ { 0x3f5, 1, 677 },
+ { 0x400, 2, 678 },
+ { 0x401, 2, 680 },
+ { 0x403, 2, 682 },
+ { 0x407, 2, 684 },
+ { 0x40c, 2, 686 },
+ { 0x40d, 2, 688 },
+ { 0x40e, 2, 690 },
+ { 0x419, 2, 692 },
+ { 0x439, 2, 694 },
+ { 0x450, 2, 696 },
+ { 0x451, 2, 698 },
+ { 0x453, 2, 700 },
+ { 0x457, 2, 702 },
+ { 0x45c, 2, 704 },
+ { 0x45d, 2, 706 },
+ { 0x45e, 2, 708 },
+ { 0x476, 2, 710 },
+ { 0x477, 2, 712 },
+ { 0x4c1, 2, 714 },
+ { 0x4c2, 2, 716 },
+ { 0x4d0, 2, 718 },
+ { 0x4d1, 2, 720 },
+ { 0x4d2, 2, 722 },
+ { 0x4d3, 2, 724 },
+ { 0x4d6, 2, 726 },
+ { 0x4d7, 2, 728 },
+ { 0x4da, 2, 730 },
+ { 0x4db, 2, 732 },
+ { 0x4dc, 2, 734 },
+ { 0x4dd, 2, 736 },
+ { 0x4de, 2, 738 },
+ { 0x4df, 2, 740 },
+ { 0x4e2, 2, 742 },
+ { 0x4e3, 2, 744 },
+ { 0x4e4, 2, 746 },
+ { 0x4e5, 2, 748 },
+ { 0x4e6, 2, 750 },
+ { 0x4e7, 2, 752 },
+ { 0x4ea, 2, 754 },
+ { 0x4eb, 2, 756 },
+ { 0x4ec, 2, 758 },
+ { 0x4ed, 2, 760 },
+ { 0x4ee, 2, 762 },
+ { 0x4ef, 2, 764 },
+ { 0x4f0, 2, 766 },
+ { 0x4f1, 2, 768 },
+ { 0x4f2, 2, 770 },
+ { 0x4f3, 2, 772 },
+ { 0x4f4, 2, 774 },
+ { 0x4f5, 2, 776 },
+ { 0x4f8, 2, 778 },
+ { 0x4f9, 2, 780 },
+ { 0x587, 2, 782 },
+ { 0x622, 2, 784 },
+ { 0x623, 2, 786 },
+ { 0x624, 2, 788 },
+ { 0x625, 2, 790 },
+ { 0x626, 2, 792 },
+ { 0x675, 2, 794 },
+ { 0x676, 2, 796 },
+ { 0x677, 2, 798 },
+ { 0x678, 2, 800 },
+ { 0x6c0, 2, 802 },
+ { 0x6c2, 2, 804 },
+ { 0x6d3, 2, 806 },
+ { 0x929, 2, 808 },
+ { 0x931, 2, 810 },
+ { 0x934, 2, 812 },
+ { 0x958, 2, 814 },
+ { 0x959, 2, 816 },
+ { 0x95a, 2, 818 },
+ { 0x95b, 2, 820 },
+ { 0x95c, 2, 822 },
+ { 0x95d, 2, 824 },
+ { 0x95e, 2, 826 },
+ { 0x95f, 2, 828 },
+ { 0x9cb, 2, 830 },
+ { 0x9cc, 2, 832 },
+ { 0x9dc, 2, 834 },
+ { 0x9dd, 2, 836 },
+ { 0x9df, 2, 838 },
+ { 0xa33, 2, 840 },
+ { 0xa36, 2, 842 },
+ { 0xa59, 2, 844 },
+ { 0xa5a, 2, 846 },
+ { 0xa5b, 2, 848 },
+ { 0xa5e, 2, 850 },
+ { 0xb48, 2, 852 },
+ { 0xb4b, 2, 854 },
+ { 0xb4c, 2, 856 },
+ { 0xb5c, 2, 858 },
+ { 0xb5d, 2, 860 },
+ { 0xb94, 2, 862 },
+ { 0xbca, 2, 864 },
+ { 0xbcb, 2, 866 },
+ { 0xbcc, 2, 868 },
+ { 0xc48, 2, 870 },
+ { 0xcc0, 2, 872 },
+ { 0xcc7, 2, 874 },
+ { 0xcc8, 2, 876 },
+ { 0xcca, 2, 878 },
+ { 0xccb, 3, 880 },
+ { 0xd4a, 2, 883 },
+ { 0xd4b, 2, 885 },
+ { 0xd4c, 2, 887 },
+ { 0xdda, 2, 889 },
+ { 0xddc, 2, 891 },
+ { 0xddd, 3, 893 },
+ { 0xdde, 2, 896 },
+ { 0xe33, 2, 898 },
+ { 0xeb3, 2, 900 },
+ { 0xedc, 2, 902 },
+ { 0xedd, 2, 904 },
+ { 0xf0c, 1, 906 },
+ { 0xf43, 2, 907 },
+ { 0xf4d, 2, 909 },
+ { 0xf52, 2, 911 },
+ { 0xf57, 2, 913 },
+ { 0xf5c, 2, 915 },
+ { 0xf69, 2, 917 },
+ { 0xf73, 2, 919 },
+ { 0xf75, 2, 921 },
+ { 0xf76, 2, 923 },
+ { 0xf77, 3, 925 },
+ { 0xf78, 2, 928 },
+ { 0xf79, 3, 930 },
+ { 0xf81, 2, 933 },
+ { 0xf93, 2, 935 },
+ { 0xf9d, 2, 937 },
+ { 0xfa2, 2, 939 },
+ { 0xfa7, 2, 941 },
+ { 0xfac, 2, 943 },
+ { 0xfb9, 2, 945 },
+ { 0x1026, 2, 947 },
+ { 0x1e00, 2, 949 },
+ { 0x1e01, 2, 951 },
+ { 0x1e02, 2, 953 },
+ { 0x1e03, 2, 955 },
+ { 0x1e04, 2, 957 },
+ { 0x1e05, 2, 959 },
+ { 0x1e06, 2, 961 },
+ { 0x1e07, 2, 963 },
+ { 0x1e08, 3, 965 },
+ { 0x1e09, 3, 968 },
+ { 0x1e0a, 2, 971 },
+ { 0x1e0b, 2, 973 },
+ { 0x1e0c, 2, 975 },
+ { 0x1e0d, 2, 977 },
+ { 0x1e0e, 2, 979 },
+ { 0x1e0f, 2, 981 },
+ { 0x1e10, 2, 983 },
+ { 0x1e11, 2, 985 },
+ { 0x1e12, 2, 987 },
+ { 0x1e13, 2, 989 },
+ { 0x1e14, 3, 991 },
+ { 0x1e15, 3, 994 },
+ { 0x1e16, 3, 997 },
+ { 0x1e17, 3, 1000 },
+ { 0x1e18, 2, 1003 },
+ { 0x1e19, 2, 1005 },
+ { 0x1e1a, 2, 1007 },
+ { 0x1e1b, 2, 1009 },
+ { 0x1e1c, 3, 1011 },
+ { 0x1e1d, 3, 1014 },
+ { 0x1e1e, 2, 1017 },
+ { 0x1e1f, 2, 1019 },
+ { 0x1e20, 2, 1021 },
+ { 0x1e21, 2, 1023 },
+ { 0x1e22, 2, 1025 },
+ { 0x1e23, 2, 1027 },
+ { 0x1e24, 2, 1029 },
+ { 0x1e25, 2, 1031 },
+ { 0x1e26, 2, 1033 },
+ { 0x1e27, 2, 1035 },
+ { 0x1e28, 2, 1037 },
+ { 0x1e29, 2, 1039 },
+ { 0x1e2a, 2, 1041 },
+ { 0x1e2b, 2, 1043 },
+ { 0x1e2c, 2, 1045 },
+ { 0x1e2d, 2, 1047 },
+ { 0x1e2e, 3, 1049 },
+ { 0x1e2f, 3, 1052 },
+ { 0x1e30, 2, 1055 },
+ { 0x1e31, 2, 1057 },
+ { 0x1e32, 2, 1059 },
+ { 0x1e33, 2, 1061 },
+ { 0x1e34, 2, 1063 },
+ { 0x1e35, 2, 1065 },
+ { 0x1e36, 2, 1067 },
+ { 0x1e37, 2, 1069 },
+ { 0x1e38, 3, 1071 },
+ { 0x1e39, 3, 1074 },
+ { 0x1e3a, 2, 1077 },
+ { 0x1e3b, 2, 1079 },
+ { 0x1e3c, 2, 1081 },
+ { 0x1e3d, 2, 1083 },
+ { 0x1e3e, 2, 1085 },
+ { 0x1e3f, 2, 1087 },
+ { 0x1e40, 2, 1089 },
+ { 0x1e41, 2, 1091 },
+ { 0x1e42, 2, 1093 },
+ { 0x1e43, 2, 1095 },
+ { 0x1e44, 2, 1097 },
+ { 0x1e45, 2, 1099 },
+ { 0x1e46, 2, 1101 },
+ { 0x1e47, 2, 1103 },
+ { 0x1e48, 2, 1105 },
+ { 0x1e49, 2, 1107 },
+ { 0x1e4a, 2, 1109 },
+ { 0x1e4b, 2, 1111 },
+ { 0x1e4c, 3, 1113 },
+ { 0x1e4d, 3, 1116 },
+ { 0x1e4e, 3, 1119 },
+ { 0x1e4f, 3, 1122 },
+ { 0x1e50, 3, 1125 },
+ { 0x1e51, 3, 1128 },
+ { 0x1e52, 3, 1131 },
+ { 0x1e53, 3, 1134 },
+ { 0x1e54, 2, 1137 },
+ { 0x1e55, 2, 1139 },
+ { 0x1e56, 2, 1141 },
+ { 0x1e57, 2, 1143 },
+ { 0x1e58, 2, 1145 },
+ { 0x1e59, 2, 1147 },
+ { 0x1e5a, 2, 1149 },
+ { 0x1e5b, 2, 1151 },
+ { 0x1e5c, 3, 1153 },
+ { 0x1e5d, 3, 1156 },
+ { 0x1e5e, 2, 1159 },
+ { 0x1e5f, 2, 1161 },
+ { 0x1e60, 2, 1163 },
+ { 0x1e61, 2, 1165 },
+ { 0x1e62, 2, 1167 },
+ { 0x1e63, 2, 1169 },
+ { 0x1e64, 3, 1171 },
+ { 0x1e65, 3, 1174 },
+ { 0x1e66, 3, 1177 },
+ { 0x1e67, 3, 1180 },
+ { 0x1e68, 3, 1183 },
+ { 0x1e69, 3, 1186 },
+ { 0x1e6a, 2, 1189 },
+ { 0x1e6b, 2, 1191 },
+ { 0x1e6c, 2, 1193 },
+ { 0x1e6d, 2, 1195 },
+ { 0x1e6e, 2, 1197 },
+ { 0x1e6f, 2, 1199 },
+ { 0x1e70, 2, 1201 },
+ { 0x1e71, 2, 1203 },
+ { 0x1e72, 2, 1205 },
+ { 0x1e73, 2, 1207 },
+ { 0x1e74, 2, 1209 },
+ { 0x1e75, 2, 1211 },
+ { 0x1e76, 2, 1213 },
+ { 0x1e77, 2, 1215 },
+ { 0x1e78, 3, 1217 },
+ { 0x1e79, 3, 1220 },
+ { 0x1e7a, 3, 1223 },
+ { 0x1e7b, 3, 1226 },
+ { 0x1e7c, 2, 1229 },
+ { 0x1e7d, 2, 1231 },
+ { 0x1e7e, 2, 1233 },
+ { 0x1e7f, 2, 1235 },
+ { 0x1e80, 2, 1237 },
+ { 0x1e81, 2, 1239 },
+ { 0x1e82, 2, 1241 },
+ { 0x1e83, 2, 1243 },
+ { 0x1e84, 2, 1245 },
+ { 0x1e85, 2, 1247 },
+ { 0x1e86, 2, 1249 },
+ { 0x1e87, 2, 1251 },
+ { 0x1e88, 2, 1253 },
+ { 0x1e89, 2, 1255 },
+ { 0x1e8a, 2, 1257 },
+ { 0x1e8b, 2, 1259 },
+ { 0x1e8c, 2, 1261 },
+ { 0x1e8d, 2, 1263 },
+ { 0x1e8e, 2, 1265 },
+ { 0x1e8f, 2, 1267 },
+ { 0x1e90, 2, 1269 },
+ { 0x1e91, 2, 1271 },
+ { 0x1e92, 2, 1273 },
+ { 0x1e93, 2, 1275 },
+ { 0x1e94, 2, 1277 },
+ { 0x1e95, 2, 1279 },
+ { 0x1e96, 2, 1281 },
+ { 0x1e97, 2, 1283 },
+ { 0x1e98, 2, 1285 },
+ { 0x1e99, 2, 1287 },
+ { 0x1e9a, 2, 1289 },
+ { 0x1e9b, 2, 1165 },
+ { 0x1ea0, 2, 1291 },
+ { 0x1ea1, 2, 1293 },
+ { 0x1ea2, 2, 1295 },
+ { 0x1ea3, 2, 1297 },
+ { 0x1ea4, 3, 1299 },
+ { 0x1ea5, 3, 1302 },
+ { 0x1ea6, 3, 1305 },
+ { 0x1ea7, 3, 1308 },
+ { 0x1ea8, 3, 1311 },
+ { 0x1ea9, 3, 1314 },
+ { 0x1eaa, 3, 1317 },
+ { 0x1eab, 3, 1320 },
+ { 0x1eac, 3, 1323 },
+ { 0x1ead, 3, 1326 },
+ { 0x1eae, 3, 1329 },
+ { 0x1eaf, 3, 1332 },
+ { 0x1eb0, 3, 1335 },
+ { 0x1eb1, 3, 1338 },
+ { 0x1eb2, 3, 1341 },
+ { 0x1eb3, 3, 1344 },
+ { 0x1eb4, 3, 1347 },
+ { 0x1eb5, 3, 1350 },
+ { 0x1eb6, 3, 1353 },
+ { 0x1eb7, 3, 1356 },
+ { 0x1eb8, 2, 1359 },
+ { 0x1eb9, 2, 1361 },
+ { 0x1eba, 2, 1363 },
+ { 0x1ebb, 2, 1365 },
+ { 0x1ebc, 2, 1367 },
+ { 0x1ebd, 2, 1369 },
+ { 0x1ebe, 3, 1371 },
+ { 0x1ebf, 3, 1374 },
+ { 0x1ec0, 3, 1377 },
+ { 0x1ec1, 3, 1380 },
+ { 0x1ec2, 3, 1383 },
+ { 0x1ec3, 3, 1386 },
+ { 0x1ec4, 3, 1389 },
+ { 0x1ec5, 3, 1392 },
+ { 0x1ec6, 3, 1395 },
+ { 0x1ec7, 3, 1398 },
+ { 0x1ec8, 2, 1401 },
+ { 0x1ec9, 2, 1403 },
+ { 0x1eca, 2, 1405 },
+ { 0x1ecb, 2, 1407 },
+ { 0x1ecc, 2, 1409 },
+ { 0x1ecd, 2, 1411 },
+ { 0x1ece, 2, 1413 },
+ { 0x1ecf, 2, 1415 },
+ { 0x1ed0, 3, 1417 },
+ { 0x1ed1, 3, 1420 },
+ { 0x1ed2, 3, 1423 },
+ { 0x1ed3, 3, 1426 },
+ { 0x1ed4, 3, 1429 },
+ { 0x1ed5, 3, 1432 },
+ { 0x1ed6, 3, 1435 },
+ { 0x1ed7, 3, 1438 },
+ { 0x1ed8, 3, 1441 },
+ { 0x1ed9, 3, 1444 },
+ { 0x1eda, 3, 1447 },
+ { 0x1edb, 3, 1450 },
+ { 0x1edc, 3, 1453 },
+ { 0x1edd, 3, 1456 },
+ { 0x1ede, 3, 1459 },
+ { 0x1edf, 3, 1462 },
+ { 0x1ee0, 3, 1465 },
+ { 0x1ee1, 3, 1468 },
+ { 0x1ee2, 3, 1471 },
+ { 0x1ee3, 3, 1474 },
+ { 0x1ee4, 2, 1477 },
+ { 0x1ee5, 2, 1479 },
+ { 0x1ee6, 2, 1481 },
+ { 0x1ee7, 2, 1483 },
+ { 0x1ee8, 3, 1485 },
+ { 0x1ee9, 3, 1488 },
+ { 0x1eea, 3, 1491 },
+ { 0x1eeb, 3, 1494 },
+ { 0x1eec, 3, 1497 },
+ { 0x1eed, 3, 1500 },
+ { 0x1eee, 3, 1503 },
+ { 0x1eef, 3, 1506 },
+ { 0x1ef0, 3, 1509 },
+ { 0x1ef1, 3, 1512 },
+ { 0x1ef2, 2, 1515 },
+ { 0x1ef3, 2, 1517 },
+ { 0x1ef4, 2, 1519 },
+ { 0x1ef5, 2, 1521 },
+ { 0x1ef6, 2, 1523 },
+ { 0x1ef7, 2, 1525 },
+ { 0x1ef8, 2, 1527 },
+ { 0x1ef9, 2, 1529 },
+ { 0x1f00, 2, 1531 },
+ { 0x1f01, 2, 1533 },
+ { 0x1f02, 3, 1535 },
+ { 0x1f03, 3, 1538 },
+ { 0x1f04, 3, 1541 },
+ { 0x1f05, 3, 1544 },
+ { 0x1f06, 3, 1547 },
+ { 0x1f07, 3, 1550 },
+ { 0x1f08, 2, 1553 },
+ { 0x1f09, 2, 1555 },
+ { 0x1f0a, 3, 1557 },
+ { 0x1f0b, 3, 1560 },
+ { 0x1f0c, 3, 1563 },
+ { 0x1f0d, 3, 1566 },
+ { 0x1f0e, 3, 1569 },
+ { 0x1f0f, 3, 1572 },
+ { 0x1f10, 2, 1575 },
+ { 0x1f11, 2, 1577 },
+ { 0x1f12, 3, 1579 },
+ { 0x1f13, 3, 1582 },
+ { 0x1f14, 3, 1585 },
+ { 0x1f15, 3, 1588 },
+ { 0x1f18, 2, 1591 },
+ { 0x1f19, 2, 1593 },
+ { 0x1f1a, 3, 1595 },
+ { 0x1f1b, 3, 1598 },
+ { 0x1f1c, 3, 1601 },
+ { 0x1f1d, 3, 1604 },
+ { 0x1f20, 2, 1607 },
+ { 0x1f21, 2, 1609 },
+ { 0x1f22, 3, 1611 },
+ { 0x1f23, 3, 1614 },
+ { 0x1f24, 3, 1617 },
+ { 0x1f25, 3, 1620 },
+ { 0x1f26, 3, 1623 },
+ { 0x1f27, 3, 1626 },
+ { 0x1f28, 2, 1629 },
+ { 0x1f29, 2, 1631 },
+ { 0x1f2a, 3, 1633 },
+ { 0x1f2b, 3, 1636 },
+ { 0x1f2c, 3, 1639 },
+ { 0x1f2d, 3, 1642 },
+ { 0x1f2e, 3, 1645 },
+ { 0x1f2f, 3, 1648 },
+ { 0x1f30, 2, 1651 },
+ { 0x1f31, 2, 1653 },
+ { 0x1f32, 3, 1655 },
+ { 0x1f33, 3, 1658 },
+ { 0x1f34, 3, 1661 },
+ { 0x1f35, 3, 1664 },
+ { 0x1f36, 3, 1667 },
+ { 0x1f37, 3, 1670 },
+ { 0x1f38, 2, 1673 },
+ { 0x1f39, 2, 1675 },
+ { 0x1f3a, 3, 1677 },
+ { 0x1f3b, 3, 1680 },
+ { 0x1f3c, 3, 1683 },
+ { 0x1f3d, 3, 1686 },
+ { 0x1f3e, 3, 1689 },
+ { 0x1f3f, 3, 1692 },
+ { 0x1f40, 2, 1695 },
+ { 0x1f41, 2, 1697 },
+ { 0x1f42, 3, 1699 },
+ { 0x1f43, 3, 1702 },
+ { 0x1f44, 3, 1705 },
+ { 0x1f45, 3, 1708 },
+ { 0x1f48, 2, 1711 },
+ { 0x1f49, 2, 1713 },
+ { 0x1f4a, 3, 1715 },
+ { 0x1f4b, 3, 1718 },
+ { 0x1f4c, 3, 1721 },
+ { 0x1f4d, 3, 1724 },
+ { 0x1f50, 2, 1727 },
+ { 0x1f51, 2, 1729 },
+ { 0x1f52, 3, 1731 },
+ { 0x1f53, 3, 1734 },
+ { 0x1f54, 3, 1737 },
+ { 0x1f55, 3, 1740 },
+ { 0x1f56, 3, 1743 },
+ { 0x1f57, 3, 1746 },
+ { 0x1f59, 2, 1749 },
+ { 0x1f5b, 3, 1751 },
+ { 0x1f5d, 3, 1754 },
+ { 0x1f5f, 3, 1757 },
+ { 0x1f60, 2, 1760 },
+ { 0x1f61, 2, 1762 },
+ { 0x1f62, 3, 1764 },
+ { 0x1f63, 3, 1767 },
+ { 0x1f64, 3, 1770 },
+ { 0x1f65, 3, 1773 },
+ { 0x1f66, 3, 1776 },
+ { 0x1f67, 3, 1779 },
+ { 0x1f68, 2, 1782 },
+ { 0x1f69, 2, 1784 },
+ { 0x1f6a, 3, 1786 },
+ { 0x1f6b, 3, 1789 },
+ { 0x1f6c, 3, 1792 },
+ { 0x1f6d, 3, 1795 },
+ { 0x1f6e, 3, 1798 },
+ { 0x1f6f, 3, 1801 },
+ { 0x1f70, 2, 1804 },
+ { 0x1f71, 2, 647 },
+ { 0x1f72, 2, 1806 },
+ { 0x1f73, 2, 649 },
+ { 0x1f74, 2, 1808 },
+ { 0x1f75, 2, 651 },
+ { 0x1f76, 2, 1810 },
+ { 0x1f77, 2, 653 },
+ { 0x1f78, 2, 1812 },
+ { 0x1f79, 2, 662 },
+ { 0x1f7a, 2, 1814 },
+ { 0x1f7b, 2, 664 },
+ { 0x1f7c, 2, 1816 },
+ { 0x1f7d, 2, 666 },
+ { 0x1f80, 3, 1818 },
+ { 0x1f81, 3, 1821 },
+ { 0x1f82, 4, 1824 },
+ { 0x1f83, 4, 1828 },
+ { 0x1f84, 4, 1832 },
+ { 0x1f85, 4, 1836 },
+ { 0x1f86, 4, 1840 },
+ { 0x1f87, 4, 1844 },
+ { 0x1f88, 3, 1848 },
+ { 0x1f89, 3, 1851 },
+ { 0x1f8a, 4, 1854 },
+ { 0x1f8b, 4, 1858 },
+ { 0x1f8c, 4, 1862 },
+ { 0x1f8d, 4, 1866 },
+ { 0x1f8e, 4, 1870 },
+ { 0x1f8f, 4, 1874 },
+ { 0x1f90, 3, 1878 },
+ { 0x1f91, 3, 1881 },
+ { 0x1f92, 4, 1884 },
+ { 0x1f93, 4, 1888 },
+ { 0x1f94, 4, 1892 },
+ { 0x1f95, 4, 1896 },
+ { 0x1f96, 4, 1900 },
+ { 0x1f97, 4, 1904 },
+ { 0x1f98, 3, 1908 },
+ { 0x1f99, 3, 1911 },
+ { 0x1f9a, 4, 1914 },
+ { 0x1f9b, 4, 1918 },
+ { 0x1f9c, 4, 1922 },
+ { 0x1f9d, 4, 1926 },
+ { 0x1f9e, 4, 1930 },
+ { 0x1f9f, 4, 1934 },
+ { 0x1fa0, 3, 1938 },
+ { 0x1fa1, 3, 1941 },
+ { 0x1fa2, 4, 1944 },
+ { 0x1fa3, 4, 1948 },
+ { 0x1fa4, 4, 1952 },
+ { 0x1fa5, 4, 1956 },
+ { 0x1fa6, 4, 1960 },
+ { 0x1fa7, 4, 1964 },
+ { 0x1fa8, 3, 1968 },
+ { 0x1fa9, 3, 1971 },
+ { 0x1faa, 4, 1974 },
+ { 0x1fab, 4, 1978 },
+ { 0x1fac, 4, 1982 },
+ { 0x1fad, 4, 1986 },
+ { 0x1fae, 4, 1990 },
+ { 0x1faf, 4, 1994 },
+ { 0x1fb0, 2, 1998 },
+ { 0x1fb1, 2, 2000 },
+ { 0x1fb2, 3, 2002 },
+ { 0x1fb3, 2, 2005 },
+ { 0x1fb4, 3, 2007 },
+ { 0x1fb6, 2, 2010 },
+ { 0x1fb7, 3, 2012 },
+ { 0x1fb8, 2, 2015 },
+ { 0x1fb9, 2, 2017 },
+ { 0x1fba, 2, 2019 },
+ { 0x1fbb, 2, 625 },
+ { 0x1fbc, 2, 2021 },
+ { 0x1fbd, 2, 2023 },
+ { 0x1fbe, 1, 2025 },
+ { 0x1fbf, 2, 2023 },
+ { 0x1fc0, 2, 2026 },
+ { 0x1fc1, 3, 2028 },
+ { 0x1fc2, 3, 2031 },
+ { 0x1fc3, 2, 2034 },
+ { 0x1fc4, 3, 2036 },
+ { 0x1fc6, 2, 2039 },
+ { 0x1fc7, 3, 2041 },
+ { 0x1fc8, 2, 2044 },
+ { 0x1fc9, 2, 628 },
+ { 0x1fca, 2, 2046 },
+ { 0x1fcb, 2, 630 },
+ { 0x1fcc, 2, 2048 },
+ { 0x1fcd, 3, 2050 },
+ { 0x1fce, 3, 2053 },
+ { 0x1fcf, 3, 2056 },
+ { 0x1fd0, 2, 2059 },
+ { 0x1fd1, 2, 2061 },
+ { 0x1fd2, 3, 2063 },
+ { 0x1fd3, 3, 640 },
+ { 0x1fd6, 2, 2066 },
+ { 0x1fd7, 3, 2068 },
+ { 0x1fd8, 2, 2071 },
+ { 0x1fd9, 2, 2073 },
+ { 0x1fda, 2, 2075 },
+ { 0x1fdb, 2, 632 },
+ { 0x1fdd, 3, 2077 },
+ { 0x1fde, 3, 2080 },
+ { 0x1fdf, 3, 2083 },
+ { 0x1fe0, 2, 2086 },
+ { 0x1fe1, 2, 2088 },
+ { 0x1fe2, 3, 2090 },
+ { 0x1fe3, 3, 655 },
+ { 0x1fe4, 2, 2093 },
+ { 0x1fe5, 2, 2095 },
+ { 0x1fe6, 2, 2097 },
+ { 0x1fe7, 3, 2099 },
+ { 0x1fe8, 2, 2102 },
+ { 0x1fe9, 2, 2104 },
+ { 0x1fea, 2, 2106 },
+ { 0x1feb, 2, 636 },
+ { 0x1fec, 2, 2108 },
+ { 0x1fed, 3, 2110 },
+ { 0x1fee, 3, 622 },
+ { 0x1fef, 1, 2113 },
+ { 0x1ff2, 3, 2114 },
+ { 0x1ff3, 2, 2117 },
+ { 0x1ff4, 3, 2119 },
+ { 0x1ff6, 2, 2122 },
+ { 0x1ff7, 3, 2124 },
+ { 0x1ff8, 2, 2127 },
+ { 0x1ff9, 2, 634 },
+ { 0x1ffa, 2, 2129 },
+ { 0x1ffb, 2, 638 },
+ { 0x1ffc, 2, 2131 },
+ { 0x1ffd, 2, 8 },
+ { 0x1ffe, 2, 2133 },
+ { 0x2000, 1, 0 },
+ { 0x2001, 1, 0 },
+ { 0x2002, 1, 0 },
+ { 0x2003, 1, 0 },
+ { 0x2004, 1, 0 },
+ { 0x2005, 1, 0 },
+ { 0x2006, 1, 0 },
+ { 0x2007, 1, 0 },
+ { 0x2008, 1, 0 },
+ { 0x2009, 1, 0 },
+ { 0x200a, 1, 0 },
+ { 0x2011, 1, 2135 },
+ { 0x2017, 2, 2136 },
+ { 0x2024, 1, 2138 },
+ { 0x2025, 2, 2139 },
+ { 0x2026, 3, 2141 },
+ { 0x202f, 1, 0 },
+ { 0x2033, 2, 2144 },
+ { 0x2034, 3, 2146 },
+ { 0x2036, 2, 2149 },
+ { 0x2037, 3, 2151 },
+ { 0x203c, 2, 2154 },
+ { 0x203e, 2, 2156 },
+ { 0x2047, 2, 2158 },
+ { 0x2048, 2, 2160 },
+ { 0x2049, 2, 2162 },
+ { 0x2057, 4, 2164 },
+ { 0x205f, 1, 0 },
+ { 0x2070, 1, 2168 },
+ { 0x2071, 1, 2169 },
+ { 0x2074, 1, 2170 },
+ { 0x2075, 1, 2171 },
+ { 0x2076, 1, 2172 },
+ { 0x2077, 1, 2173 },
+ { 0x2078, 1, 2174 },
+ { 0x2079, 1, 2175 },
+ { 0x207a, 1, 2176 },
+ { 0x207b, 1, 2177 },
+ { 0x207c, 1, 2178 },
+ { 0x207d, 1, 2179 },
+ { 0x207e, 1, 2180 },
+ { 0x207f, 1, 2181 },
+ { 0x2080, 1, 2168 },
+ { 0x2081, 1, 13 },
+ { 0x2082, 1, 6 },
+ { 0x2083, 1, 7 },
+ { 0x2084, 1, 2170 },
+ { 0x2085, 1, 2171 },
+ { 0x2086, 1, 2172 },
+ { 0x2087, 1, 2173 },
+ { 0x2088, 1, 2174 },
+ { 0x2089, 1, 2175 },
+ { 0x208a, 1, 2176 },
+ { 0x208b, 1, 2177 },
+ { 0x208c, 1, 2178 },
+ { 0x208d, 1, 2179 },
+ { 0x208e, 1, 2180 },
+ { 0x20a8, 2, 2182 },
+ { 0x2100, 3, 2184 },
+ { 0x2101, 3, 2187 },
+ { 0x2102, 1, 2190 },
+ { 0x2103, 2, 2191 },
+ { 0x2105, 3, 2193 },
+ { 0x2106, 3, 2196 },
+ { 0x2107, 1, 2199 },
+ { 0x2109, 2, 2200 },
+ { 0x210a, 1, 2202 },
+ { 0x210b, 1, 2203 },
+ { 0x210c, 1, 2203 },
+ { 0x210d, 1, 2203 },
+ { 0x210e, 1, 588 },
+ { 0x210f, 1, 2204 },
+ { 0x2110, 1, 2205 },
+ { 0x2111, 1, 2205 },
+ { 0x2112, 1, 2206 },
+ { 0x2113, 1, 610 },
+ { 0x2115, 1, 2207 },
+ { 0x2116, 2, 2208 },
+ { 0x2119, 1, 2210 },
+ { 0x211a, 1, 2211 },
+ { 0x211b, 1, 2212 },
+ { 0x211c, 1, 2212 },
+ { 0x211d, 1, 2212 },
+ { 0x2120, 2, 2213 },
+ { 0x2121, 3, 2215 },
+ { 0x2122, 2, 2218 },
+ { 0x2124, 1, 2220 },
+ { 0x2126, 1, 2221 },
+ { 0x2128, 1, 2220 },
+ { 0x212a, 1, 2222 },
+ { 0x212b, 2, 34 },
+ { 0x212c, 1, 2223 },
+ { 0x212d, 1, 2190 },
+ { 0x212f, 1, 2224 },
+ { 0x2130, 1, 2225 },
+ { 0x2131, 1, 2226 },
+ { 0x2133, 1, 2227 },
+ { 0x2134, 1, 14 },
+ { 0x2135, 1, 2228 },
+ { 0x2136, 1, 2229 },
+ { 0x2137, 1, 2230 },
+ { 0x2138, 1, 2231 },
+ { 0x2139, 1, 2169 },
+ { 0x213d, 1, 2232 },
+ { 0x213e, 1, 2233 },
+ { 0x213f, 1, 2234 },
+ { 0x2140, 1, 2235 },
+ { 0x2145, 1, 2236 },
+ { 0x2146, 1, 2237 },
+ { 0x2147, 1, 2224 },
+ { 0x2148, 1, 2169 },
+ { 0x2149, 1, 590 },
+ { 0x2153, 3, 2238 },
+ { 0x2154, 3, 2241 },
+ { 0x2155, 3, 2244 },
+ { 0x2156, 3, 2247 },
+ { 0x2157, 3, 2250 },
+ { 0x2158, 3, 2253 },
+ { 0x2159, 3, 2256 },
+ { 0x215a, 3, 2259 },
+ { 0x215b, 3, 2262 },
+ { 0x215c, 3, 2265 },
+ { 0x215d, 3, 2268 },
+ { 0x215e, 3, 2271 },
+ { 0x215f, 2, 2274 },
+ { 0x2160, 1, 2205 },
+ { 0x2161, 2, 2276 },
+ { 0x2162, 3, 2278 },
+ { 0x2163, 2, 2281 },
+ { 0x2164, 1, 2283 },
+ { 0x2165, 2, 2284 },
+ { 0x2166, 3, 2286 },
+ { 0x2167, 4, 2289 },
+ { 0x2168, 2, 2293 },
+ { 0x2169, 1, 2295 },
+ { 0x216a, 2, 2296 },
+ { 0x216b, 3, 2298 },
+ { 0x216c, 1, 2206 },
+ { 0x216d, 1, 2190 },
+ { 0x216e, 1, 2236 },
+ { 0x216f, 1, 2227 },
+ { 0x2170, 1, 2169 },
+ { 0x2171, 2, 2301 },
+ { 0x2172, 3, 2303 },
+ { 0x2173, 2, 2306 },
+ { 0x2174, 1, 2308 },
+ { 0x2175, 2, 2309 },
+ { 0x2176, 3, 2311 },
+ { 0x2177, 4, 2314 },
+ { 0x2178, 2, 2318 },
+ { 0x2179, 1, 611 },
+ { 0x217a, 2, 2320 },
+ { 0x217b, 3, 2322 },
+ { 0x217c, 1, 610 },
+ { 0x217d, 1, 2325 },
+ { 0x217e, 1, 2237 },
+ { 0x217f, 1, 2326 },
+ { 0x219a, 2, 2327 },
+ { 0x219b, 2, 2329 },
+ { 0x21ae, 2, 2331 },
+ { 0x21cd, 2, 2333 },
+ { 0x21ce, 2, 2335 },
+ { 0x21cf, 2, 2337 },
+ { 0x2204, 2, 2339 },
+ { 0x2209, 2, 2341 },
+ { 0x220c, 2, 2343 },
+ { 0x2224, 2, 2345 },
+ { 0x2226, 2, 2347 },
+ { 0x222c, 2, 2349 },
+ { 0x222d, 3, 2351 },
+ { 0x222f, 2, 2354 },
+ { 0x2230, 3, 2356 },
+ { 0x2241, 2, 2359 },
+ { 0x2244, 2, 2361 },
+ { 0x2247, 2, 2363 },
+ { 0x2249, 2, 2365 },
+ { 0x2260, 2, 2367 },
+ { 0x2262, 2, 2369 },
+ { 0x226d, 2, 2371 },
+ { 0x226e, 2, 2373 },
+ { 0x226f, 2, 2375 },
+ { 0x2270, 2, 2377 },
+ { 0x2271, 2, 2379 },
+ { 0x2274, 2, 2381 },
+ { 0x2275, 2, 2383 },
+ { 0x2278, 2, 2385 },
+ { 0x2279, 2, 2387 },
+ { 0x2280, 2, 2389 },
+ { 0x2281, 2, 2391 },
+ { 0x2284, 2, 2393 },
+ { 0x2285, 2, 2395 },
+ { 0x2288, 2, 2397 },
+ { 0x2289, 2, 2399 },
+ { 0x22ac, 2, 2401 },
+ { 0x22ad, 2, 2403 },
+ { 0x22ae, 2, 2405 },
+ { 0x22af, 2, 2407 },
+ { 0x22e0, 2, 2409 },
+ { 0x22e1, 2, 2411 },
+ { 0x22e2, 2, 2413 },
+ { 0x22e3, 2, 2415 },
+ { 0x22ea, 2, 2417 },
+ { 0x22eb, 2, 2419 },
+ { 0x22ec, 2, 2421 },
+ { 0x22ed, 2, 2423 },
+ { 0x2329, 1, 2425 },
+ { 0x232a, 1, 2426 },
+ { 0x2460, 1, 13 },
+ { 0x2461, 1, 6 },
+ { 0x2462, 1, 7 },
+ { 0x2463, 1, 2170 },
+ { 0x2464, 1, 2171 },
+ { 0x2465, 1, 2172 },
+ { 0x2466, 1, 2173 },
+ { 0x2467, 1, 2174 },
+ { 0x2468, 1, 2175 },
+ { 0x2469, 2, 2427 },
+ { 0x246a, 2, 2429 },
+ { 0x246b, 2, 2431 },
+ { 0x246c, 2, 2433 },
+ { 0x246d, 2, 2435 },
+ { 0x246e, 2, 2437 },
+ { 0x246f, 2, 2439 },
+ { 0x2470, 2, 2441 },
+ { 0x2471, 2, 2443 },
+ { 0x2472, 2, 2445 },
+ { 0x2473, 2, 2447 },
+ { 0x2474, 3, 2449 },
+ { 0x2475, 3, 2452 },
+ { 0x2476, 3, 2455 },
+ { 0x2477, 3, 2458 },
+ { 0x2478, 3, 2461 },
+ { 0x2479, 3, 2464 },
+ { 0x247a, 3, 2467 },
+ { 0x247b, 3, 2470 },
+ { 0x247c, 3, 2473 },
+ { 0x247d, 4, 2476 },
+ { 0x247e, 4, 2480 },
+ { 0x247f, 4, 2484 },
+ { 0x2480, 4, 2488 },
+ { 0x2481, 4, 2492 },
+ { 0x2482, 4, 2496 },
+ { 0x2483, 4, 2500 },
+ { 0x2484, 4, 2504 },
+ { 0x2485, 4, 2508 },
+ { 0x2486, 4, 2512 },
+ { 0x2487, 4, 2516 },
+ { 0x2488, 2, 2520 },
+ { 0x2489, 2, 2522 },
+ { 0x248a, 2, 2524 },
+ { 0x248b, 2, 2526 },
+ { 0x248c, 2, 2528 },
+ { 0x248d, 2, 2530 },
+ { 0x248e, 2, 2532 },
+ { 0x248f, 2, 2534 },
+ { 0x2490, 2, 2536 },
+ { 0x2491, 3, 2538 },
+ { 0x2492, 3, 2541 },
+ { 0x2493, 3, 2544 },
+ { 0x2494, 3, 2547 },
+ { 0x2495, 3, 2550 },
+ { 0x2496, 3, 2553 },
+ { 0x2497, 3, 2556 },
+ { 0x2498, 3, 2559 },
+ { 0x2499, 3, 2562 },
+ { 0x249a, 3, 2565 },
+ { 0x249b, 3, 2568 },
+ { 0x249c, 3, 2571 },
+ { 0x249d, 3, 2574 },
+ { 0x249e, 3, 2577 },
+ { 0x249f, 3, 2580 },
+ { 0x24a0, 3, 2583 },
+ { 0x24a1, 3, 2586 },
+ { 0x24a2, 3, 2589 },
+ { 0x24a3, 3, 2592 },
+ { 0x24a4, 3, 2595 },
+ { 0x24a5, 3, 2598 },
+ { 0x24a6, 3, 2601 },
+ { 0x24a7, 3, 2604 },
+ { 0x24a8, 3, 2607 },
+ { 0x24a9, 3, 2610 },
+ { 0x24aa, 3, 2613 },
+ { 0x24ab, 3, 2616 },
+ { 0x24ac, 3, 2619 },
+ { 0x24ad, 3, 2622 },
+ { 0x24ae, 3, 2625 },
+ { 0x24af, 3, 2628 },
+ { 0x24b0, 3, 2631 },
+ { 0x24b1, 3, 2634 },
+ { 0x24b2, 3, 2637 },
+ { 0x24b3, 3, 2640 },
+ { 0x24b4, 3, 2643 },
+ { 0x24b5, 3, 2646 },
+ { 0x24b6, 1, 2649 },
+ { 0x24b7, 1, 2223 },
+ { 0x24b8, 1, 2190 },
+ { 0x24b9, 1, 2236 },
+ { 0x24ba, 1, 2225 },
+ { 0x24bb, 1, 2226 },
+ { 0x24bc, 1, 2650 },
+ { 0x24bd, 1, 2203 },
+ { 0x24be, 1, 2205 },
+ { 0x24bf, 1, 2651 },
+ { 0x24c0, 1, 2222 },
+ { 0x24c1, 1, 2206 },
+ { 0x24c2, 1, 2227 },
+ { 0x24c3, 1, 2207 },
+ { 0x24c4, 1, 2652 },
+ { 0x24c5, 1, 2210 },
+ { 0x24c6, 1, 2211 },
+ { 0x24c7, 1, 2212 },
+ { 0x24c8, 1, 2653 },
+ { 0x24c9, 1, 2654 },
+ { 0x24ca, 1, 2655 },
+ { 0x24cb, 1, 2283 },
+ { 0x24cc, 1, 2656 },
+ { 0x24cd, 1, 2295 },
+ { 0x24ce, 1, 2657 },
+ { 0x24cf, 1, 2220 },
+ { 0x24d0, 1, 3 },
+ { 0x24d1, 1, 2658 },
+ { 0x24d2, 1, 2325 },
+ { 0x24d3, 1, 2237 },
+ { 0x24d4, 1, 2224 },
+ { 0x24d5, 1, 2659 },
+ { 0x24d6, 1, 2202 },
+ { 0x24d7, 1, 588 },
+ { 0x24d8, 1, 2169 },
+ { 0x24d9, 1, 590 },
+ { 0x24da, 1, 2660 },
+ { 0x24db, 1, 610 },
+ { 0x24dc, 1, 2326 },
+ { 0x24dd, 1, 2181 },
+ { 0x24de, 1, 14 },
+ { 0x24df, 1, 2661 },
+ { 0x24e0, 1, 2662 },
+ { 0x24e1, 1, 591 },
+ { 0x24e2, 1, 356 },
+ { 0x24e3, 1, 2663 },
+ { 0x24e4, 1, 2664 },
+ { 0x24e5, 1, 2308 },
+ { 0x24e6, 1, 595 },
+ { 0x24e7, 1, 611 },
+ { 0x24e8, 1, 596 },
+ { 0x24e9, 1, 2665 },
+ { 0x24ea, 1, 2168 },
+ { 0x2a0c, 4, 2666 },
+ { 0x2a74, 3, 2670 },
+ { 0x2a75, 2, 2673 },
+ { 0x2a76, 3, 2675 },
+ { 0x2adc, 2, 2678 },
+ { 0x2e9f, 1, 2680 },
+ { 0x2ef3, 1, 2681 },
+ { 0x2f00, 1, 2682 },
+ { 0x2f01, 1, 2683 },
+ { 0x2f02, 1, 2684 },
+ { 0x2f03, 1, 2685 },
+ { 0x2f04, 1, 2686 },
+ { 0x2f05, 1, 2687 },
+ { 0x2f06, 1, 2688 },
+ { 0x2f07, 1, 2689 },
+ { 0x2f08, 1, 2690 },
+ { 0x2f09, 1, 2691 },
+ { 0x2f0a, 1, 2692 },
+ { 0x2f0b, 1, 2693 },
+ { 0x2f0c, 1, 2694 },
+ { 0x2f0d, 1, 2695 },
+ { 0x2f0e, 1, 2696 },
+ { 0x2f0f, 1, 2697 },
+ { 0x2f10, 1, 2698 },
+ { 0x2f11, 1, 2699 },
+ { 0x2f12, 1, 2700 },
+ { 0x2f13, 1, 2701 },
+ { 0x2f14, 1, 2702 },
+ { 0x2f15, 1, 2703 },
+ { 0x2f16, 1, 2704 },
+ { 0x2f17, 1, 2705 },
+ { 0x2f18, 1, 2706 },
+ { 0x2f19, 1, 2707 },
+ { 0x2f1a, 1, 2708 },
+ { 0x2f1b, 1, 2709 },
+ { 0x2f1c, 1, 2710 },
+ { 0x2f1d, 1, 2711 },
+ { 0x2f1e, 1, 2712 },
+ { 0x2f1f, 1, 2713 },
+ { 0x2f20, 1, 2714 },
+ { 0x2f21, 1, 2715 },
+ { 0x2f22, 1, 2716 },
+ { 0x2f23, 1, 2717 },
+ { 0x2f24, 1, 2718 },
+ { 0x2f25, 1, 2719 },
+ { 0x2f26, 1, 2720 },
+ { 0x2f27, 1, 2721 },
+ { 0x2f28, 1, 2722 },
+ { 0x2f29, 1, 2723 },
+ { 0x2f2a, 1, 2724 },
+ { 0x2f2b, 1, 2725 },
+ { 0x2f2c, 1, 2726 },
+ { 0x2f2d, 1, 2727 },
+ { 0x2f2e, 1, 2728 },
+ { 0x2f2f, 1, 2729 },
+ { 0x2f30, 1, 2730 },
+ { 0x2f31, 1, 2731 },
+ { 0x2f32, 1, 2732 },
+ { 0x2f33, 1, 2733 },
+ { 0x2f34, 1, 2734 },
+ { 0x2f35, 1, 2735 },
+ { 0x2f36, 1, 2736 },
+ { 0x2f37, 1, 2737 },
+ { 0x2f38, 1, 2738 },
+ { 0x2f39, 1, 2739 },
+ { 0x2f3a, 1, 2740 },
+ { 0x2f3b, 1, 2741 },
+ { 0x2f3c, 1, 2742 },
+ { 0x2f3d, 1, 2743 },
+ { 0x2f3e, 1, 2744 },
+ { 0x2f3f, 1, 2745 },
+ { 0x2f40, 1, 2746 },
+ { 0x2f41, 1, 2747 },
+ { 0x2f42, 1, 2748 },
+ { 0x2f43, 1, 2749 },
+ { 0x2f44, 1, 2750 },
+ { 0x2f45, 1, 2751 },
+ { 0x2f46, 1, 2752 },
+ { 0x2f47, 1, 2753 },
+ { 0x2f48, 1, 2754 },
+ { 0x2f49, 1, 2755 },
+ { 0x2f4a, 1, 2756 },
+ { 0x2f4b, 1, 2757 },
+ { 0x2f4c, 1, 2758 },
+ { 0x2f4d, 1, 2759 },
+ { 0x2f4e, 1, 2760 },
+ { 0x2f4f, 1, 2761 },
+ { 0x2f50, 1, 2762 },
+ { 0x2f51, 1, 2763 },
+ { 0x2f52, 1, 2764 },
+ { 0x2f53, 1, 2765 },
+ { 0x2f54, 1, 2766 },
+ { 0x2f55, 1, 2767 },
+ { 0x2f56, 1, 2768 },
+ { 0x2f57, 1, 2769 },
+ { 0x2f58, 1, 2770 },
+ { 0x2f59, 1, 2771 },
+ { 0x2f5a, 1, 2772 },
+ { 0x2f5b, 1, 2773 },
+ { 0x2f5c, 1, 2774 },
+ { 0x2f5d, 1, 2775 },
+ { 0x2f5e, 1, 2776 },
+ { 0x2f5f, 1, 2777 },
+ { 0x2f60, 1, 2778 },
+ { 0x2f61, 1, 2779 },
+ { 0x2f62, 1, 2780 },
+ { 0x2f63, 1, 2781 },
+ { 0x2f64, 1, 2782 },
+ { 0x2f65, 1, 2783 },
+ { 0x2f66, 1, 2784 },
+ { 0x2f67, 1, 2785 },
+ { 0x2f68, 1, 2786 },
+ { 0x2f69, 1, 2787 },
+ { 0x2f6a, 1, 2788 },
+ { 0x2f6b, 1, 2789 },
+ { 0x2f6c, 1, 2790 },
+ { 0x2f6d, 1, 2791 },
+ { 0x2f6e, 1, 2792 },
+ { 0x2f6f, 1, 2793 },
+ { 0x2f70, 1, 2794 },
+ { 0x2f71, 1, 2795 },
+ { 0x2f72, 1, 2796 },
+ { 0x2f73, 1, 2797 },
+ { 0x2f74, 1, 2798 },
+ { 0x2f75, 1, 2799 },
+ { 0x2f76, 1, 2800 },
+ { 0x2f77, 1, 2801 },
+ { 0x2f78, 1, 2802 },
+ { 0x2f79, 1, 2803 },
+ { 0x2f7a, 1, 2804 },
+ { 0x2f7b, 1, 2805 },
+ { 0x2f7c, 1, 2806 },
+ { 0x2f7d, 1, 2807 },
+ { 0x2f7e, 1, 2808 },
+ { 0x2f7f, 1, 2809 },
+ { 0x2f80, 1, 2810 },
+ { 0x2f81, 1, 2811 },
+ { 0x2f82, 1, 2812 },
+ { 0x2f83, 1, 2813 },
+ { 0x2f84, 1, 2814 },
+ { 0x2f85, 1, 2815 },
+ { 0x2f86, 1, 2816 },
+ { 0x2f87, 1, 2817 },
+ { 0x2f88, 1, 2818 },
+ { 0x2f89, 1, 2819 },
+ { 0x2f8a, 1, 2820 },
+ { 0x2f8b, 1, 2821 },
+ { 0x2f8c, 1, 2822 },
+ { 0x2f8d, 1, 2823 },
+ { 0x2f8e, 1, 2824 },
+ { 0x2f8f, 1, 2825 },
+ { 0x2f90, 1, 2826 },
+ { 0x2f91, 1, 2827 },
+ { 0x2f92, 1, 2828 },
+ { 0x2f93, 1, 2829 },
+ { 0x2f94, 1, 2830 },
+ { 0x2f95, 1, 2831 },
+ { 0x2f96, 1, 2832 },
+ { 0x2f97, 1, 2833 },
+ { 0x2f98, 1, 2834 },
+ { 0x2f99, 1, 2835 },
+ { 0x2f9a, 1, 2836 },
+ { 0x2f9b, 1, 2837 },
+ { 0x2f9c, 1, 2838 },
+ { 0x2f9d, 1, 2839 },
+ { 0x2f9e, 1, 2840 },
+ { 0x2f9f, 1, 2841 },
+ { 0x2fa0, 1, 2842 },
+ { 0x2fa1, 1, 2843 },
+ { 0x2fa2, 1, 2844 },
+ { 0x2fa3, 1, 2845 },
+ { 0x2fa4, 1, 2846 },
+ { 0x2fa5, 1, 2847 },
+ { 0x2fa6, 1, 2848 },
+ { 0x2fa7, 1, 2849 },
+ { 0x2fa8, 1, 2850 },
+ { 0x2fa9, 1, 2851 },
+ { 0x2faa, 1, 2852 },
+ { 0x2fab, 1, 2853 },
+ { 0x2fac, 1, 2854 },
+ { 0x2fad, 1, 2855 },
+ { 0x2fae, 1, 2856 },
+ { 0x2faf, 1, 2857 },
+ { 0x2fb0, 1, 2858 },
+ { 0x2fb1, 1, 2859 },
+ { 0x2fb2, 1, 2860 },
+ { 0x2fb3, 1, 2861 },
+ { 0x2fb4, 1, 2862 },
+ { 0x2fb5, 1, 2863 },
+ { 0x2fb6, 1, 2864 },
+ { 0x2fb7, 1, 2865 },
+ { 0x2fb8, 1, 2866 },
+ { 0x2fb9, 1, 2867 },
+ { 0x2fba, 1, 2868 },
+ { 0x2fbb, 1, 2869 },
+ { 0x2fbc, 1, 2870 },
+ { 0x2fbd, 1, 2871 },
+ { 0x2fbe, 1, 2872 },
+ { 0x2fbf, 1, 2873 },
+ { 0x2fc0, 1, 2874 },
+ { 0x2fc1, 1, 2875 },
+ { 0x2fc2, 1, 2876 },
+ { 0x2fc3, 1, 2877 },
+ { 0x2fc4, 1, 2878 },
+ { 0x2fc5, 1, 2879 },
+ { 0x2fc6, 1, 2880 },
+ { 0x2fc7, 1, 2881 },
+ { 0x2fc8, 1, 2882 },
+ { 0x2fc9, 1, 2883 },
+ { 0x2fca, 1, 2884 },
+ { 0x2fcb, 1, 2885 },
+ { 0x2fcc, 1, 2886 },
+ { 0x2fcd, 1, 2887 },
+ { 0x2fce, 1, 2888 },
+ { 0x2fcf, 1, 2889 },
+ { 0x2fd0, 1, 2890 },
+ { 0x2fd1, 1, 2891 },
+ { 0x2fd2, 1, 2892 },
+ { 0x2fd3, 1, 2893 },
+ { 0x2fd4, 1, 2894 },
+ { 0x2fd5, 1, 2895 },
+ { 0x3000, 1, 0 },
+ { 0x3036, 1, 2896 },
+ { 0x3038, 1, 2705 },
+ { 0x3039, 1, 2897 },
+ { 0x303a, 1, 2898 },
+ { 0x304c, 2, 2899 },
+ { 0x304e, 2, 2901 },
+ { 0x3050, 2, 2903 },
+ { 0x3052, 2, 2905 },
+ { 0x3054, 2, 2907 },
+ { 0x3056, 2, 2909 },
+ { 0x3058, 2, 2911 },
+ { 0x305a, 2, 2913 },
+ { 0x305c, 2, 2915 },
+ { 0x305e, 2, 2917 },
+ { 0x3060, 2, 2919 },
+ { 0x3062, 2, 2921 },
+ { 0x3065, 2, 2923 },
+ { 0x3067, 2, 2925 },
+ { 0x3069, 2, 2927 },
+ { 0x3070, 2, 2929 },
+ { 0x3071, 2, 2931 },
+ { 0x3073, 2, 2933 },
+ { 0x3074, 2, 2935 },
+ { 0x3076, 2, 2937 },
+ { 0x3077, 2, 2939 },
+ { 0x3079, 2, 2941 },
+ { 0x307a, 2, 2943 },
+ { 0x307c, 2, 2945 },
+ { 0x307d, 2, 2947 },
+ { 0x3094, 2, 2949 },
+ { 0x309b, 2, 2951 },
+ { 0x309c, 2, 2953 },
+ { 0x309e, 2, 2955 },
+ { 0x309f, 2, 2957 },
+ { 0x30ac, 2, 2959 },
+ { 0x30ae, 2, 2961 },
+ { 0x30b0, 2, 2963 },
+ { 0x30b2, 2, 2965 },
+ { 0x30b4, 2, 2967 },
+ { 0x30b6, 2, 2969 },
+ { 0x30b8, 2, 2971 },
+ { 0x30ba, 2, 2973 },
+ { 0x30bc, 2, 2975 },
+ { 0x30be, 2, 2977 },
+ { 0x30c0, 2, 2979 },
+ { 0x30c2, 2, 2981 },
+ { 0x30c5, 2, 2983 },
+ { 0x30c7, 2, 2985 },
+ { 0x30c9, 2, 2987 },
+ { 0x30d0, 2, 2989 },
+ { 0x30d1, 2, 2991 },
+ { 0x30d3, 2, 2993 },
+ { 0x30d4, 2, 2995 },
+ { 0x30d6, 2, 2997 },
+ { 0x30d7, 2, 2999 },
+ { 0x30d9, 2, 3001 },
+ { 0x30da, 2, 3003 },
+ { 0x30dc, 2, 3005 },
+ { 0x30dd, 2, 3007 },
+ { 0x30f4, 2, 3009 },
+ { 0x30f7, 2, 3011 },
+ { 0x30f8, 2, 3013 },
+ { 0x30f9, 2, 3015 },
+ { 0x30fa, 2, 3017 },
+ { 0x30fe, 2, 3019 },
+ { 0x30ff, 2, 3021 },
+ { 0x3131, 1, 3023 },
+ { 0x3132, 1, 3024 },
+ { 0x3133, 1, 3025 },
+ { 0x3134, 1, 3026 },
+ { 0x3135, 1, 3027 },
+ { 0x3136, 1, 3028 },
+ { 0x3137, 1, 3029 },
+ { 0x3138, 1, 3030 },
+ { 0x3139, 1, 3031 },
+ { 0x313a, 1, 3032 },
+ { 0x313b, 1, 3033 },
+ { 0x313c, 1, 3034 },
+ { 0x313d, 1, 3035 },
+ { 0x313e, 1, 3036 },
+ { 0x313f, 1, 3037 },
+ { 0x3140, 1, 3038 },
+ { 0x3141, 1, 3039 },
+ { 0x3142, 1, 3040 },
+ { 0x3143, 1, 3041 },
+ { 0x3144, 1, 3042 },
+ { 0x3145, 1, 3043 },
+ { 0x3146, 1, 3044 },
+ { 0x3147, 1, 3045 },
+ { 0x3148, 1, 3046 },
+ { 0x3149, 1, 3047 },
+ { 0x314a, 1, 3048 },
+ { 0x314b, 1, 3049 },
+ { 0x314c, 1, 3050 },
+ { 0x314d, 1, 3051 },
+ { 0x314e, 1, 3052 },
+ { 0x314f, 1, 3053 },
+ { 0x3150, 1, 3054 },
+ { 0x3151, 1, 3055 },
+ { 0x3152, 1, 3056 },
+ { 0x3153, 1, 3057 },
+ { 0x3154, 1, 3058 },
+ { 0x3155, 1, 3059 },
+ { 0x3156, 1, 3060 },
+ { 0x3157, 1, 3061 },
+ { 0x3158, 1, 3062 },
+ { 0x3159, 1, 3063 },
+ { 0x315a, 1, 3064 },
+ { 0x315b, 1, 3065 },
+ { 0x315c, 1, 3066 },
+ { 0x315d, 1, 3067 },
+ { 0x315e, 1, 3068 },
+ { 0x315f, 1, 3069 },
+ { 0x3160, 1, 3070 },
+ { 0x3161, 1, 3071 },
+ { 0x3162, 1, 3072 },
+ { 0x3163, 1, 3073 },
+ { 0x3164, 1, 3074 },
+ { 0x3165, 1, 3075 },
+ { 0x3166, 1, 3076 },
+ { 0x3167, 1, 3077 },
+ { 0x3168, 1, 3078 },
+ { 0x3169, 1, 3079 },
+ { 0x316a, 1, 3080 },
+ { 0x316b, 1, 3081 },
+ { 0x316c, 1, 3082 },
+ { 0x316d, 1, 3083 },
+ { 0x316e, 1, 3084 },
+ { 0x316f, 1, 3085 },
+ { 0x3170, 1, 3086 },
+ { 0x3171, 1, 3087 },
+ { 0x3172, 1, 3088 },
+ { 0x3173, 1, 3089 },
+ { 0x3174, 1, 3090 },
+ { 0x3175, 1, 3091 },
+ { 0x3176, 1, 3092 },
+ { 0x3177, 1, 3093 },
+ { 0x3178, 1, 3094 },
+ { 0x3179, 1, 3095 },
+ { 0x317a, 1, 3096 },
+ { 0x317b, 1, 3097 },
+ { 0x317c, 1, 3098 },
+ { 0x317d, 1, 3099 },
+ { 0x317e, 1, 3100 },
+ { 0x317f, 1, 3101 },
+ { 0x3180, 1, 3102 },
+ { 0x3181, 1, 3103 },
+ { 0x3182, 1, 3104 },
+ { 0x3183, 1, 3105 },
+ { 0x3184, 1, 3106 },
+ { 0x3185, 1, 3107 },
+ { 0x3186, 1, 3108 },
+ { 0x3187, 1, 3109 },
+ { 0x3188, 1, 3110 },
+ { 0x3189, 1, 3111 },
+ { 0x318a, 1, 3112 },
+ { 0x318b, 1, 3113 },
+ { 0x318c, 1, 3114 },
+ { 0x318d, 1, 3115 },
+ { 0x318e, 1, 3116 },
+ { 0x3192, 1, 2682 },
+ { 0x3193, 1, 2688 },
+ { 0x3194, 1, 3117 },
+ { 0x3195, 1, 3118 },
+ { 0x3196, 1, 3119 },
+ { 0x3197, 1, 3120 },
+ { 0x3198, 1, 3121 },
+ { 0x3199, 1, 3122 },
+ { 0x319a, 1, 2686 },
+ { 0x319b, 1, 3123 },
+ { 0x319c, 1, 3124 },
+ { 0x319d, 1, 3125 },
+ { 0x319e, 1, 3126 },
+ { 0x319f, 1, 2690 },
+ { 0x3200, 3, 3127 },
+ { 0x3201, 3, 3130 },
+ { 0x3202, 3, 3133 },
+ { 0x3203, 3, 3136 },
+ { 0x3204, 3, 3139 },
+ { 0x3205, 3, 3142 },
+ { 0x3206, 3, 3145 },
+ { 0x3207, 3, 3148 },
+ { 0x3208, 3, 3151 },
+ { 0x3209, 3, 3154 },
+ { 0x320a, 3, 3157 },
+ { 0x320b, 3, 3160 },
+ { 0x320c, 3, 3163 },
+ { 0x320d, 3, 3166 },
+ { 0x320e, 4, 3169 },
+ { 0x320f, 4, 3173 },
+ { 0x3210, 4, 3177 },
+ { 0x3211, 4, 3181 },
+ { 0x3212, 4, 3185 },
+ { 0x3213, 4, 3189 },
+ { 0x3214, 4, 3193 },
+ { 0x3215, 4, 3197 },
+ { 0x3216, 4, 3201 },
+ { 0x3217, 4, 3205 },
+ { 0x3218, 4, 3209 },
+ { 0x3219, 4, 3213 },
+ { 0x321a, 4, 3217 },
+ { 0x321b, 4, 3221 },
+ { 0x321c, 4, 3225 },
+ { 0x3220, 3, 3229 },
+ { 0x3221, 3, 3232 },
+ { 0x3222, 3, 3235 },
+ { 0x3223, 3, 3238 },
+ { 0x3224, 3, 3241 },
+ { 0x3225, 3, 3244 },
+ { 0x3226, 3, 3247 },
+ { 0x3227, 3, 3250 },
+ { 0x3228, 3, 3253 },
+ { 0x3229, 3, 3256 },
+ { 0x322a, 3, 3259 },
+ { 0x322b, 3, 3262 },
+ { 0x322c, 3, 3265 },
+ { 0x322d, 3, 3268 },
+ { 0x322e, 3, 3271 },
+ { 0x322f, 3, 3274 },
+ { 0x3230, 3, 3277 },
+ { 0x3231, 3, 3280 },
+ { 0x3232, 3, 3283 },
+ { 0x3233, 3, 3286 },
+ { 0x3234, 3, 3289 },
+ { 0x3235, 3, 3292 },
+ { 0x3236, 3, 3295 },
+ { 0x3237, 3, 3298 },
+ { 0x3238, 3, 3301 },
+ { 0x3239, 3, 3304 },
+ { 0x323a, 3, 3307 },
+ { 0x323b, 3, 3310 },
+ { 0x323c, 3, 3313 },
+ { 0x323d, 3, 3316 },
+ { 0x323e, 3, 3319 },
+ { 0x323f, 3, 3322 },
+ { 0x3240, 3, 3325 },
+ { 0x3241, 3, 3328 },
+ { 0x3242, 3, 3331 },
+ { 0x3243, 3, 3334 },
+ { 0x3251, 2, 3337 },
+ { 0x3252, 2, 3339 },
+ { 0x3253, 2, 3341 },
+ { 0x3254, 2, 3343 },
+ { 0x3255, 2, 3345 },
+ { 0x3256, 2, 3347 },
+ { 0x3257, 2, 3349 },
+ { 0x3258, 2, 3351 },
+ { 0x3259, 2, 3353 },
+ { 0x325a, 2, 3355 },
+ { 0x325b, 2, 3357 },
+ { 0x325c, 2, 3359 },
+ { 0x325d, 2, 3361 },
+ { 0x325e, 2, 3363 },
+ { 0x325f, 2, 3365 },
+ { 0x3260, 1, 3023 },
+ { 0x3261, 1, 3026 },
+ { 0x3262, 1, 3029 },
+ { 0x3263, 1, 3031 },
+ { 0x3264, 1, 3039 },
+ { 0x3265, 1, 3040 },
+ { 0x3266, 1, 3043 },
+ { 0x3267, 1, 3045 },
+ { 0x3268, 1, 3046 },
+ { 0x3269, 1, 3048 },
+ { 0x326a, 1, 3049 },
+ { 0x326b, 1, 3050 },
+ { 0x326c, 1, 3051 },
+ { 0x326d, 1, 3052 },
+ { 0x326e, 2, 3367 },
+ { 0x326f, 2, 3369 },
+ { 0x3270, 2, 3371 },
+ { 0x3271, 2, 3373 },
+ { 0x3272, 2, 3375 },
+ { 0x3273, 2, 3377 },
+ { 0x3274, 2, 3379 },
+ { 0x3275, 2, 3381 },
+ { 0x3276, 2, 3383 },
+ { 0x3277, 2, 3385 },
+ { 0x3278, 2, 3387 },
+ { 0x3279, 2, 3389 },
+ { 0x327a, 2, 3391 },
+ { 0x327b, 2, 3393 },
+ { 0x3280, 1, 2682 },
+ { 0x3281, 1, 2688 },
+ { 0x3282, 1, 3117 },
+ { 0x3283, 1, 3118 },
+ { 0x3284, 1, 3395 },
+ { 0x3285, 1, 3396 },
+ { 0x3286, 1, 3397 },
+ { 0x3287, 1, 2693 },
+ { 0x3288, 1, 3398 },
+ { 0x3289, 1, 2705 },
+ { 0x328a, 1, 2755 },
+ { 0x328b, 1, 2767 },
+ { 0x328c, 1, 2766 },
+ { 0x328d, 1, 2756 },
+ { 0x328e, 1, 2848 },
+ { 0x328f, 1, 2713 },
+ { 0x3290, 1, 2753 },
+ { 0x3291, 1, 3399 },
+ { 0x3292, 1, 3400 },
+ { 0x3293, 1, 3401 },
+ { 0x3294, 1, 3402 },
+ { 0x3295, 1, 3403 },
+ { 0x3296, 1, 3404 },
+ { 0x3297, 1, 3405 },
+ { 0x3298, 1, 3406 },
+ { 0x3299, 1, 3407 },
+ { 0x329a, 1, 3408 },
+ { 0x329b, 1, 2719 },
+ { 0x329c, 1, 3409 },
+ { 0x329d, 1, 3410 },
+ { 0x329e, 1, 3411 },
+ { 0x329f, 1, 3412 },
+ { 0x32a0, 1, 3413 },
+ { 0x32a1, 1, 3414 },
+ { 0x32a2, 1, 3415 },
+ { 0x32a3, 1, 3416 },
+ { 0x32a4, 1, 3119 },
+ { 0x32a5, 1, 3120 },
+ { 0x32a6, 1, 3121 },
+ { 0x32a7, 1, 3417 },
+ { 0x32a8, 1, 3418 },
+ { 0x32a9, 1, 3419 },
+ { 0x32aa, 1, 3420 },
+ { 0x32ab, 1, 3421 },
+ { 0x32ac, 1, 3422 },
+ { 0x32ad, 1, 3423 },
+ { 0x32ae, 1, 3424 },
+ { 0x32af, 1, 3425 },
+ { 0x32b0, 1, 3426 },
+ { 0x32b1, 2, 3427 },
+ { 0x32b2, 2, 3429 },
+ { 0x32b3, 2, 3431 },
+ { 0x32b4, 2, 3433 },
+ { 0x32b5, 2, 3435 },
+ { 0x32b6, 2, 3437 },
+ { 0x32b7, 2, 3439 },
+ { 0x32b8, 2, 3441 },
+ { 0x32b9, 2, 3443 },
+ { 0x32ba, 2, 3445 },
+ { 0x32bb, 2, 3447 },
+ { 0x32bc, 2, 3449 },
+ { 0x32bd, 2, 3451 },
+ { 0x32be, 2, 3453 },
+ { 0x32bf, 2, 3455 },
+ { 0x32c0, 2, 3457 },
+ { 0x32c1, 2, 3459 },
+ { 0x32c2, 2, 3461 },
+ { 0x32c3, 2, 3463 },
+ { 0x32c4, 2, 3465 },
+ { 0x32c5, 2, 3467 },
+ { 0x32c6, 2, 3469 },
+ { 0x32c7, 2, 3471 },
+ { 0x32c8, 2, 3473 },
+ { 0x32c9, 3, 3475 },
+ { 0x32ca, 3, 3478 },
+ { 0x32cb, 3, 3481 },
+ { 0x32d0, 1, 3484 },
+ { 0x32d1, 1, 3485 },
+ { 0x32d2, 1, 3486 },
+ { 0x32d3, 1, 3487 },
+ { 0x32d4, 1, 3488 },
+ { 0x32d5, 1, 3489 },
+ { 0x32d6, 1, 3490 },
+ { 0x32d7, 1, 3491 },
+ { 0x32d8, 1, 3492 },
+ { 0x32d9, 1, 3493 },
+ { 0x32da, 1, 3494 },
+ { 0x32db, 1, 3495 },
+ { 0x32dc, 1, 3496 },
+ { 0x32dd, 1, 3497 },
+ { 0x32de, 1, 3498 },
+ { 0x32df, 1, 3499 },
+ { 0x32e0, 1, 3500 },
+ { 0x32e1, 1, 3501 },
+ { 0x32e2, 1, 3502 },
+ { 0x32e3, 1, 3503 },
+ { 0x32e4, 1, 3504 },
+ { 0x32e5, 1, 3505 },
+ { 0x32e6, 1, 3506 },
+ { 0x32e7, 1, 3507 },
+ { 0x32e8, 1, 3508 },
+ { 0x32e9, 1, 3509 },
+ { 0x32ea, 1, 3510 },
+ { 0x32eb, 1, 3511 },
+ { 0x32ec, 1, 3512 },
+ { 0x32ed, 1, 3513 },
+ { 0x32ee, 1, 3514 },
+ { 0x32ef, 1, 3515 },
+ { 0x32f0, 1, 3516 },
+ { 0x32f1, 1, 3517 },
+ { 0x32f2, 1, 3518 },
+ { 0x32f3, 1, 3519 },
+ { 0x32f4, 1, 3520 },
+ { 0x32f5, 1, 3521 },
+ { 0x32f6, 1, 3522 },
+ { 0x32f7, 1, 3523 },
+ { 0x32f8, 1, 3524 },
+ { 0x32f9, 1, 3525 },
+ { 0x32fa, 1, 3526 },
+ { 0x32fb, 1, 3527 },
+ { 0x32fc, 1, 3528 },
+ { 0x32fd, 1, 3529 },
+ { 0x32fe, 1, 3530 },
+ { 0x3300, 5, 3531 },
+ { 0x3301, 4, 3536 },
+ { 0x3302, 5, 3540 },
+ { 0x3303, 3, 3545 },
+ { 0x3304, 5, 3548 },
+ { 0x3305, 3, 3553 },
+ { 0x3306, 3, 3556 },
+ { 0x3307, 6, 3559 },
+ { 0x3308, 4, 3565 },
+ { 0x3309, 3, 3569 },
+ { 0x330a, 3, 3572 },
+ { 0x330b, 3, 3575 },
+ { 0x330c, 4, 3578 },
+ { 0x330d, 4, 3582 },
+ { 0x330e, 4, 3586 },
+ { 0x330f, 4, 3590 },
+ { 0x3310, 4, 3594 },
+ { 0x3311, 4, 3598 },
+ { 0x3312, 4, 3602 },
+ { 0x3313, 6, 3606 },
+ { 0x3314, 2, 3612 },
+ { 0x3315, 6, 3614 },
+ { 0x3316, 6, 3620 },
+ { 0x3317, 5, 3626 },
+ { 0x3318, 4, 3631 },
+ { 0x3319, 6, 3635 },
+ { 0x331a, 6, 3641 },
+ { 0x331b, 4, 3647 },
+ { 0x331c, 3, 3651 },
+ { 0x331d, 3, 3654 },
+ { 0x331e, 4, 3657 },
+ { 0x331f, 4, 3661 },
+ { 0x3320, 5, 3665 },
+ { 0x3321, 5, 3670 },
+ { 0x3322, 3, 3675 },
+ { 0x3323, 3, 3678 },
+ { 0x3324, 4, 3681 },
+ { 0x3325, 3, 3685 },
+ { 0x3326, 3, 3688 },
+ { 0x3327, 2, 3691 },
+ { 0x3328, 2, 3693 },
+ { 0x3329, 3, 3695 },
+ { 0x332a, 3, 3698 },
+ { 0x332b, 6, 3701 },
+ { 0x332c, 4, 3707 },
+ { 0x332d, 5, 3711 },
+ { 0x332e, 6, 3716 },
+ { 0x332f, 4, 3722 },
+ { 0x3330, 3, 3726 },
+ { 0x3331, 3, 3729 },
+ { 0x3332, 6, 3732 },
+ { 0x3333, 4, 3738 },
+ { 0x3334, 6, 3742 },
+ { 0x3335, 3, 3748 },
+ { 0x3336, 5, 3751 },
+ { 0x3337, 3, 3756 },
+ { 0x3338, 4, 3759 },
+ { 0x3339, 3, 3763 },
+ { 0x333a, 4, 3766 },
+ { 0x333b, 5, 3770 },
+ { 0x333c, 4, 3775 },
+ { 0x333d, 5, 3779 },
+ { 0x333e, 4, 3784 },
+ { 0x333f, 2, 3788 },
+ { 0x3340, 5, 3790 },
+ { 0x3341, 3, 3795 },
+ { 0x3342, 3, 3798 },
+ { 0x3343, 4, 3801 },
+ { 0x3344, 3, 3805 },
+ { 0x3345, 3, 3808 },
+ { 0x3346, 3, 3811 },
+ { 0x3347, 5, 3814 },
+ { 0x3348, 4, 3819 },
+ { 0x3349, 2, 3823 },
+ { 0x334a, 6, 3825 },
+ { 0x334b, 3, 3831 },
+ { 0x334c, 5, 3834 },
+ { 0x334d, 4, 3839 },
+ { 0x334e, 4, 3843 },
+ { 0x334f, 3, 3847 },
+ { 0x3350, 3, 3850 },
+ { 0x3351, 4, 3853 },
+ { 0x3352, 2, 3857 },
+ { 0x3353, 4, 3859 },
+ { 0x3354, 5, 3863 },
+ { 0x3355, 2, 3868 },
+ { 0x3356, 6, 3870 },
+ { 0x3357, 3, 3876 },
+ { 0x3358, 2, 3879 },
+ { 0x3359, 2, 3881 },
+ { 0x335a, 2, 3883 },
+ { 0x335b, 2, 3885 },
+ { 0x335c, 2, 3887 },
+ { 0x335d, 2, 3889 },
+ { 0x335e, 2, 3891 },
+ { 0x335f, 2, 3893 },
+ { 0x3360, 2, 3895 },
+ { 0x3361, 2, 3897 },
+ { 0x3362, 3, 3899 },
+ { 0x3363, 3, 3902 },
+ { 0x3364, 3, 3905 },
+ { 0x3365, 3, 3908 },
+ { 0x3366, 3, 3911 },
+ { 0x3367, 3, 3914 },
+ { 0x3368, 3, 3917 },
+ { 0x3369, 3, 3920 },
+ { 0x336a, 3, 3923 },
+ { 0x336b, 3, 3926 },
+ { 0x336c, 3, 3929 },
+ { 0x336d, 3, 3932 },
+ { 0x336e, 3, 3935 },
+ { 0x336f, 3, 3938 },
+ { 0x3370, 3, 3941 },
+ { 0x3371, 3, 3944 },
+ { 0x3372, 2, 3947 },
+ { 0x3373, 2, 3949 },
+ { 0x3374, 3, 3951 },
+ { 0x3375, 2, 3954 },
+ { 0x3376, 2, 3956 },
+ { 0x337b, 2, 3958 },
+ { 0x337c, 2, 3960 },
+ { 0x337d, 2, 3962 },
+ { 0x337e, 2, 3964 },
+ { 0x337f, 4, 3966 },
+ { 0x3380, 2, 3970 },
+ { 0x3381, 2, 3972 },
+ { 0x3382, 2, 3974 },
+ { 0x3383, 2, 3976 },
+ { 0x3384, 2, 3978 },
+ { 0x3385, 2, 3980 },
+ { 0x3386, 2, 3982 },
+ { 0x3387, 2, 3984 },
+ { 0x3388, 3, 3986 },
+ { 0x3389, 4, 3989 },
+ { 0x338a, 2, 3993 },
+ { 0x338b, 2, 3995 },
+ { 0x338c, 2, 3997 },
+ { 0x338d, 2, 3999 },
+ { 0x338e, 2, 4001 },
+ { 0x338f, 2, 4003 },
+ { 0x3390, 2, 4005 },
+ { 0x3391, 3, 4007 },
+ { 0x3392, 3, 4010 },
+ { 0x3393, 3, 4013 },
+ { 0x3394, 3, 4016 },
+ { 0x3395, 2, 4019 },
+ { 0x3396, 2, 4021 },
+ { 0x3397, 2, 4023 },
+ { 0x3398, 2, 4025 },
+ { 0x3399, 2, 4027 },
+ { 0x339a, 2, 4029 },
+ { 0x339b, 2, 4031 },
+ { 0x339c, 2, 4033 },
+ { 0x339d, 2, 4035 },
+ { 0x339e, 2, 4037 },
+ { 0x339f, 3, 4039 },
+ { 0x33a0, 3, 4042 },
+ { 0x33a1, 2, 4045 },
+ { 0x33a2, 3, 4047 },
+ { 0x33a3, 3, 4050 },
+ { 0x33a4, 3, 4053 },
+ { 0x33a5, 2, 4056 },
+ { 0x33a6, 3, 4058 },
+ { 0x33a7, 3, 4061 },
+ { 0x33a8, 4, 4064 },
+ { 0x33a9, 2, 4068 },
+ { 0x33aa, 3, 4070 },
+ { 0x33ab, 3, 4073 },
+ { 0x33ac, 3, 4076 },
+ { 0x33ad, 3, 4079 },
+ { 0x33ae, 5, 4082 },
+ { 0x33af, 6, 4087 },
+ { 0x33b0, 2, 4093 },
+ { 0x33b1, 2, 4095 },
+ { 0x33b2, 2, 4097 },
+ { 0x33b3, 2, 4099 },
+ { 0x33b4, 2, 4101 },
+ { 0x33b5, 2, 4103 },
+ { 0x33b6, 2, 4105 },
+ { 0x33b7, 2, 4107 },
+ { 0x33b8, 2, 4109 },
+ { 0x33b9, 2, 4111 },
+ { 0x33ba, 2, 4113 },
+ { 0x33bb, 2, 4115 },
+ { 0x33bc, 2, 4117 },
+ { 0x33bd, 2, 4119 },
+ { 0x33be, 2, 4121 },
+ { 0x33bf, 2, 4123 },
+ { 0x33c0, 2, 4125 },
+ { 0x33c1, 2, 4127 },
+ { 0x33c2, 4, 4129 },
+ { 0x33c3, 2, 4133 },
+ { 0x33c4, 2, 4135 },
+ { 0x33c5, 2, 4137 },
+ { 0x33c6, 4, 4139 },
+ { 0x33c7, 3, 4143 },
+ { 0x33c8, 2, 4146 },
+ { 0x33c9, 2, 4148 },
+ { 0x33ca, 2, 4150 },
+ { 0x33cb, 2, 4152 },
+ { 0x33cc, 2, 4154 },
+ { 0x33cd, 2, 4156 },
+ { 0x33ce, 2, 4158 },
+ { 0x33cf, 2, 4160 },
+ { 0x33d0, 2, 4162 },
+ { 0x33d1, 2, 4164 },
+ { 0x33d2, 3, 4166 },
+ { 0x33d3, 2, 4169 },
+ { 0x33d4, 2, 4171 },
+ { 0x33d5, 3, 4173 },
+ { 0x33d6, 3, 4176 },
+ { 0x33d7, 2, 4179 },
+ { 0x33d8, 4, 4181 },
+ { 0x33d9, 3, 4185 },
+ { 0x33da, 2, 4188 },
+ { 0x33db, 2, 4190 },
+ { 0x33dc, 2, 4192 },
+ { 0x33dd, 2, 4194 },
+ { 0x33e0, 2, 4196 },
+ { 0x33e1, 2, 4198 },
+ { 0x33e2, 2, 4200 },
+ { 0x33e3, 2, 4202 },
+ { 0x33e4, 2, 4204 },
+ { 0x33e5, 2, 4206 },
+ { 0x33e6, 2, 4208 },
+ { 0x33e7, 2, 4210 },
+ { 0x33e8, 2, 4212 },
+ { 0x33e9, 3, 4214 },
+ { 0x33ea, 3, 4217 },
+ { 0x33eb, 3, 4220 },
+ { 0x33ec, 3, 4223 },
+ { 0x33ed, 3, 4226 },
+ { 0x33ee, 3, 4229 },
+ { 0x33ef, 3, 4232 },
+ { 0x33f0, 3, 4235 },
+ { 0x33f1, 3, 4238 },
+ { 0x33f2, 3, 4241 },
+ { 0x33f3, 3, 4244 },
+ { 0x33f4, 3, 4247 },
+ { 0x33f5, 3, 4250 },
+ { 0x33f6, 3, 4253 },
+ { 0x33f7, 3, 4256 },
+ { 0x33f8, 3, 4259 },
+ { 0x33f9, 3, 4262 },
+ { 0x33fa, 3, 4265 },
+ { 0x33fb, 3, 4268 },
+ { 0x33fc, 3, 4271 },
+ { 0x33fd, 3, 4274 },
+ { 0x33fe, 3, 4277 },
+ { 0xf900, 1, 4280 },
+ { 0xf901, 1, 4281 },
+ { 0xf902, 1, 2840 },
+ { 0xf903, 1, 4282 },
+ { 0xf904, 1, 4283 },
+ { 0xf905, 1, 4284 },
+ { 0xf906, 1, 4285 },
+ { 0xf907, 1, 2894 },
+ { 0xf908, 1, 2894 },
+ { 0xf909, 1, 4286 },
+ { 0xf90a, 1, 2848 },
+ { 0xf90b, 1, 4287 },
+ { 0xf90c, 1, 4288 },
+ { 0xf90d, 1, 4289 },
+ { 0xf90e, 1, 4290 },
+ { 0xf90f, 1, 4291 },
+ { 0xf910, 1, 4292 },
+ { 0xf911, 1, 4293 },
+ { 0xf912, 1, 4294 },
+ { 0xf913, 1, 4295 },
+ { 0xf914, 1, 4296 },
+ { 0xf915, 1, 4297 },
+ { 0xf916, 1, 4298 },
+ { 0xf917, 1, 4299 },
+ { 0xf918, 1, 4300 },
+ { 0xf919, 1, 4301 },
+ { 0xf91a, 1, 4302 },
+ { 0xf91b, 1, 4303 },
+ { 0xf91c, 1, 4304 },
+ { 0xf91d, 1, 4305 },
+ { 0xf91e, 1, 4306 },
+ { 0xf91f, 1, 4307 },
+ { 0xf920, 1, 4308 },
+ { 0xf921, 1, 4309 },
+ { 0xf922, 1, 4310 },
+ { 0xf923, 1, 4311 },
+ { 0xf924, 1, 4312 },
+ { 0xf925, 1, 4313 },
+ { 0xf926, 1, 4314 },
+ { 0xf927, 1, 4315 },
+ { 0xf928, 1, 4316 },
+ { 0xf929, 1, 4317 },
+ { 0xf92a, 1, 4318 },
+ { 0xf92b, 1, 4319 },
+ { 0xf92c, 1, 4320 },
+ { 0xf92d, 1, 4321 },
+ { 0xf92e, 1, 4322 },
+ { 0xf92f, 1, 4323 },
+ { 0xf930, 1, 4324 },
+ { 0xf931, 1, 4325 },
+ { 0xf932, 1, 4326 },
+ { 0xf933, 1, 4327 },
+ { 0xf934, 1, 2806 },
+ { 0xf935, 1, 4328 },
+ { 0xf936, 1, 4329 },
+ { 0xf937, 1, 4330 },
+ { 0xf938, 1, 4331 },
+ { 0xf939, 1, 4332 },
+ { 0xf93a, 1, 4333 },
+ { 0xf93b, 1, 4334 },
+ { 0xf93c, 1, 4335 },
+ { 0xf93d, 1, 4336 },
+ { 0xf93e, 1, 4337 },
+ { 0xf93f, 1, 4338 },
+ { 0xf940, 1, 2879 },
+ { 0xf941, 1, 4339 },
+ { 0xf942, 1, 4340 },
+ { 0xf943, 1, 4341 },
+ { 0xf944, 1, 4342 },
+ { 0xf945, 1, 4343 },
+ { 0xf946, 1, 4344 },
+ { 0xf947, 1, 4345 },
+ { 0xf948, 1, 4346 },
+ { 0xf949, 1, 4347 },
+ { 0xf94a, 1, 4348 },
+ { 0xf94b, 1, 4349 },
+ { 0xf94c, 1, 4350 },
+ { 0xf94d, 1, 4351 },
+ { 0xf94e, 1, 4352 },
+ { 0xf94f, 1, 4353 },
+ { 0xf950, 1, 4354 },
+ { 0xf951, 1, 4355 },
+ { 0xf952, 1, 4356 },
+ { 0xf953, 1, 4357 },
+ { 0xf954, 1, 4358 },
+ { 0xf955, 1, 4359 },
+ { 0xf956, 1, 4360 },
+ { 0xf957, 1, 4361 },
+ { 0xf958, 1, 4362 },
+ { 0xf959, 1, 4363 },
+ { 0xf95a, 1, 4364 },
+ { 0xf95b, 1, 4365 },
+ { 0xf95c, 1, 4296 },
+ { 0xf95d, 1, 4366 },
+ { 0xf95e, 1, 4367 },
+ { 0xf95f, 1, 4368 },
+ { 0xf960, 1, 4369 },
+ { 0xf961, 1, 4370 },
+ { 0xf962, 1, 4371 },
+ { 0xf963, 1, 4372 },
+ { 0xf964, 1, 4373 },
+ { 0xf965, 1, 4374 },
+ { 0xf966, 1, 4375 },
+ { 0xf967, 1, 4376 },
+ { 0xf968, 1, 4377 },
+ { 0xf969, 1, 4378 },
+ { 0xf96a, 1, 4379 },
+ { 0xf96b, 1, 4380 },
+ { 0xf96c, 1, 4381 },
+ { 0xf96d, 1, 4382 },
+ { 0xf96e, 1, 4383 },
+ { 0xf96f, 1, 4384 },
+ { 0xf970, 1, 4385 },
+ { 0xf971, 1, 2842 },
+ { 0xf972, 1, 4386 },
+ { 0xf973, 1, 4387 },
+ { 0xf974, 1, 4388 },
+ { 0xf975, 1, 4389 },
+ { 0xf976, 1, 4390 },
+ { 0xf977, 1, 4391 },
+ { 0xf978, 1, 4392 },
+ { 0xf979, 1, 4393 },
+ { 0xf97a, 1, 4394 },
+ { 0xf97b, 1, 4395 },
+ { 0xf97c, 1, 4396 },
+ { 0xf97d, 1, 4397 },
+ { 0xf97e, 1, 4398 },
+ { 0xf97f, 1, 4399 },
+ { 0xf980, 1, 4400 },
+ { 0xf981, 1, 2719 },
+ { 0xf982, 1, 4401 },
+ { 0xf983, 1, 4402 },
+ { 0xf984, 1, 4403 },
+ { 0xf985, 1, 4404 },
+ { 0xf986, 1, 4405 },
+ { 0xf987, 1, 4406 },
+ { 0xf988, 1, 4407 },
+ { 0xf989, 1, 4408 },
+ { 0xf98a, 1, 2700 },
+ { 0xf98b, 1, 4409 },
+ { 0xf98c, 1, 4410 },
+ { 0xf98d, 1, 4411 },
+ { 0xf98e, 1, 4412 },
+ { 0xf98f, 1, 4413 },
+ { 0xf990, 1, 4414 },
+ { 0xf991, 1, 4415 },
+ { 0xf992, 1, 4416 },
+ { 0xf993, 1, 4417 },
+ { 0xf994, 1, 4418 },
+ { 0xf995, 1, 4419 },
+ { 0xf996, 1, 4420 },
+ { 0xf997, 1, 4421 },
+ { 0xf998, 1, 4422 },
+ { 0xf999, 1, 4423 },
+ { 0xf99a, 1, 4424 },
+ { 0xf99b, 1, 4425 },
+ { 0xf99c, 1, 4426 },
+ { 0xf99d, 1, 4427 },
+ { 0xf99e, 1, 4428 },
+ { 0xf99f, 1, 4429 },
+ { 0xf9a0, 1, 4430 },
+ { 0xf9a1, 1, 4384 },
+ { 0xf9a2, 1, 4431 },
+ { 0xf9a3, 1, 4432 },
+ { 0xf9a4, 1, 4433 },
+ { 0xf9a5, 1, 4434 },
+ { 0xf9a6, 1, 4435 },
+ { 0xf9a7, 1, 4436 },
+ { 0xf9a8, 1, 4437 },
+ { 0xf9a9, 1, 4438 },
+ { 0xf9aa, 1, 4368 },
+ { 0xf9ab, 1, 4439 },
+ { 0xf9ac, 1, 4440 },
+ { 0xf9ad, 1, 4441 },
+ { 0xf9ae, 1, 4442 },
+ { 0xf9af, 1, 4443 },
+ { 0xf9b0, 1, 4444 },
+ { 0xf9b1, 1, 4445 },
+ { 0xf9b2, 1, 4446 },
+ { 0xf9b3, 1, 4447 },
+ { 0xf9b4, 1, 4448 },
+ { 0xf9b5, 1, 4449 },
+ { 0xf9b6, 1, 4450 },
+ { 0xf9b7, 1, 4451 },
+ { 0xf9b8, 1, 4452 },
+ { 0xf9b9, 1, 4453 },
+ { 0xf9ba, 1, 4454 },
+ { 0xf9bb, 1, 4455 },
+ { 0xf9bc, 1, 4456 },
+ { 0xf9bd, 1, 4457 },
+ { 0xf9be, 1, 4458 },
+ { 0xf9bf, 1, 4296 },
+ { 0xf9c0, 1, 4459 },
+ { 0xf9c1, 1, 4460 },
+ { 0xf9c2, 1, 4461 },
+ { 0xf9c3, 1, 4462 },
+ { 0xf9c4, 1, 2893 },
+ { 0xf9c5, 1, 4463 },
+ { 0xf9c6, 1, 4464 },
+ { 0xf9c7, 1, 4465 },
+ { 0xf9c8, 1, 4466 },
+ { 0xf9c9, 1, 4467 },
+ { 0xf9ca, 1, 4468 },
+ { 0xf9cb, 1, 4469 },
+ { 0xf9cc, 1, 4470 },
+ { 0xf9cd, 1, 4471 },
+ { 0xf9ce, 1, 4472 },
+ { 0xf9cf, 1, 4473 },
+ { 0xf9d0, 1, 4474 },
+ { 0xf9d1, 1, 3396 },
+ { 0xf9d2, 1, 4475 },
+ { 0xf9d3, 1, 4476 },
+ { 0xf9d4, 1, 4477 },
+ { 0xf9d5, 1, 4478 },
+ { 0xf9d6, 1, 4479 },
+ { 0xf9d7, 1, 4480 },
+ { 0xf9d8, 1, 4481 },
+ { 0xf9d9, 1, 4482 },
+ { 0xf9da, 1, 4483 },
+ { 0xf9db, 1, 4370 },
+ { 0xf9dc, 1, 4484 },
+ { 0xf9dd, 1, 4485 },
+ { 0xf9de, 1, 4486 },
+ { 0xf9df, 1, 4487 },
+ { 0xf9e0, 1, 4488 },
+ { 0xf9e1, 1, 4489 },
+ { 0xf9e2, 1, 4490 },
+ { 0xf9e3, 1, 4491 },
+ { 0xf9e4, 1, 4492 },
+ { 0xf9e5, 1, 4493 },
+ { 0xf9e6, 1, 4494 },
+ { 0xf9e7, 1, 4495 },
+ { 0xf9e8, 1, 4496 },
+ { 0xf9e9, 1, 2847 },
+ { 0xf9ea, 1, 4497 },
+ { 0xf9eb, 1, 4498 },
+ { 0xf9ec, 1, 4499 },
+ { 0xf9ed, 1, 4500 },
+ { 0xf9ee, 1, 4501 },
+ { 0xf9ef, 1, 4502 },
+ { 0xf9f0, 1, 4503 },
+ { 0xf9f1, 1, 4504 },
+ { 0xf9f2, 1, 4505 },
+ { 0xf9f3, 1, 4506 },
+ { 0xf9f4, 1, 4507 },
+ { 0xf9f5, 1, 4508 },
+ { 0xf9f6, 1, 4509 },
+ { 0xf9f7, 1, 2798 },
+ { 0xf9f8, 1, 4510 },
+ { 0xf9f9, 1, 4511 },
+ { 0xf9fa, 1, 4512 },
+ { 0xf9fb, 1, 4513 },
+ { 0xf9fc, 1, 4514 },
+ { 0xf9fd, 1, 4515 },
+ { 0xf9fe, 1, 4516 },
+ { 0xf9ff, 1, 4517 },
+ { 0xfa00, 1, 4518 },
+ { 0xfa01, 1, 4519 },
+ { 0xfa02, 1, 4520 },
+ { 0xfa03, 1, 4521 },
+ { 0xfa04, 1, 4522 },
+ { 0xfa05, 1, 4523 },
+ { 0xfa06, 1, 4524 },
+ { 0xfa07, 1, 4525 },
+ { 0xfa08, 1, 2825 },
+ { 0xfa09, 1, 4526 },
+ { 0xfa0a, 1, 2828 },
+ { 0xfa0b, 1, 4527 },
+ { 0xfa0c, 1, 4528 },
+ { 0xfa0d, 1, 4529 },
+ { 0xfa10, 1, 4530 },
+ { 0xfa12, 1, 4531 },
+ { 0xfa15, 1, 4532 },
+ { 0xfa16, 1, 4533 },
+ { 0xfa17, 1, 4534 },
+ { 0xfa18, 1, 4535 },
+ { 0xfa19, 1, 4536 },
+ { 0xfa1a, 1, 4537 },
+ { 0xfa1b, 1, 4538 },
+ { 0xfa1c, 1, 4539 },
+ { 0xfa1d, 1, 4540 },
+ { 0xfa1e, 1, 2805 },
+ { 0xfa20, 1, 4541 },
+ { 0xfa22, 1, 4542 },
+ { 0xfa25, 1, 4543 },
+ { 0xfa26, 1, 4544 },
+ { 0xfa2a, 1, 4545 },
+ { 0xfa2b, 1, 4546 },
+ { 0xfa2c, 1, 4547 },
+ { 0xfa2d, 1, 4548 },
+ { 0xfa30, 1, 4549 },
+ { 0xfa31, 1, 4550 },
+ { 0xfa32, 1, 4551 },
+ { 0xfa33, 1, 4552 },
+ { 0xfa34, 1, 4553 },
+ { 0xfa35, 1, 4554 },
+ { 0xfa36, 1, 4555 },
+ { 0xfa37, 1, 4556 },
+ { 0xfa38, 1, 4557 },
+ { 0xfa39, 1, 4558 },
+ { 0xfa3a, 1, 4559 },
+ { 0xfa3b, 1, 4560 },
+ { 0xfa3c, 1, 2726 },
+ { 0xfa3d, 1, 4561 },
+ { 0xfa3e, 1, 4562 },
+ { 0xfa3f, 1, 4563 },
+ { 0xfa40, 1, 4564 },
+ { 0xfa41, 1, 4565 },
+ { 0xfa42, 1, 4566 },
+ { 0xfa43, 1, 4567 },
+ { 0xfa44, 1, 4568 },
+ { 0xfa45, 1, 4569 },
+ { 0xfa46, 1, 4570 },
+ { 0xfa47, 1, 4571 },
+ { 0xfa48, 1, 4572 },
+ { 0xfa49, 1, 4573 },
+ { 0xfa4a, 1, 4574 },
+ { 0xfa4b, 1, 4575 },
+ { 0xfa4c, 1, 3401 },
+ { 0xfa4d, 1, 4576 },
+ { 0xfa4e, 1, 4577 },
+ { 0xfa4f, 1, 4578 },
+ { 0xfa50, 1, 4579 },
+ { 0xfa51, 1, 3405 },
+ { 0xfa52, 1, 4580 },
+ { 0xfa53, 1, 4581 },
+ { 0xfa54, 1, 4582 },
+ { 0xfa55, 1, 4583 },
+ { 0xfa56, 1, 4584 },
+ { 0xfa57, 1, 4420 },
+ { 0xfa58, 1, 4585 },
+ { 0xfa59, 1, 4586 },
+ { 0xfa5a, 1, 4587 },
+ { 0xfa5b, 1, 4588 },
+ { 0xfa5c, 1, 4589 },
+ { 0xfa5d, 1, 4590 },
+ { 0xfa5e, 1, 4590 },
+ { 0xfa5f, 1, 4591 },
+ { 0xfa60, 1, 4592 },
+ { 0xfa61, 1, 4593 },
+ { 0xfa62, 1, 4594 },
+ { 0xfa63, 1, 4595 },
+ { 0xfa64, 1, 4596 },
+ { 0xfa65, 1, 4597 },
+ { 0xfa66, 1, 4598 },
+ { 0xfa67, 1, 4543 },
+ { 0xfa68, 1, 4599 },
+ { 0xfa69, 1, 4600 },
+ { 0xfa6a, 1, 4601 },
+ { 0xfb00, 2, 4602 },
+ { 0xfb01, 2, 4604 },
+ { 0xfb02, 2, 4606 },
+ { 0xfb03, 3, 4608 },
+ { 0xfb04, 3, 4611 },
+ { 0xfb05, 2, 4614 },
+ { 0xfb06, 2, 4614 },
+ { 0xfb13, 2, 4616 },
+ { 0xfb14, 2, 4618 },
+ { 0xfb15, 2, 4620 },
+ { 0xfb16, 2, 4622 },
+ { 0xfb17, 2, 4624 },
+ { 0xfb1d, 2, 4626 },
+ { 0xfb1f, 2, 4628 },
+ { 0xfb20, 1, 4630 },
+ { 0xfb21, 1, 2228 },
+ { 0xfb22, 1, 2231 },
+ { 0xfb23, 1, 4631 },
+ { 0xfb24, 1, 4632 },
+ { 0xfb25, 1, 4633 },
+ { 0xfb26, 1, 4634 },
+ { 0xfb27, 1, 4635 },
+ { 0xfb28, 1, 4636 },
+ { 0xfb29, 1, 2176 },
+ { 0xfb2a, 2, 4637 },
+ { 0xfb2b, 2, 4639 },
+ { 0xfb2c, 3, 4641 },
+ { 0xfb2d, 3, 4644 },
+ { 0xfb2e, 2, 4647 },
+ { 0xfb2f, 2, 4649 },
+ { 0xfb30, 2, 4651 },
+ { 0xfb31, 2, 4653 },
+ { 0xfb32, 2, 4655 },
+ { 0xfb33, 2, 4657 },
+ { 0xfb34, 2, 4659 },
+ { 0xfb35, 2, 4661 },
+ { 0xfb36, 2, 4663 },
+ { 0xfb38, 2, 4665 },
+ { 0xfb39, 2, 4667 },
+ { 0xfb3a, 2, 4669 },
+ { 0xfb3b, 2, 4671 },
+ { 0xfb3c, 2, 4673 },
+ { 0xfb3e, 2, 4675 },
+ { 0xfb40, 2, 4677 },
+ { 0xfb41, 2, 4679 },
+ { 0xfb43, 2, 4681 },
+ { 0xfb44, 2, 4683 },
+ { 0xfb46, 2, 4685 },
+ { 0xfb47, 2, 4687 },
+ { 0xfb48, 2, 4689 },
+ { 0xfb49, 2, 4691 },
+ { 0xfb4a, 2, 4693 },
+ { 0xfb4b, 2, 4695 },
+ { 0xfb4c, 2, 4697 },
+ { 0xfb4d, 2, 4699 },
+ { 0xfb4e, 2, 4701 },
+ { 0xfb4f, 2, 4703 },
+ { 0xfb50, 1, 4705 },
+ { 0xfb51, 1, 4705 },
+ { 0xfb52, 1, 4706 },
+ { 0xfb53, 1, 4706 },
+ { 0xfb54, 1, 4706 },
+ { 0xfb55, 1, 4706 },
+ { 0xfb56, 1, 4707 },
+ { 0xfb57, 1, 4707 },
+ { 0xfb58, 1, 4707 },
+ { 0xfb59, 1, 4707 },
+ { 0xfb5a, 1, 4708 },
+ { 0xfb5b, 1, 4708 },
+ { 0xfb5c, 1, 4708 },
+ { 0xfb5d, 1, 4708 },
+ { 0xfb5e, 1, 4709 },
+ { 0xfb5f, 1, 4709 },
+ { 0xfb60, 1, 4709 },
+ { 0xfb61, 1, 4709 },
+ { 0xfb62, 1, 4710 },
+ { 0xfb63, 1, 4710 },
+ { 0xfb64, 1, 4710 },
+ { 0xfb65, 1, 4710 },
+ { 0xfb66, 1, 4711 },
+ { 0xfb67, 1, 4711 },
+ { 0xfb68, 1, 4711 },
+ { 0xfb69, 1, 4711 },
+ { 0xfb6a, 1, 4712 },
+ { 0xfb6b, 1, 4712 },
+ { 0xfb6c, 1, 4712 },
+ { 0xfb6d, 1, 4712 },
+ { 0xfb6e, 1, 4713 },
+ { 0xfb6f, 1, 4713 },
+ { 0xfb70, 1, 4713 },
+ { 0xfb71, 1, 4713 },
+ { 0xfb72, 1, 4714 },
+ { 0xfb73, 1, 4714 },
+ { 0xfb74, 1, 4714 },
+ { 0xfb75, 1, 4714 },
+ { 0xfb76, 1, 4715 },
+ { 0xfb77, 1, 4715 },
+ { 0xfb78, 1, 4715 },
+ { 0xfb79, 1, 4715 },
+ { 0xfb7a, 1, 4716 },
+ { 0xfb7b, 1, 4716 },
+ { 0xfb7c, 1, 4716 },
+ { 0xfb7d, 1, 4716 },
+ { 0xfb7e, 1, 4717 },
+ { 0xfb7f, 1, 4717 },
+ { 0xfb80, 1, 4717 },
+ { 0xfb81, 1, 4717 },
+ { 0xfb82, 1, 4718 },
+ { 0xfb83, 1, 4718 },
+ { 0xfb84, 1, 4719 },
+ { 0xfb85, 1, 4719 },
+ { 0xfb86, 1, 4720 },
+ { 0xfb87, 1, 4720 },
+ { 0xfb88, 1, 4721 },
+ { 0xfb89, 1, 4721 },
+ { 0xfb8a, 1, 4722 },
+ { 0xfb8b, 1, 4722 },
+ { 0xfb8c, 1, 4723 },
+ { 0xfb8d, 1, 4723 },
+ { 0xfb8e, 1, 4724 },
+ { 0xfb8f, 1, 4724 },
+ { 0xfb90, 1, 4724 },
+ { 0xfb91, 1, 4724 },
+ { 0xfb92, 1, 4725 },
+ { 0xfb93, 1, 4725 },
+ { 0xfb94, 1, 4725 },
+ { 0xfb95, 1, 4725 },
+ { 0xfb96, 1, 4726 },
+ { 0xfb97, 1, 4726 },
+ { 0xfb98, 1, 4726 },
+ { 0xfb99, 1, 4726 },
+ { 0xfb9a, 1, 4727 },
+ { 0xfb9b, 1, 4727 },
+ { 0xfb9c, 1, 4727 },
+ { 0xfb9d, 1, 4727 },
+ { 0xfb9e, 1, 4728 },
+ { 0xfb9f, 1, 4728 },
+ { 0xfba0, 1, 4729 },
+ { 0xfba1, 1, 4729 },
+ { 0xfba2, 1, 4729 },
+ { 0xfba3, 1, 4729 },
+ { 0xfba4, 2, 802 },
+ { 0xfba5, 2, 802 },
+ { 0xfba6, 1, 4730 },
+ { 0xfba7, 1, 4730 },
+ { 0xfba8, 1, 4730 },
+ { 0xfba9, 1, 4730 },
+ { 0xfbaa, 1, 4731 },
+ { 0xfbab, 1, 4731 },
+ { 0xfbac, 1, 4731 },
+ { 0xfbad, 1, 4731 },
+ { 0xfbae, 1, 4732 },
+ { 0xfbaf, 1, 4732 },
+ { 0xfbb0, 2, 806 },
+ { 0xfbb1, 2, 806 },
+ { 0xfbd3, 1, 4733 },
+ { 0xfbd4, 1, 4733 },
+ { 0xfbd5, 1, 4733 },
+ { 0xfbd6, 1, 4733 },
+ { 0xfbd7, 1, 4734 },
+ { 0xfbd8, 1, 4734 },
+ { 0xfbd9, 1, 4735 },
+ { 0xfbda, 1, 4735 },
+ { 0xfbdb, 1, 4736 },
+ { 0xfbdc, 1, 4736 },
+ { 0xfbdd, 2, 798 },
+ { 0xfbde, 1, 4737 },
+ { 0xfbdf, 1, 4737 },
+ { 0xfbe0, 1, 4738 },
+ { 0xfbe1, 1, 4738 },
+ { 0xfbe2, 1, 4739 },
+ { 0xfbe3, 1, 4739 },
+ { 0xfbe4, 1, 4740 },
+ { 0xfbe5, 1, 4740 },
+ { 0xfbe6, 1, 4740 },
+ { 0xfbe7, 1, 4740 },
+ { 0xfbe8, 1, 4741 },
+ { 0xfbe9, 1, 4741 },
+ { 0xfbea, 3, 4742 },
+ { 0xfbeb, 3, 4742 },
+ { 0xfbec, 3, 4745 },
+ { 0xfbed, 3, 4745 },
+ { 0xfbee, 3, 4748 },
+ { 0xfbef, 3, 4748 },
+ { 0xfbf0, 3, 4751 },
+ { 0xfbf1, 3, 4751 },
+ { 0xfbf2, 3, 4754 },
+ { 0xfbf3, 3, 4754 },
+ { 0xfbf4, 3, 4757 },
+ { 0xfbf5, 3, 4757 },
+ { 0xfbf6, 3, 4760 },
+ { 0xfbf7, 3, 4760 },
+ { 0xfbf8, 3, 4760 },
+ { 0xfbf9, 3, 4763 },
+ { 0xfbfa, 3, 4763 },
+ { 0xfbfb, 3, 4763 },
+ { 0xfbfc, 1, 4766 },
+ { 0xfbfd, 1, 4766 },
+ { 0xfbfe, 1, 4766 },
+ { 0xfbff, 1, 4766 },
+ { 0xfc00, 3, 4767 },
+ { 0xfc01, 3, 4770 },
+ { 0xfc02, 3, 4773 },
+ { 0xfc03, 3, 4763 },
+ { 0xfc04, 3, 4776 },
+ { 0xfc05, 2, 4779 },
+ { 0xfc06, 2, 4781 },
+ { 0xfc07, 2, 4783 },
+ { 0xfc08, 2, 4785 },
+ { 0xfc09, 2, 4787 },
+ { 0xfc0a, 2, 4789 },
+ { 0xfc0b, 2, 4791 },
+ { 0xfc0c, 2, 4793 },
+ { 0xfc0d, 2, 4795 },
+ { 0xfc0e, 2, 4797 },
+ { 0xfc0f, 2, 4799 },
+ { 0xfc10, 2, 4801 },
+ { 0xfc11, 2, 4803 },
+ { 0xfc12, 2, 4805 },
+ { 0xfc13, 2, 4807 },
+ { 0xfc14, 2, 4809 },
+ { 0xfc15, 2, 4811 },
+ { 0xfc16, 2, 4813 },
+ { 0xfc17, 2, 4815 },
+ { 0xfc18, 2, 4817 },
+ { 0xfc19, 2, 4819 },
+ { 0xfc1a, 2, 4821 },
+ { 0xfc1b, 2, 4823 },
+ { 0xfc1c, 2, 4825 },
+ { 0xfc1d, 2, 4827 },
+ { 0xfc1e, 2, 4829 },
+ { 0xfc1f, 2, 4831 },
+ { 0xfc20, 2, 4833 },
+ { 0xfc21, 2, 4835 },
+ { 0xfc22, 2, 4837 },
+ { 0xfc23, 2, 4839 },
+ { 0xfc24, 2, 4841 },
+ { 0xfc25, 2, 4843 },
+ { 0xfc26, 2, 4845 },
+ { 0xfc27, 2, 4847 },
+ { 0xfc28, 2, 4849 },
+ { 0xfc29, 2, 4851 },
+ { 0xfc2a, 2, 4853 },
+ { 0xfc2b, 2, 4855 },
+ { 0xfc2c, 2, 4857 },
+ { 0xfc2d, 2, 4859 },
+ { 0xfc2e, 2, 4861 },
+ { 0xfc2f, 2, 4863 },
+ { 0xfc30, 2, 4865 },
+ { 0xfc31, 2, 4867 },
+ { 0xfc32, 2, 4869 },
+ { 0xfc33, 2, 4871 },
+ { 0xfc34, 2, 4873 },
+ { 0xfc35, 2, 4875 },
+ { 0xfc36, 2, 4877 },
+ { 0xfc37, 2, 4879 },
+ { 0xfc38, 2, 4881 },
+ { 0xfc39, 2, 4883 },
+ { 0xfc3a, 2, 4885 },
+ { 0xfc3b, 2, 4887 },
+ { 0xfc3c, 2, 4889 },
+ { 0xfc3d, 2, 4891 },
+ { 0xfc3e, 2, 4893 },
+ { 0xfc3f, 2, 4895 },
+ { 0xfc40, 2, 4897 },
+ { 0xfc41, 2, 4899 },
+ { 0xfc42, 2, 4901 },
+ { 0xfc43, 2, 4903 },
+ { 0xfc44, 2, 4905 },
+ { 0xfc45, 2, 4907 },
+ { 0xfc46, 2, 4909 },
+ { 0xfc47, 2, 4911 },
+ { 0xfc48, 2, 4913 },
+ { 0xfc49, 2, 4915 },
+ { 0xfc4a, 2, 4917 },
+ { 0xfc4b, 2, 4919 },
+ { 0xfc4c, 2, 4921 },
+ { 0xfc4d, 2, 4923 },
+ { 0xfc4e, 2, 4925 },
+ { 0xfc4f, 2, 4927 },
+ { 0xfc50, 2, 4929 },
+ { 0xfc51, 2, 4931 },
+ { 0xfc52, 2, 4933 },
+ { 0xfc53, 2, 4935 },
+ { 0xfc54, 2, 4937 },
+ { 0xfc55, 2, 4939 },
+ { 0xfc56, 2, 4941 },
+ { 0xfc57, 2, 4943 },
+ { 0xfc58, 2, 4945 },
+ { 0xfc59, 2, 4947 },
+ { 0xfc5a, 2, 4949 },
+ { 0xfc5b, 2, 4951 },
+ { 0xfc5c, 2, 4953 },
+ { 0xfc5d, 2, 4955 },
+ { 0xfc5e, 3, 4957 },
+ { 0xfc5f, 3, 4960 },
+ { 0xfc60, 3, 4963 },
+ { 0xfc61, 3, 4966 },
+ { 0xfc62, 3, 4969 },
+ { 0xfc63, 3, 4972 },
+ { 0xfc64, 3, 4975 },
+ { 0xfc65, 3, 4978 },
+ { 0xfc66, 3, 4773 },
+ { 0xfc67, 3, 4981 },
+ { 0xfc68, 3, 4763 },
+ { 0xfc69, 3, 4776 },
+ { 0xfc6a, 2, 4984 },
+ { 0xfc6b, 2, 4986 },
+ { 0xfc6c, 2, 4785 },
+ { 0xfc6d, 2, 4988 },
+ { 0xfc6e, 2, 4787 },
+ { 0xfc6f, 2, 4789 },
+ { 0xfc70, 2, 4990 },
+ { 0xfc71, 2, 4992 },
+ { 0xfc72, 2, 4797 },
+ { 0xfc73, 2, 4994 },
+ { 0xfc74, 2, 4799 },
+ { 0xfc75, 2, 4801 },
+ { 0xfc76, 2, 4996 },
+ { 0xfc77, 2, 4998 },
+ { 0xfc78, 2, 4805 },
+ { 0xfc79, 2, 5000 },
+ { 0xfc7a, 2, 4807 },
+ { 0xfc7b, 2, 4809 },
+ { 0xfc7c, 2, 4867 },
+ { 0xfc7d, 2, 4869 },
+ { 0xfc7e, 2, 4875 },
+ { 0xfc7f, 2, 4877 },
+ { 0xfc80, 2, 4879 },
+ { 0xfc81, 2, 4887 },
+ { 0xfc82, 2, 4889 },
+ { 0xfc83, 2, 4891 },
+ { 0xfc84, 2, 4893 },
+ { 0xfc85, 2, 4901 },
+ { 0xfc86, 2, 4903 },
+ { 0xfc87, 2, 4905 },
+ { 0xfc88, 2, 5002 },
+ { 0xfc89, 2, 4913 },
+ { 0xfc8a, 2, 5004 },
+ { 0xfc8b, 2, 5006 },
+ { 0xfc8c, 2, 4925 },
+ { 0xfc8d, 2, 5008 },
+ { 0xfc8e, 2, 4927 },
+ { 0xfc8f, 2, 4929 },
+ { 0xfc90, 2, 4955 },
+ { 0xfc91, 2, 5010 },
+ { 0xfc92, 2, 5012 },
+ { 0xfc93, 2, 4945 },
+ { 0xfc94, 2, 5014 },
+ { 0xfc95, 2, 4947 },
+ { 0xfc96, 2, 4949 },
+ { 0xfc97, 3, 4767 },
+ { 0xfc98, 3, 4770 },
+ { 0xfc99, 3, 5016 },
+ { 0xfc9a, 3, 4773 },
+ { 0xfc9b, 3, 5019 },
+ { 0xfc9c, 2, 4779 },
+ { 0xfc9d, 2, 4781 },
+ { 0xfc9e, 2, 4783 },
+ { 0xfc9f, 2, 4785 },
+ { 0xfca0, 2, 5022 },
+ { 0xfca1, 2, 4791 },
+ { 0xfca2, 2, 4793 },
+ { 0xfca3, 2, 4795 },
+ { 0xfca4, 2, 4797 },
+ { 0xfca5, 2, 5024 },
+ { 0xfca6, 2, 4805 },
+ { 0xfca7, 2, 4811 },
+ { 0xfca8, 2, 4813 },
+ { 0xfca9, 2, 4815 },
+ { 0xfcaa, 2, 4817 },
+ { 0xfcab, 2, 4819 },
+ { 0xfcac, 2, 4823 },
+ { 0xfcad, 2, 4825 },
+ { 0xfcae, 2, 4827 },
+ { 0xfcaf, 2, 4829 },
+ { 0xfcb0, 2, 4831 },
+ { 0xfcb1, 2, 4833 },
+ { 0xfcb2, 2, 5026 },
+ { 0xfcb3, 2, 4835 },
+ { 0xfcb4, 2, 4837 },
+ { 0xfcb5, 2, 4839 },
+ { 0xfcb6, 2, 4841 },
+ { 0xfcb7, 2, 4843 },
+ { 0xfcb8, 2, 4845 },
+ { 0xfcb9, 2, 4849 },
+ { 0xfcba, 2, 4851 },
+ { 0xfcbb, 2, 4853 },
+ { 0xfcbc, 2, 4855 },
+ { 0xfcbd, 2, 4857 },
+ { 0xfcbe, 2, 4859 },
+ { 0xfcbf, 2, 4861 },
+ { 0xfcc0, 2, 4863 },
+ { 0xfcc1, 2, 4865 },
+ { 0xfcc2, 2, 4871 },
+ { 0xfcc3, 2, 4873 },
+ { 0xfcc4, 2, 4881 },
+ { 0xfcc5, 2, 4883 },
+ { 0xfcc6, 2, 4885 },
+ { 0xfcc7, 2, 4887 },
+ { 0xfcc8, 2, 4889 },
+ { 0xfcc9, 2, 4895 },
+ { 0xfcca, 2, 4897 },
+ { 0xfccb, 2, 4899 },
+ { 0xfccc, 2, 4901 },
+ { 0xfccd, 2, 5028 },
+ { 0xfcce, 2, 4907 },
+ { 0xfccf, 2, 4909 },
+ { 0xfcd0, 2, 4911 },
+ { 0xfcd1, 2, 4913 },
+ { 0xfcd2, 2, 4919 },
+ { 0xfcd3, 2, 4921 },
+ { 0xfcd4, 2, 4923 },
+ { 0xfcd5, 2, 4925 },
+ { 0xfcd6, 2, 5030 },
+ { 0xfcd7, 2, 4931 },
+ { 0xfcd8, 2, 4933 },
+ { 0xfcd9, 2, 5032 },
+ { 0xfcda, 2, 4939 },
+ { 0xfcdb, 2, 4941 },
+ { 0xfcdc, 2, 4943 },
+ { 0xfcdd, 2, 4945 },
+ { 0xfcde, 2, 5034 },
+ { 0xfcdf, 3, 4773 },
+ { 0xfce0, 3, 5019 },
+ { 0xfce1, 2, 4785 },
+ { 0xfce2, 2, 5022 },
+ { 0xfce3, 2, 4797 },
+ { 0xfce4, 2, 5024 },
+ { 0xfce5, 2, 4805 },
+ { 0xfce6, 2, 5036 },
+ { 0xfce7, 2, 4831 },
+ { 0xfce8, 2, 5038 },
+ { 0xfce9, 2, 5040 },
+ { 0xfcea, 2, 5042 },
+ { 0xfceb, 2, 4887 },
+ { 0xfcec, 2, 4889 },
+ { 0xfced, 2, 4901 },
+ { 0xfcee, 2, 4925 },
+ { 0xfcef, 2, 5030 },
+ { 0xfcf0, 2, 4945 },
+ { 0xfcf1, 2, 5034 },
+ { 0xfcf2, 3, 5044 },
+ { 0xfcf3, 3, 5047 },
+ { 0xfcf4, 3, 5050 },
+ { 0xfcf5, 2, 5053 },
+ { 0xfcf6, 2, 5055 },
+ { 0xfcf7, 2, 5057 },
+ { 0xfcf8, 2, 5059 },
+ { 0xfcf9, 2, 5061 },
+ { 0xfcfa, 2, 5063 },
+ { 0xfcfb, 2, 5065 },
+ { 0xfcfc, 2, 5067 },
+ { 0xfcfd, 2, 5069 },
+ { 0xfcfe, 2, 5071 },
+ { 0xfcff, 2, 5073 },
+ { 0xfd00, 2, 5075 },
+ { 0xfd01, 2, 5077 },
+ { 0xfd02, 2, 5079 },
+ { 0xfd03, 2, 5081 },
+ { 0xfd04, 2, 5083 },
+ { 0xfd05, 2, 5085 },
+ { 0xfd06, 2, 5087 },
+ { 0xfd07, 2, 5089 },
+ { 0xfd08, 2, 5091 },
+ { 0xfd09, 2, 5093 },
+ { 0xfd0a, 2, 5095 },
+ { 0xfd0b, 2, 5097 },
+ { 0xfd0c, 2, 5040 },
+ { 0xfd0d, 2, 5099 },
+ { 0xfd0e, 2, 5101 },
+ { 0xfd0f, 2, 5103 },
+ { 0xfd10, 2, 5105 },
+ { 0xfd11, 2, 5053 },
+ { 0xfd12, 2, 5055 },
+ { 0xfd13, 2, 5057 },
+ { 0xfd14, 2, 5059 },
+ { 0xfd15, 2, 5061 },
+ { 0xfd16, 2, 5063 },
+ { 0xfd17, 2, 5065 },
+ { 0xfd18, 2, 5067 },
+ { 0xfd19, 2, 5069 },
+ { 0xfd1a, 2, 5071 },
+ { 0xfd1b, 2, 5073 },
+ { 0xfd1c, 2, 5075 },
+ { 0xfd1d, 2, 5077 },
+ { 0xfd1e, 2, 5079 },
+ { 0xfd1f, 2, 5081 },
+ { 0xfd20, 2, 5083 },
+ { 0xfd21, 2, 5085 },
+ { 0xfd22, 2, 5087 },
+ { 0xfd23, 2, 5089 },
+ { 0xfd24, 2, 5091 },
+ { 0xfd25, 2, 5093 },
+ { 0xfd26, 2, 5095 },
+ { 0xfd27, 2, 5097 },
+ { 0xfd28, 2, 5040 },
+ { 0xfd29, 2, 5099 },
+ { 0xfd2a, 2, 5101 },
+ { 0xfd2b, 2, 5103 },
+ { 0xfd2c, 2, 5105 },
+ { 0xfd2d, 2, 5093 },
+ { 0xfd2e, 2, 5095 },
+ { 0xfd2f, 2, 5097 },
+ { 0xfd30, 2, 5040 },
+ { 0xfd31, 2, 5038 },
+ { 0xfd32, 2, 5042 },
+ { 0xfd33, 2, 4847 },
+ { 0xfd34, 2, 4825 },
+ { 0xfd35, 2, 4827 },
+ { 0xfd36, 2, 4829 },
+ { 0xfd37, 2, 5093 },
+ { 0xfd38, 2, 5095 },
+ { 0xfd39, 2, 5097 },
+ { 0xfd3a, 2, 4847 },
+ { 0xfd3b, 2, 4849 },
+ { 0xfd3c, 2, 5107 },
+ { 0xfd3d, 2, 5107 },
+ { 0xfd50, 3, 5109 },
+ { 0xfd51, 3, 5112 },
+ { 0xfd52, 3, 5112 },
+ { 0xfd53, 3, 5115 },
+ { 0xfd54, 3, 5118 },
+ { 0xfd55, 3, 5121 },
+ { 0xfd56, 3, 5124 },
+ { 0xfd57, 3, 5127 },
+ { 0xfd58, 3, 5130 },
+ { 0xfd59, 3, 5130 },
+ { 0xfd5a, 3, 5133 },
+ { 0xfd5b, 3, 5136 },
+ { 0xfd5c, 3, 5139 },
+ { 0xfd5d, 3, 5142 },
+ { 0xfd5e, 3, 5145 },
+ { 0xfd5f, 3, 5148 },
+ { 0xfd60, 3, 5148 },
+ { 0xfd61, 3, 5151 },
+ { 0xfd62, 3, 5154 },
+ { 0xfd63, 3, 5154 },
+ { 0xfd64, 3, 5157 },
+ { 0xfd65, 3, 5157 },
+ { 0xfd66, 3, 5160 },
+ { 0xfd67, 3, 5163 },
+ { 0xfd68, 3, 5163 },
+ { 0xfd69, 3, 5166 },
+ { 0xfd6a, 3, 5169 },
+ { 0xfd6b, 3, 5169 },
+ { 0xfd6c, 3, 5172 },
+ { 0xfd6d, 3, 5172 },
+ { 0xfd6e, 3, 5175 },
+ { 0xfd6f, 3, 5178 },
+ { 0xfd70, 3, 5178 },
+ { 0xfd71, 3, 5181 },
+ { 0xfd72, 3, 5181 },
+ { 0xfd73, 3, 5184 },
+ { 0xfd74, 3, 5187 },
+ { 0xfd75, 3, 5190 },
+ { 0xfd76, 3, 5193 },
+ { 0xfd77, 3, 5193 },
+ { 0xfd78, 3, 5196 },
+ { 0xfd79, 3, 5199 },
+ { 0xfd7a, 3, 5202 },
+ { 0xfd7b, 3, 5205 },
+ { 0xfd7c, 3, 5208 },
+ { 0xfd7d, 3, 5208 },
+ { 0xfd7e, 3, 5211 },
+ { 0xfd7f, 3, 5214 },
+ { 0xfd80, 3, 5217 },
+ { 0xfd81, 3, 5220 },
+ { 0xfd82, 3, 5223 },
+ { 0xfd83, 3, 5226 },
+ { 0xfd84, 3, 5226 },
+ { 0xfd85, 3, 5229 },
+ { 0xfd86, 3, 5229 },
+ { 0xfd87, 3, 5232 },
+ { 0xfd88, 3, 5232 },
+ { 0xfd89, 3, 5235 },
+ { 0xfd8a, 3, 5238 },
+ { 0xfd8b, 3, 5241 },
+ { 0xfd8c, 3, 5244 },
+ { 0xfd8d, 3, 5247 },
+ { 0xfd8e, 3, 5250 },
+ { 0xfd8f, 3, 5253 },
+ { 0xfd92, 3, 5256 },
+ { 0xfd93, 3, 5259 },
+ { 0xfd94, 3, 5262 },
+ { 0xfd95, 3, 5265 },
+ { 0xfd96, 3, 5268 },
+ { 0xfd97, 3, 5271 },
+ { 0xfd98, 3, 5271 },
+ { 0xfd99, 3, 5274 },
+ { 0xfd9a, 3, 5277 },
+ { 0xfd9b, 3, 5280 },
+ { 0xfd9c, 3, 5283 },
+ { 0xfd9d, 3, 5283 },
+ { 0xfd9e, 3, 5286 },
+ { 0xfd9f, 3, 5289 },
+ { 0xfda0, 3, 5292 },
+ { 0xfda1, 3, 5295 },
+ { 0xfda2, 3, 5298 },
+ { 0xfda3, 3, 5301 },
+ { 0xfda4, 3, 5304 },
+ { 0xfda5, 3, 5307 },
+ { 0xfda6, 3, 5310 },
+ { 0xfda7, 3, 5313 },
+ { 0xfda8, 3, 5316 },
+ { 0xfda9, 3, 5319 },
+ { 0xfdaa, 3, 5322 },
+ { 0xfdab, 3, 5325 },
+ { 0xfdac, 3, 5328 },
+ { 0xfdad, 3, 5331 },
+ { 0xfdae, 3, 5334 },
+ { 0xfdaf, 3, 5337 },
+ { 0xfdb0, 3, 5340 },
+ { 0xfdb1, 3, 5343 },
+ { 0xfdb2, 3, 5346 },
+ { 0xfdb3, 3, 5349 },
+ { 0xfdb4, 3, 5211 },
+ { 0xfdb5, 3, 5217 },
+ { 0xfdb6, 3, 5352 },
+ { 0xfdb7, 3, 5355 },
+ { 0xfdb8, 3, 5358 },
+ { 0xfdb9, 3, 5361 },
+ { 0xfdba, 3, 5364 },
+ { 0xfdbb, 3, 5367 },
+ { 0xfdbc, 3, 5364 },
+ { 0xfdbd, 3, 5358 },
+ { 0xfdbe, 3, 5370 },
+ { 0xfdbf, 3, 5373 },
+ { 0xfdc0, 3, 5376 },
+ { 0xfdc1, 3, 5379 },
+ { 0xfdc2, 3, 5382 },
+ { 0xfdc3, 3, 5367 },
+ { 0xfdc4, 3, 5190 },
+ { 0xfdc5, 3, 5160 },
+ { 0xfdc6, 3, 5385 },
+ { 0xfdc7, 3, 5388 },
+ { 0xfdf0, 3, 5391 },
+ { 0xfdf1, 3, 5394 },
+ { 0xfdf2, 4, 5397 },
+ { 0xfdf3, 4, 5401 },
+ { 0xfdf4, 4, 5405 },
+ { 0xfdf5, 4, 5409 },
+ { 0xfdf6, 4, 5413 },
+ { 0xfdf7, 4, 5417 },
+ { 0xfdf8, 4, 5421 },
+ { 0xfdf9, 3, 5425 },
+ { 0xfdfa, 18, 5428 },
+ { 0xfdfb, 8, 5446 },
+ { 0xfdfc, 4, 5454 },
+ { 0xfe30, 2, 2139 },
+ { 0xfe31, 1, 5458 },
+ { 0xfe32, 1, 5459 },
+ { 0xfe33, 1, 5460 },
+ { 0xfe34, 1, 5460 },
+ { 0xfe35, 1, 2179 },
+ { 0xfe36, 1, 2180 },
+ { 0xfe37, 1, 5461 },
+ { 0xfe38, 1, 5462 },
+ { 0xfe39, 1, 5463 },
+ { 0xfe3a, 1, 5464 },
+ { 0xfe3b, 1, 5465 },
+ { 0xfe3c, 1, 5466 },
+ { 0xfe3d, 1, 5467 },
+ { 0xfe3e, 1, 5468 },
+ { 0xfe3f, 1, 2425 },
+ { 0xfe40, 1, 2426 },
+ { 0xfe41, 1, 5469 },
+ { 0xfe42, 1, 5470 },
+ { 0xfe43, 1, 5471 },
+ { 0xfe44, 1, 5472 },
+ { 0xfe49, 2, 2156 },
+ { 0xfe4a, 2, 2156 },
+ { 0xfe4b, 2, 2156 },
+ { 0xfe4c, 2, 2156 },
+ { 0xfe4d, 1, 5460 },
+ { 0xfe4e, 1, 5460 },
+ { 0xfe4f, 1, 5460 },
+ { 0xfe50, 1, 5473 },
+ { 0xfe51, 1, 5474 },
+ { 0xfe52, 1, 2138 },
+ { 0xfe54, 1, 621 },
+ { 0xfe55, 1, 5475 },
+ { 0xfe56, 1, 5476 },
+ { 0xfe57, 1, 5477 },
+ { 0xfe58, 1, 5458 },
+ { 0xfe59, 1, 2179 },
+ { 0xfe5a, 1, 2180 },
+ { 0xfe5b, 1, 5461 },
+ { 0xfe5c, 1, 5462 },
+ { 0xfe5d, 1, 5463 },
+ { 0xfe5e, 1, 5464 },
+ { 0xfe5f, 1, 5478 },
+ { 0xfe60, 1, 5479 },
+ { 0xfe61, 1, 5480 },
+ { 0xfe62, 1, 2176 },
+ { 0xfe63, 1, 5481 },
+ { 0xfe64, 1, 5482 },
+ { 0xfe65, 1, 5483 },
+ { 0xfe66, 1, 2178 },
+ { 0xfe68, 1, 5484 },
+ { 0xfe69, 1, 5485 },
+ { 0xfe6a, 1, 5486 },
+ { 0xfe6b, 1, 5487 },
+ { 0xfe70, 2, 5488 },
+ { 0xfe71, 2, 5490 },
+ { 0xfe72, 2, 5492 },
+ { 0xfe74, 2, 5494 },
+ { 0xfe76, 2, 5496 },
+ { 0xfe77, 2, 5498 },
+ { 0xfe78, 2, 5500 },
+ { 0xfe79, 2, 5502 },
+ { 0xfe7a, 2, 5504 },
+ { 0xfe7b, 2, 5506 },
+ { 0xfe7c, 2, 5508 },
+ { 0xfe7d, 2, 5510 },
+ { 0xfe7e, 2, 5512 },
+ { 0xfe7f, 2, 5514 },
+ { 0xfe80, 1, 5516 },
+ { 0xfe81, 2, 784 },
+ { 0xfe82, 2, 784 },
+ { 0xfe83, 2, 786 },
+ { 0xfe84, 2, 786 },
+ { 0xfe85, 2, 788 },
+ { 0xfe86, 2, 788 },
+ { 0xfe87, 2, 790 },
+ { 0xfe88, 2, 790 },
+ { 0xfe89, 2, 792 },
+ { 0xfe8a, 2, 792 },
+ { 0xfe8b, 2, 792 },
+ { 0xfe8c, 2, 792 },
+ { 0xfe8d, 1, 5517 },
+ { 0xfe8e, 1, 5517 },
+ { 0xfe8f, 1, 5518 },
+ { 0xfe90, 1, 5518 },
+ { 0xfe91, 1, 5518 },
+ { 0xfe92, 1, 5518 },
+ { 0xfe93, 1, 5519 },
+ { 0xfe94, 1, 5519 },
+ { 0xfe95, 1, 5520 },
+ { 0xfe96, 1, 5520 },
+ { 0xfe97, 1, 5520 },
+ { 0xfe98, 1, 5520 },
+ { 0xfe99, 1, 5521 },
+ { 0xfe9a, 1, 5521 },
+ { 0xfe9b, 1, 5521 },
+ { 0xfe9c, 1, 5521 },
+ { 0xfe9d, 1, 5522 },
+ { 0xfe9e, 1, 5522 },
+ { 0xfe9f, 1, 5522 },
+ { 0xfea0, 1, 5522 },
+ { 0xfea1, 1, 5523 },
+ { 0xfea2, 1, 5523 },
+ { 0xfea3, 1, 5523 },
+ { 0xfea4, 1, 5523 },
+ { 0xfea5, 1, 5524 },
+ { 0xfea6, 1, 5524 },
+ { 0xfea7, 1, 5524 },
+ { 0xfea8, 1, 5524 },
+ { 0xfea9, 1, 5525 },
+ { 0xfeaa, 1, 5525 },
+ { 0xfeab, 1, 5526 },
+ { 0xfeac, 1, 5526 },
+ { 0xfead, 1, 5527 },
+ { 0xfeae, 1, 5527 },
+ { 0xfeaf, 1, 5528 },
+ { 0xfeb0, 1, 5528 },
+ { 0xfeb1, 1, 5529 },
+ { 0xfeb2, 1, 5529 },
+ { 0xfeb3, 1, 5529 },
+ { 0xfeb4, 1, 5529 },
+ { 0xfeb5, 1, 5530 },
+ { 0xfeb6, 1, 5530 },
+ { 0xfeb7, 1, 5530 },
+ { 0xfeb8, 1, 5530 },
+ { 0xfeb9, 1, 5531 },
+ { 0xfeba, 1, 5531 },
+ { 0xfebb, 1, 5531 },
+ { 0xfebc, 1, 5531 },
+ { 0xfebd, 1, 5532 },
+ { 0xfebe, 1, 5532 },
+ { 0xfebf, 1, 5532 },
+ { 0xfec0, 1, 5532 },
+ { 0xfec1, 1, 5533 },
+ { 0xfec2, 1, 5533 },
+ { 0xfec3, 1, 5533 },
+ { 0xfec4, 1, 5533 },
+ { 0xfec5, 1, 5534 },
+ { 0xfec6, 1, 5534 },
+ { 0xfec7, 1, 5534 },
+ { 0xfec8, 1, 5534 },
+ { 0xfec9, 1, 5535 },
+ { 0xfeca, 1, 5535 },
+ { 0xfecb, 1, 5535 },
+ { 0xfecc, 1, 5535 },
+ { 0xfecd, 1, 5536 },
+ { 0xfece, 1, 5536 },
+ { 0xfecf, 1, 5536 },
+ { 0xfed0, 1, 5536 },
+ { 0xfed1, 1, 5537 },
+ { 0xfed2, 1, 5537 },
+ { 0xfed3, 1, 5537 },
+ { 0xfed4, 1, 5537 },
+ { 0xfed5, 1, 5538 },
+ { 0xfed6, 1, 5538 },
+ { 0xfed7, 1, 5538 },
+ { 0xfed8, 1, 5538 },
+ { 0xfed9, 1, 5539 },
+ { 0xfeda, 1, 5539 },
+ { 0xfedb, 1, 5539 },
+ { 0xfedc, 1, 5539 },
+ { 0xfedd, 1, 5540 },
+ { 0xfede, 1, 5540 },
+ { 0xfedf, 1, 5540 },
+ { 0xfee0, 1, 5540 },
+ { 0xfee1, 1, 5541 },
+ { 0xfee2, 1, 5541 },
+ { 0xfee3, 1, 5541 },
+ { 0xfee4, 1, 5541 },
+ { 0xfee5, 1, 5542 },
+ { 0xfee6, 1, 5542 },
+ { 0xfee7, 1, 5542 },
+ { 0xfee8, 1, 5542 },
+ { 0xfee9, 1, 5543 },
+ { 0xfeea, 1, 5543 },
+ { 0xfeeb, 1, 5543 },
+ { 0xfeec, 1, 5543 },
+ { 0xfeed, 1, 5544 },
+ { 0xfeee, 1, 5544 },
+ { 0xfeef, 1, 4741 },
+ { 0xfef0, 1, 4741 },
+ { 0xfef1, 1, 5545 },
+ { 0xfef2, 1, 5545 },
+ { 0xfef3, 1, 5545 },
+ { 0xfef4, 1, 5545 },
+ { 0xfef5, 3, 5546 },
+ { 0xfef6, 3, 5546 },
+ { 0xfef7, 3, 5549 },
+ { 0xfef8, 3, 5549 },
+ { 0xfef9, 3, 5552 },
+ { 0xfefa, 3, 5552 },
+ { 0xfefb, 2, 5555 },
+ { 0xfefc, 2, 5555 },
+ { 0xff01, 1, 5477 },
+ { 0xff02, 1, 5557 },
+ { 0xff03, 1, 5478 },
+ { 0xff04, 1, 5485 },
+ { 0xff05, 1, 5486 },
+ { 0xff06, 1, 5479 },
+ { 0xff07, 1, 5558 },
+ { 0xff08, 1, 2179 },
+ { 0xff09, 1, 2180 },
+ { 0xff0a, 1, 5480 },
+ { 0xff0b, 1, 2176 },
+ { 0xff0c, 1, 5473 },
+ { 0xff0d, 1, 5481 },
+ { 0xff0e, 1, 2138 },
+ { 0xff0f, 1, 5559 },
+ { 0xff10, 1, 2168 },
+ { 0xff11, 1, 13 },
+ { 0xff12, 1, 6 },
+ { 0xff13, 1, 7 },
+ { 0xff14, 1, 2170 },
+ { 0xff15, 1, 2171 },
+ { 0xff16, 1, 2172 },
+ { 0xff17, 1, 2173 },
+ { 0xff18, 1, 2174 },
+ { 0xff19, 1, 2175 },
+ { 0xff1a, 1, 5475 },
+ { 0xff1b, 1, 621 },
+ { 0xff1c, 1, 5482 },
+ { 0xff1d, 1, 2178 },
+ { 0xff1e, 1, 5483 },
+ { 0xff1f, 1, 5476 },
+ { 0xff20, 1, 5487 },
+ { 0xff21, 1, 2649 },
+ { 0xff22, 1, 2223 },
+ { 0xff23, 1, 2190 },
+ { 0xff24, 1, 2236 },
+ { 0xff25, 1, 2225 },
+ { 0xff26, 1, 2226 },
+ { 0xff27, 1, 2650 },
+ { 0xff28, 1, 2203 },
+ { 0xff29, 1, 2205 },
+ { 0xff2a, 1, 2651 },
+ { 0xff2b, 1, 2222 },
+ { 0xff2c, 1, 2206 },
+ { 0xff2d, 1, 2227 },
+ { 0xff2e, 1, 2207 },
+ { 0xff2f, 1, 2652 },
+ { 0xff30, 1, 2210 },
+ { 0xff31, 1, 2211 },
+ { 0xff32, 1, 2212 },
+ { 0xff33, 1, 2653 },
+ { 0xff34, 1, 2654 },
+ { 0xff35, 1, 2655 },
+ { 0xff36, 1, 2283 },
+ { 0xff37, 1, 2656 },
+ { 0xff38, 1, 2295 },
+ { 0xff39, 1, 2657 },
+ { 0xff3a, 1, 2220 },
+ { 0xff3b, 1, 5560 },
+ { 0xff3c, 1, 5484 },
+ { 0xff3d, 1, 5561 },
+ { 0xff3e, 1, 5562 },
+ { 0xff3f, 1, 5460 },
+ { 0xff40, 1, 2113 },
+ { 0xff41, 1, 3 },
+ { 0xff42, 1, 2658 },
+ { 0xff43, 1, 2325 },
+ { 0xff44, 1, 2237 },
+ { 0xff45, 1, 2224 },
+ { 0xff46, 1, 2659 },
+ { 0xff47, 1, 2202 },
+ { 0xff48, 1, 588 },
+ { 0xff49, 1, 2169 },
+ { 0xff4a, 1, 590 },
+ { 0xff4b, 1, 2660 },
+ { 0xff4c, 1, 610 },
+ { 0xff4d, 1, 2326 },
+ { 0xff4e, 1, 2181 },
+ { 0xff4f, 1, 14 },
+ { 0xff50, 1, 2661 },
+ { 0xff51, 1, 2662 },
+ { 0xff52, 1, 591 },
+ { 0xff53, 1, 356 },
+ { 0xff54, 1, 2663 },
+ { 0xff55, 1, 2664 },
+ { 0xff56, 1, 2308 },
+ { 0xff57, 1, 595 },
+ { 0xff58, 1, 611 },
+ { 0xff59, 1, 596 },
+ { 0xff5a, 1, 2665 },
+ { 0xff5b, 1, 5461 },
+ { 0xff5c, 1, 5563 },
+ { 0xff5d, 1, 5462 },
+ { 0xff5e, 1, 5564 },
+ { 0xff5f, 1, 5565 },
+ { 0xff60, 1, 5566 },
+ { 0xff61, 1, 5567 },
+ { 0xff62, 1, 5469 },
+ { 0xff63, 1, 5470 },
+ { 0xff64, 1, 5474 },
+ { 0xff65, 1, 5568 },
+ { 0xff66, 1, 3530 },
+ { 0xff67, 1, 5569 },
+ { 0xff68, 1, 5570 },
+ { 0xff69, 1, 5571 },
+ { 0xff6a, 1, 5572 },
+ { 0xff6b, 1, 5573 },
+ { 0xff6c, 1, 5574 },
+ { 0xff6d, 1, 5575 },
+ { 0xff6e, 1, 5576 },
+ { 0xff6f, 1, 5577 },
+ { 0xff70, 1, 5578 },
+ { 0xff71, 1, 3484 },
+ { 0xff72, 1, 3485 },
+ { 0xff73, 1, 3486 },
+ { 0xff74, 1, 3487 },
+ { 0xff75, 1, 3488 },
+ { 0xff76, 1, 3489 },
+ { 0xff77, 1, 3490 },
+ { 0xff78, 1, 3491 },
+ { 0xff79, 1, 3492 },
+ { 0xff7a, 1, 3493 },
+ { 0xff7b, 1, 3494 },
+ { 0xff7c, 1, 3495 },
+ { 0xff7d, 1, 3496 },
+ { 0xff7e, 1, 3497 },
+ { 0xff7f, 1, 3498 },
+ { 0xff80, 1, 3499 },
+ { 0xff81, 1, 3500 },
+ { 0xff82, 1, 3501 },
+ { 0xff83, 1, 3502 },
+ { 0xff84, 1, 3503 },
+ { 0xff85, 1, 3504 },
+ { 0xff86, 1, 3505 },
+ { 0xff87, 1, 3506 },
+ { 0xff88, 1, 3507 },
+ { 0xff89, 1, 3508 },
+ { 0xff8a, 1, 3509 },
+ { 0xff8b, 1, 3510 },
+ { 0xff8c, 1, 3511 },
+ { 0xff8d, 1, 3512 },
+ { 0xff8e, 1, 3513 },
+ { 0xff8f, 1, 3514 },
+ { 0xff90, 1, 3515 },
+ { 0xff91, 1, 3516 },
+ { 0xff92, 1, 3517 },
+ { 0xff93, 1, 3518 },
+ { 0xff94, 1, 3519 },
+ { 0xff95, 1, 3520 },
+ { 0xff96, 1, 3521 },
+ { 0xff97, 1, 3522 },
+ { 0xff98, 1, 3523 },
+ { 0xff99, 1, 3524 },
+ { 0xff9a, 1, 3525 },
+ { 0xff9b, 1, 3526 },
+ { 0xff9c, 1, 3527 },
+ { 0xff9d, 1, 5579 },
+ { 0xff9e, 1, 5580 },
+ { 0xff9f, 1, 5581 },
+ { 0xffa0, 1, 3074 },
+ { 0xffa1, 1, 3023 },
+ { 0xffa2, 1, 3024 },
+ { 0xffa3, 1, 3025 },
+ { 0xffa4, 1, 3026 },
+ { 0xffa5, 1, 3027 },
+ { 0xffa6, 1, 3028 },
+ { 0xffa7, 1, 3029 },
+ { 0xffa8, 1, 3030 },
+ { 0xffa9, 1, 3031 },
+ { 0xffaa, 1, 3032 },
+ { 0xffab, 1, 3033 },
+ { 0xffac, 1, 3034 },
+ { 0xffad, 1, 3035 },
+ { 0xffae, 1, 3036 },
+ { 0xffaf, 1, 3037 },
+ { 0xffb0, 1, 3038 },
+ { 0xffb1, 1, 3039 },
+ { 0xffb2, 1, 3040 },
+ { 0xffb3, 1, 3041 },
+ { 0xffb4, 1, 3042 },
+ { 0xffb5, 1, 3043 },
+ { 0xffb6, 1, 3044 },
+ { 0xffb7, 1, 3045 },
+ { 0xffb8, 1, 3046 },
+ { 0xffb9, 1, 3047 },
+ { 0xffba, 1, 3048 },
+ { 0xffbb, 1, 3049 },
+ { 0xffbc, 1, 3050 },
+ { 0xffbd, 1, 3051 },
+ { 0xffbe, 1, 3052 },
+ { 0xffc2, 1, 3053 },
+ { 0xffc3, 1, 3054 },
+ { 0xffc4, 1, 3055 },
+ { 0xffc5, 1, 3056 },
+ { 0xffc6, 1, 3057 },
+ { 0xffc7, 1, 3058 },
+ { 0xffca, 1, 3059 },
+ { 0xffcb, 1, 3060 },
+ { 0xffcc, 1, 3061 },
+ { 0xffcd, 1, 3062 },
+ { 0xffce, 1, 3063 },
+ { 0xffcf, 1, 3064 },
+ { 0xffd2, 1, 3065 },
+ { 0xffd3, 1, 3066 },
+ { 0xffd4, 1, 3067 },
+ { 0xffd5, 1, 3068 },
+ { 0xffd6, 1, 3069 },
+ { 0xffd7, 1, 3070 },
+ { 0xffda, 1, 3071 },
+ { 0xffdb, 1, 3072 },
+ { 0xffdc, 1, 3073 },
+ { 0xffe0, 1, 5582 },
+ { 0xffe1, 1, 5583 },
+ { 0xffe2, 1, 5584 },
+ { 0xffe3, 2, 4 },
+ { 0xffe4, 1, 5585 },
+ { 0xffe5, 1, 5586 },
+ { 0xffe6, 1, 5587 },
+ { 0xffe8, 1, 5588 },
+ { 0xffe9, 1, 5589 },
+ { 0xffea, 1, 5590 },
+ { 0xffeb, 1, 5591 },
+ { 0xffec, 1, 5592 },
+ { 0xffed, 1, 5593 },
+ { 0xffee, 1, 5594 },
+ { 0x1d15e, 2, 5595 },
+ { 0x1d15f, 2, 5597 },
+ { 0x1d160, 3, 5599 },
+ { 0x1d161, 3, 5602 },
+ { 0x1d162, 3, 5605 },
+ { 0x1d163, 3, 5608 },
+ { 0x1d164, 3, 5611 },
+ { 0x1d1bb, 2, 5614 },
+ { 0x1d1bc, 2, 5616 },
+ { 0x1d1bd, 3, 5618 },
+ { 0x1d1be, 3, 5621 },
+ { 0x1d1bf, 3, 5624 },
+ { 0x1d1c0, 3, 5627 },
+ { 0x1d400, 1, 2649 },
+ { 0x1d401, 1, 2223 },
+ { 0x1d402, 1, 2190 },
+ { 0x1d403, 1, 2236 },
+ { 0x1d404, 1, 2225 },
+ { 0x1d405, 1, 2226 },
+ { 0x1d406, 1, 2650 },
+ { 0x1d407, 1, 2203 },
+ { 0x1d408, 1, 2205 },
+ { 0x1d409, 1, 2651 },
+ { 0x1d40a, 1, 2222 },
+ { 0x1d40b, 1, 2206 },
+ { 0x1d40c, 1, 2227 },
+ { 0x1d40d, 1, 2207 },
+ { 0x1d40e, 1, 2652 },
+ { 0x1d40f, 1, 2210 },
+ { 0x1d410, 1, 2211 },
+ { 0x1d411, 1, 2212 },
+ { 0x1d412, 1, 2653 },
+ { 0x1d413, 1, 2654 },
+ { 0x1d414, 1, 2655 },
+ { 0x1d415, 1, 2283 },
+ { 0x1d416, 1, 2656 },
+ { 0x1d417, 1, 2295 },
+ { 0x1d418, 1, 2657 },
+ { 0x1d419, 1, 2220 },
+ { 0x1d41a, 1, 3 },
+ { 0x1d41b, 1, 2658 },
+ { 0x1d41c, 1, 2325 },
+ { 0x1d41d, 1, 2237 },
+ { 0x1d41e, 1, 2224 },
+ { 0x1d41f, 1, 2659 },
+ { 0x1d420, 1, 2202 },
+ { 0x1d421, 1, 588 },
+ { 0x1d422, 1, 2169 },
+ { 0x1d423, 1, 590 },
+ { 0x1d424, 1, 2660 },
+ { 0x1d425, 1, 610 },
+ { 0x1d426, 1, 2326 },
+ { 0x1d427, 1, 2181 },
+ { 0x1d428, 1, 14 },
+ { 0x1d429, 1, 2661 },
+ { 0x1d42a, 1, 2662 },
+ { 0x1d42b, 1, 591 },
+ { 0x1d42c, 1, 356 },
+ { 0x1d42d, 1, 2663 },
+ { 0x1d42e, 1, 2664 },
+ { 0x1d42f, 1, 2308 },
+ { 0x1d430, 1, 595 },
+ { 0x1d431, 1, 611 },
+ { 0x1d432, 1, 596 },
+ { 0x1d433, 1, 2665 },
+ { 0x1d434, 1, 2649 },
+ { 0x1d435, 1, 2223 },
+ { 0x1d436, 1, 2190 },
+ { 0x1d437, 1, 2236 },
+ { 0x1d438, 1, 2225 },
+ { 0x1d439, 1, 2226 },
+ { 0x1d43a, 1, 2650 },
+ { 0x1d43b, 1, 2203 },
+ { 0x1d43c, 1, 2205 },
+ { 0x1d43d, 1, 2651 },
+ { 0x1d43e, 1, 2222 },
+ { 0x1d43f, 1, 2206 },
+ { 0x1d440, 1, 2227 },
+ { 0x1d441, 1, 2207 },
+ { 0x1d442, 1, 2652 },
+ { 0x1d443, 1, 2210 },
+ { 0x1d444, 1, 2211 },
+ { 0x1d445, 1, 2212 },
+ { 0x1d446, 1, 2653 },
+ { 0x1d447, 1, 2654 },
+ { 0x1d448, 1, 2655 },
+ { 0x1d449, 1, 2283 },
+ { 0x1d44a, 1, 2656 },
+ { 0x1d44b, 1, 2295 },
+ { 0x1d44c, 1, 2657 },
+ { 0x1d44d, 1, 2220 },
+ { 0x1d44e, 1, 3 },
+ { 0x1d44f, 1, 2658 },
+ { 0x1d450, 1, 2325 },
+ { 0x1d451, 1, 2237 },
+ { 0x1d452, 1, 2224 },
+ { 0x1d453, 1, 2659 },
+ { 0x1d454, 1, 2202 },
+ { 0x1d456, 1, 2169 },
+ { 0x1d457, 1, 590 },
+ { 0x1d458, 1, 2660 },
+ { 0x1d459, 1, 610 },
+ { 0x1d45a, 1, 2326 },
+ { 0x1d45b, 1, 2181 },
+ { 0x1d45c, 1, 14 },
+ { 0x1d45d, 1, 2661 },
+ { 0x1d45e, 1, 2662 },
+ { 0x1d45f, 1, 591 },
+ { 0x1d460, 1, 356 },
+ { 0x1d461, 1, 2663 },
+ { 0x1d462, 1, 2664 },
+ { 0x1d463, 1, 2308 },
+ { 0x1d464, 1, 595 },
+ { 0x1d465, 1, 611 },
+ { 0x1d466, 1, 596 },
+ { 0x1d467, 1, 2665 },
+ { 0x1d468, 1, 2649 },
+ { 0x1d469, 1, 2223 },
+ { 0x1d46a, 1, 2190 },
+ { 0x1d46b, 1, 2236 },
+ { 0x1d46c, 1, 2225 },
+ { 0x1d46d, 1, 2226 },
+ { 0x1d46e, 1, 2650 },
+ { 0x1d46f, 1, 2203 },
+ { 0x1d470, 1, 2205 },
+ { 0x1d471, 1, 2651 },
+ { 0x1d472, 1, 2222 },
+ { 0x1d473, 1, 2206 },
+ { 0x1d474, 1, 2227 },
+ { 0x1d475, 1, 2207 },
+ { 0x1d476, 1, 2652 },
+ { 0x1d477, 1, 2210 },
+ { 0x1d478, 1, 2211 },
+ { 0x1d479, 1, 2212 },
+ { 0x1d47a, 1, 2653 },
+ { 0x1d47b, 1, 2654 },
+ { 0x1d47c, 1, 2655 },
+ { 0x1d47d, 1, 2283 },
+ { 0x1d47e, 1, 2656 },
+ { 0x1d47f, 1, 2295 },
+ { 0x1d480, 1, 2657 },
+ { 0x1d481, 1, 2220 },
+ { 0x1d482, 1, 3 },
+ { 0x1d483, 1, 2658 },
+ { 0x1d484, 1, 2325 },
+ { 0x1d485, 1, 2237 },
+ { 0x1d486, 1, 2224 },
+ { 0x1d487, 1, 2659 },
+ { 0x1d488, 1, 2202 },
+ { 0x1d489, 1, 588 },
+ { 0x1d48a, 1, 2169 },
+ { 0x1d48b, 1, 590 },
+ { 0x1d48c, 1, 2660 },
+ { 0x1d48d, 1, 610 },
+ { 0x1d48e, 1, 2326 },
+ { 0x1d48f, 1, 2181 },
+ { 0x1d490, 1, 14 },
+ { 0x1d491, 1, 2661 },
+ { 0x1d492, 1, 2662 },
+ { 0x1d493, 1, 591 },
+ { 0x1d494, 1, 356 },
+ { 0x1d495, 1, 2663 },
+ { 0x1d496, 1, 2664 },
+ { 0x1d497, 1, 2308 },
+ { 0x1d498, 1, 595 },
+ { 0x1d499, 1, 611 },
+ { 0x1d49a, 1, 596 },
+ { 0x1d49b, 1, 2665 },
+ { 0x1d49c, 1, 2649 },
+ { 0x1d49e, 1, 2190 },
+ { 0x1d49f, 1, 2236 },
+ { 0x1d4a2, 1, 2650 },
+ { 0x1d4a5, 1, 2651 },
+ { 0x1d4a6, 1, 2222 },
+ { 0x1d4a9, 1, 2207 },
+ { 0x1d4aa, 1, 2652 },
+ { 0x1d4ab, 1, 2210 },
+ { 0x1d4ac, 1, 2211 },
+ { 0x1d4ae, 1, 2653 },
+ { 0x1d4af, 1, 2654 },
+ { 0x1d4b0, 1, 2655 },
+ { 0x1d4b1, 1, 2283 },
+ { 0x1d4b2, 1, 2656 },
+ { 0x1d4b3, 1, 2295 },
+ { 0x1d4b4, 1, 2657 },
+ { 0x1d4b5, 1, 2220 },
+ { 0x1d4b6, 1, 3 },
+ { 0x1d4b7, 1, 2658 },
+ { 0x1d4b8, 1, 2325 },
+ { 0x1d4b9, 1, 2237 },
+ { 0x1d4bb, 1, 2659 },
+ { 0x1d4bd, 1, 588 },
+ { 0x1d4be, 1, 2169 },
+ { 0x1d4bf, 1, 590 },
+ { 0x1d4c0, 1, 2660 },
+ { 0x1d4c2, 1, 2326 },
+ { 0x1d4c3, 1, 2181 },
+ { 0x1d4c5, 1, 2661 },
+ { 0x1d4c6, 1, 2662 },
+ { 0x1d4c7, 1, 591 },
+ { 0x1d4c8, 1, 356 },
+ { 0x1d4c9, 1, 2663 },
+ { 0x1d4ca, 1, 2664 },
+ { 0x1d4cb, 1, 2308 },
+ { 0x1d4cc, 1, 595 },
+ { 0x1d4cd, 1, 611 },
+ { 0x1d4ce, 1, 596 },
+ { 0x1d4cf, 1, 2665 },
+ { 0x1d4d0, 1, 2649 },
+ { 0x1d4d1, 1, 2223 },
+ { 0x1d4d2, 1, 2190 },
+ { 0x1d4d3, 1, 2236 },
+ { 0x1d4d4, 1, 2225 },
+ { 0x1d4d5, 1, 2226 },
+ { 0x1d4d6, 1, 2650 },
+ { 0x1d4d7, 1, 2203 },
+ { 0x1d4d8, 1, 2205 },
+ { 0x1d4d9, 1, 2651 },
+ { 0x1d4da, 1, 2222 },
+ { 0x1d4db, 1, 2206 },
+ { 0x1d4dc, 1, 2227 },
+ { 0x1d4dd, 1, 2207 },
+ { 0x1d4de, 1, 2652 },
+ { 0x1d4df, 1, 2210 },
+ { 0x1d4e0, 1, 2211 },
+ { 0x1d4e1, 1, 2212 },
+ { 0x1d4e2, 1, 2653 },
+ { 0x1d4e3, 1, 2654 },
+ { 0x1d4e4, 1, 2655 },
+ { 0x1d4e5, 1, 2283 },
+ { 0x1d4e6, 1, 2656 },
+ { 0x1d4e7, 1, 2295 },
+ { 0x1d4e8, 1, 2657 },
+ { 0x1d4e9, 1, 2220 },
+ { 0x1d4ea, 1, 3 },
+ { 0x1d4eb, 1, 2658 },
+ { 0x1d4ec, 1, 2325 },
+ { 0x1d4ed, 1, 2237 },
+ { 0x1d4ee, 1, 2224 },
+ { 0x1d4ef, 1, 2659 },
+ { 0x1d4f0, 1, 2202 },
+ { 0x1d4f1, 1, 588 },
+ { 0x1d4f2, 1, 2169 },
+ { 0x1d4f3, 1, 590 },
+ { 0x1d4f4, 1, 2660 },
+ { 0x1d4f5, 1, 610 },
+ { 0x1d4f6, 1, 2326 },
+ { 0x1d4f7, 1, 2181 },
+ { 0x1d4f8, 1, 14 },
+ { 0x1d4f9, 1, 2661 },
+ { 0x1d4fa, 1, 2662 },
+ { 0x1d4fb, 1, 591 },
+ { 0x1d4fc, 1, 356 },
+ { 0x1d4fd, 1, 2663 },
+ { 0x1d4fe, 1, 2664 },
+ { 0x1d4ff, 1, 2308 },
+ { 0x1d500, 1, 595 },
+ { 0x1d501, 1, 611 },
+ { 0x1d502, 1, 596 },
+ { 0x1d503, 1, 2665 },
+ { 0x1d504, 1, 2649 },
+ { 0x1d505, 1, 2223 },
+ { 0x1d507, 1, 2236 },
+ { 0x1d508, 1, 2225 },
+ { 0x1d509, 1, 2226 },
+ { 0x1d50a, 1, 2650 },
+ { 0x1d50d, 1, 2651 },
+ { 0x1d50e, 1, 2222 },
+ { 0x1d50f, 1, 2206 },
+ { 0x1d510, 1, 2227 },
+ { 0x1d511, 1, 2207 },
+ { 0x1d512, 1, 2652 },
+ { 0x1d513, 1, 2210 },
+ { 0x1d514, 1, 2211 },
+ { 0x1d516, 1, 2653 },
+ { 0x1d517, 1, 2654 },
+ { 0x1d518, 1, 2655 },
+ { 0x1d519, 1, 2283 },
+ { 0x1d51a, 1, 2656 },
+ { 0x1d51b, 1, 2295 },
+ { 0x1d51c, 1, 2657 },
+ { 0x1d51e, 1, 3 },
+ { 0x1d51f, 1, 2658 },
+ { 0x1d520, 1, 2325 },
+ { 0x1d521, 1, 2237 },
+ { 0x1d522, 1, 2224 },
+ { 0x1d523, 1, 2659 },
+ { 0x1d524, 1, 2202 },
+ { 0x1d525, 1, 588 },
+ { 0x1d526, 1, 2169 },
+ { 0x1d527, 1, 590 },
+ { 0x1d528, 1, 2660 },
+ { 0x1d529, 1, 610 },
+ { 0x1d52a, 1, 2326 },
+ { 0x1d52b, 1, 2181 },
+ { 0x1d52c, 1, 14 },
+ { 0x1d52d, 1, 2661 },
+ { 0x1d52e, 1, 2662 },
+ { 0x1d52f, 1, 591 },
+ { 0x1d530, 1, 356 },
+ { 0x1d531, 1, 2663 },
+ { 0x1d532, 1, 2664 },
+ { 0x1d533, 1, 2308 },
+ { 0x1d534, 1, 595 },
+ { 0x1d535, 1, 611 },
+ { 0x1d536, 1, 596 },
+ { 0x1d537, 1, 2665 },
+ { 0x1d538, 1, 2649 },
+ { 0x1d539, 1, 2223 },
+ { 0x1d53b, 1, 2236 },
+ { 0x1d53c, 1, 2225 },
+ { 0x1d53d, 1, 2226 },
+ { 0x1d53e, 1, 2650 },
+ { 0x1d540, 1, 2205 },
+ { 0x1d541, 1, 2651 },
+ { 0x1d542, 1, 2222 },
+ { 0x1d543, 1, 2206 },
+ { 0x1d544, 1, 2227 },
+ { 0x1d546, 1, 2652 },
+ { 0x1d54a, 1, 2653 },
+ { 0x1d54b, 1, 2654 },
+ { 0x1d54c, 1, 2655 },
+ { 0x1d54d, 1, 2283 },
+ { 0x1d54e, 1, 2656 },
+ { 0x1d54f, 1, 2295 },
+ { 0x1d550, 1, 2657 },
+ { 0x1d552, 1, 3 },
+ { 0x1d553, 1, 2658 },
+ { 0x1d554, 1, 2325 },
+ { 0x1d555, 1, 2237 },
+ { 0x1d556, 1, 2224 },
+ { 0x1d557, 1, 2659 },
+ { 0x1d558, 1, 2202 },
+ { 0x1d559, 1, 588 },
+ { 0x1d55a, 1, 2169 },
+ { 0x1d55b, 1, 590 },
+ { 0x1d55c, 1, 2660 },
+ { 0x1d55d, 1, 610 },
+ { 0x1d55e, 1, 2326 },
+ { 0x1d55f, 1, 2181 },
+ { 0x1d560, 1, 14 },
+ { 0x1d561, 1, 2661 },
+ { 0x1d562, 1, 2662 },
+ { 0x1d563, 1, 591 },
+ { 0x1d564, 1, 356 },
+ { 0x1d565, 1, 2663 },
+ { 0x1d566, 1, 2664 },
+ { 0x1d567, 1, 2308 },
+ { 0x1d568, 1, 595 },
+ { 0x1d569, 1, 611 },
+ { 0x1d56a, 1, 596 },
+ { 0x1d56b, 1, 2665 },
+ { 0x1d56c, 1, 2649 },
+ { 0x1d56d, 1, 2223 },
+ { 0x1d56e, 1, 2190 },
+ { 0x1d56f, 1, 2236 },
+ { 0x1d570, 1, 2225 },
+ { 0x1d571, 1, 2226 },
+ { 0x1d572, 1, 2650 },
+ { 0x1d573, 1, 2203 },
+ { 0x1d574, 1, 2205 },
+ { 0x1d575, 1, 2651 },
+ { 0x1d576, 1, 2222 },
+ { 0x1d577, 1, 2206 },
+ { 0x1d578, 1, 2227 },
+ { 0x1d579, 1, 2207 },
+ { 0x1d57a, 1, 2652 },
+ { 0x1d57b, 1, 2210 },
+ { 0x1d57c, 1, 2211 },
+ { 0x1d57d, 1, 2212 },
+ { 0x1d57e, 1, 2653 },
+ { 0x1d57f, 1, 2654 },
+ { 0x1d580, 1, 2655 },
+ { 0x1d581, 1, 2283 },
+ { 0x1d582, 1, 2656 },
+ { 0x1d583, 1, 2295 },
+ { 0x1d584, 1, 2657 },
+ { 0x1d585, 1, 2220 },
+ { 0x1d586, 1, 3 },
+ { 0x1d587, 1, 2658 },
+ { 0x1d588, 1, 2325 },
+ { 0x1d589, 1, 2237 },
+ { 0x1d58a, 1, 2224 },
+ { 0x1d58b, 1, 2659 },
+ { 0x1d58c, 1, 2202 },
+ { 0x1d58d, 1, 588 },
+ { 0x1d58e, 1, 2169 },
+ { 0x1d58f, 1, 590 },
+ { 0x1d590, 1, 2660 },
+ { 0x1d591, 1, 610 },
+ { 0x1d592, 1, 2326 },
+ { 0x1d593, 1, 2181 },
+ { 0x1d594, 1, 14 },
+ { 0x1d595, 1, 2661 },
+ { 0x1d596, 1, 2662 },
+ { 0x1d597, 1, 591 },
+ { 0x1d598, 1, 356 },
+ { 0x1d599, 1, 2663 },
+ { 0x1d59a, 1, 2664 },
+ { 0x1d59b, 1, 2308 },
+ { 0x1d59c, 1, 595 },
+ { 0x1d59d, 1, 611 },
+ { 0x1d59e, 1, 596 },
+ { 0x1d59f, 1, 2665 },
+ { 0x1d5a0, 1, 2649 },
+ { 0x1d5a1, 1, 2223 },
+ { 0x1d5a2, 1, 2190 },
+ { 0x1d5a3, 1, 2236 },
+ { 0x1d5a4, 1, 2225 },
+ { 0x1d5a5, 1, 2226 },
+ { 0x1d5a6, 1, 2650 },
+ { 0x1d5a7, 1, 2203 },
+ { 0x1d5a8, 1, 2205 },
+ { 0x1d5a9, 1, 2651 },
+ { 0x1d5aa, 1, 2222 },
+ { 0x1d5ab, 1, 2206 },
+ { 0x1d5ac, 1, 2227 },
+ { 0x1d5ad, 1, 2207 },
+ { 0x1d5ae, 1, 2652 },
+ { 0x1d5af, 1, 2210 },
+ { 0x1d5b0, 1, 2211 },
+ { 0x1d5b1, 1, 2212 },
+ { 0x1d5b2, 1, 2653 },
+ { 0x1d5b3, 1, 2654 },
+ { 0x1d5b4, 1, 2655 },
+ { 0x1d5b5, 1, 2283 },
+ { 0x1d5b6, 1, 2656 },
+ { 0x1d5b7, 1, 2295 },
+ { 0x1d5b8, 1, 2657 },
+ { 0x1d5b9, 1, 2220 },
+ { 0x1d5ba, 1, 3 },
+ { 0x1d5bb, 1, 2658 },
+ { 0x1d5bc, 1, 2325 },
+ { 0x1d5bd, 1, 2237 },
+ { 0x1d5be, 1, 2224 },
+ { 0x1d5bf, 1, 2659 },
+ { 0x1d5c0, 1, 2202 },
+ { 0x1d5c1, 1, 588 },
+ { 0x1d5c2, 1, 2169 },
+ { 0x1d5c3, 1, 590 },
+ { 0x1d5c4, 1, 2660 },
+ { 0x1d5c5, 1, 610 },
+ { 0x1d5c6, 1, 2326 },
+ { 0x1d5c7, 1, 2181 },
+ { 0x1d5c8, 1, 14 },
+ { 0x1d5c9, 1, 2661 },
+ { 0x1d5ca, 1, 2662 },
+ { 0x1d5cb, 1, 591 },
+ { 0x1d5cc, 1, 356 },
+ { 0x1d5cd, 1, 2663 },
+ { 0x1d5ce, 1, 2664 },
+ { 0x1d5cf, 1, 2308 },
+ { 0x1d5d0, 1, 595 },
+ { 0x1d5d1, 1, 611 },
+ { 0x1d5d2, 1, 596 },
+ { 0x1d5d3, 1, 2665 },
+ { 0x1d5d4, 1, 2649 },
+ { 0x1d5d5, 1, 2223 },
+ { 0x1d5d6, 1, 2190 },
+ { 0x1d5d7, 1, 2236 },
+ { 0x1d5d8, 1, 2225 },
+ { 0x1d5d9, 1, 2226 },
+ { 0x1d5da, 1, 2650 },
+ { 0x1d5db, 1, 2203 },
+ { 0x1d5dc, 1, 2205 },
+ { 0x1d5dd, 1, 2651 },
+ { 0x1d5de, 1, 2222 },
+ { 0x1d5df, 1, 2206 },
+ { 0x1d5e0, 1, 2227 },
+ { 0x1d5e1, 1, 2207 },
+ { 0x1d5e2, 1, 2652 },
+ { 0x1d5e3, 1, 2210 },
+ { 0x1d5e4, 1, 2211 },
+ { 0x1d5e5, 1, 2212 },
+ { 0x1d5e6, 1, 2653 },
+ { 0x1d5e7, 1, 2654 },
+ { 0x1d5e8, 1, 2655 },
+ { 0x1d5e9, 1, 2283 },
+ { 0x1d5ea, 1, 2656 },
+ { 0x1d5eb, 1, 2295 },
+ { 0x1d5ec, 1, 2657 },
+ { 0x1d5ed, 1, 2220 },
+ { 0x1d5ee, 1, 3 },
+ { 0x1d5ef, 1, 2658 },
+ { 0x1d5f0, 1, 2325 },
+ { 0x1d5f1, 1, 2237 },
+ { 0x1d5f2, 1, 2224 },
+ { 0x1d5f3, 1, 2659 },
+ { 0x1d5f4, 1, 2202 },
+ { 0x1d5f5, 1, 588 },
+ { 0x1d5f6, 1, 2169 },
+ { 0x1d5f7, 1, 590 },
+ { 0x1d5f8, 1, 2660 },
+ { 0x1d5f9, 1, 610 },
+ { 0x1d5fa, 1, 2326 },
+ { 0x1d5fb, 1, 2181 },
+ { 0x1d5fc, 1, 14 },
+ { 0x1d5fd, 1, 2661 },
+ { 0x1d5fe, 1, 2662 },
+ { 0x1d5ff, 1, 591 },
+ { 0x1d600, 1, 356 },
+ { 0x1d601, 1, 2663 },
+ { 0x1d602, 1, 2664 },
+ { 0x1d603, 1, 2308 },
+ { 0x1d604, 1, 595 },
+ { 0x1d605, 1, 611 },
+ { 0x1d606, 1, 596 },
+ { 0x1d607, 1, 2665 },
+ { 0x1d608, 1, 2649 },
+ { 0x1d609, 1, 2223 },
+ { 0x1d60a, 1, 2190 },
+ { 0x1d60b, 1, 2236 },
+ { 0x1d60c, 1, 2225 },
+ { 0x1d60d, 1, 2226 },
+ { 0x1d60e, 1, 2650 },
+ { 0x1d60f, 1, 2203 },
+ { 0x1d610, 1, 2205 },
+ { 0x1d611, 1, 2651 },
+ { 0x1d612, 1, 2222 },
+ { 0x1d613, 1, 2206 },
+ { 0x1d614, 1, 2227 },
+ { 0x1d615, 1, 2207 },
+ { 0x1d616, 1, 2652 },
+ { 0x1d617, 1, 2210 },
+ { 0x1d618, 1, 2211 },
+ { 0x1d619, 1, 2212 },
+ { 0x1d61a, 1, 2653 },
+ { 0x1d61b, 1, 2654 },
+ { 0x1d61c, 1, 2655 },
+ { 0x1d61d, 1, 2283 },
+ { 0x1d61e, 1, 2656 },
+ { 0x1d61f, 1, 2295 },
+ { 0x1d620, 1, 2657 },
+ { 0x1d621, 1, 2220 },
+ { 0x1d622, 1, 3 },
+ { 0x1d623, 1, 2658 },
+ { 0x1d624, 1, 2325 },
+ { 0x1d625, 1, 2237 },
+ { 0x1d626, 1, 2224 },
+ { 0x1d627, 1, 2659 },
+ { 0x1d628, 1, 2202 },
+ { 0x1d629, 1, 588 },
+ { 0x1d62a, 1, 2169 },
+ { 0x1d62b, 1, 590 },
+ { 0x1d62c, 1, 2660 },
+ { 0x1d62d, 1, 610 },
+ { 0x1d62e, 1, 2326 },
+ { 0x1d62f, 1, 2181 },
+ { 0x1d630, 1, 14 },
+ { 0x1d631, 1, 2661 },
+ { 0x1d632, 1, 2662 },
+ { 0x1d633, 1, 591 },
+ { 0x1d634, 1, 356 },
+ { 0x1d635, 1, 2663 },
+ { 0x1d636, 1, 2664 },
+ { 0x1d637, 1, 2308 },
+ { 0x1d638, 1, 595 },
+ { 0x1d639, 1, 611 },
+ { 0x1d63a, 1, 596 },
+ { 0x1d63b, 1, 2665 },
+ { 0x1d63c, 1, 2649 },
+ { 0x1d63d, 1, 2223 },
+ { 0x1d63e, 1, 2190 },
+ { 0x1d63f, 1, 2236 },
+ { 0x1d640, 1, 2225 },
+ { 0x1d641, 1, 2226 },
+ { 0x1d642, 1, 2650 },
+ { 0x1d643, 1, 2203 },
+ { 0x1d644, 1, 2205 },
+ { 0x1d645, 1, 2651 },
+ { 0x1d646, 1, 2222 },
+ { 0x1d647, 1, 2206 },
+ { 0x1d648, 1, 2227 },
+ { 0x1d649, 1, 2207 },
+ { 0x1d64a, 1, 2652 },
+ { 0x1d64b, 1, 2210 },
+ { 0x1d64c, 1, 2211 },
+ { 0x1d64d, 1, 2212 },
+ { 0x1d64e, 1, 2653 },
+ { 0x1d64f, 1, 2654 },
+ { 0x1d650, 1, 2655 },
+ { 0x1d651, 1, 2283 },
+ { 0x1d652, 1, 2656 },
+ { 0x1d653, 1, 2295 },
+ { 0x1d654, 1, 2657 },
+ { 0x1d655, 1, 2220 },
+ { 0x1d656, 1, 3 },
+ { 0x1d657, 1, 2658 },
+ { 0x1d658, 1, 2325 },
+ { 0x1d659, 1, 2237 },
+ { 0x1d65a, 1, 2224 },
+ { 0x1d65b, 1, 2659 },
+ { 0x1d65c, 1, 2202 },
+ { 0x1d65d, 1, 588 },
+ { 0x1d65e, 1, 2169 },
+ { 0x1d65f, 1, 590 },
+ { 0x1d660, 1, 2660 },
+ { 0x1d661, 1, 610 },
+ { 0x1d662, 1, 2326 },
+ { 0x1d663, 1, 2181 },
+ { 0x1d664, 1, 14 },
+ { 0x1d665, 1, 2661 },
+ { 0x1d666, 1, 2662 },
+ { 0x1d667, 1, 591 },
+ { 0x1d668, 1, 356 },
+ { 0x1d669, 1, 2663 },
+ { 0x1d66a, 1, 2664 },
+ { 0x1d66b, 1, 2308 },
+ { 0x1d66c, 1, 595 },
+ { 0x1d66d, 1, 611 },
+ { 0x1d66e, 1, 596 },
+ { 0x1d66f, 1, 2665 },
+ { 0x1d670, 1, 2649 },
+ { 0x1d671, 1, 2223 },
+ { 0x1d672, 1, 2190 },
+ { 0x1d673, 1, 2236 },
+ { 0x1d674, 1, 2225 },
+ { 0x1d675, 1, 2226 },
+ { 0x1d676, 1, 2650 },
+ { 0x1d677, 1, 2203 },
+ { 0x1d678, 1, 2205 },
+ { 0x1d679, 1, 2651 },
+ { 0x1d67a, 1, 2222 },
+ { 0x1d67b, 1, 2206 },
+ { 0x1d67c, 1, 2227 },
+ { 0x1d67d, 1, 2207 },
+ { 0x1d67e, 1, 2652 },
+ { 0x1d67f, 1, 2210 },
+ { 0x1d680, 1, 2211 },
+ { 0x1d681, 1, 2212 },
+ { 0x1d682, 1, 2653 },
+ { 0x1d683, 1, 2654 },
+ { 0x1d684, 1, 2655 },
+ { 0x1d685, 1, 2283 },
+ { 0x1d686, 1, 2656 },
+ { 0x1d687, 1, 2295 },
+ { 0x1d688, 1, 2657 },
+ { 0x1d689, 1, 2220 },
+ { 0x1d68a, 1, 3 },
+ { 0x1d68b, 1, 2658 },
+ { 0x1d68c, 1, 2325 },
+ { 0x1d68d, 1, 2237 },
+ { 0x1d68e, 1, 2224 },
+ { 0x1d68f, 1, 2659 },
+ { 0x1d690, 1, 2202 },
+ { 0x1d691, 1, 588 },
+ { 0x1d692, 1, 2169 },
+ { 0x1d693, 1, 590 },
+ { 0x1d694, 1, 2660 },
+ { 0x1d695, 1, 610 },
+ { 0x1d696, 1, 2326 },
+ { 0x1d697, 1, 2181 },
+ { 0x1d698, 1, 14 },
+ { 0x1d699, 1, 2661 },
+ { 0x1d69a, 1, 2662 },
+ { 0x1d69b, 1, 591 },
+ { 0x1d69c, 1, 356 },
+ { 0x1d69d, 1, 2663 },
+ { 0x1d69e, 1, 2664 },
+ { 0x1d69f, 1, 2308 },
+ { 0x1d6a0, 1, 595 },
+ { 0x1d6a1, 1, 611 },
+ { 0x1d6a2, 1, 596 },
+ { 0x1d6a3, 1, 2665 },
+ { 0x1d6a8, 1, 5630 },
+ { 0x1d6a9, 1, 5631 },
+ { 0x1d6aa, 1, 2233 },
+ { 0x1d6ab, 1, 5632 },
+ { 0x1d6ac, 1, 5633 },
+ { 0x1d6ad, 1, 5634 },
+ { 0x1d6ae, 1, 5635 },
+ { 0x1d6af, 1, 676 },
+ { 0x1d6b0, 1, 5636 },
+ { 0x1d6b1, 1, 5637 },
+ { 0x1d6b2, 1, 5638 },
+ { 0x1d6b3, 1, 5639 },
+ { 0x1d6b4, 1, 5640 },
+ { 0x1d6b5, 1, 5641 },
+ { 0x1d6b6, 1, 5642 },
+ { 0x1d6b7, 1, 2234 },
+ { 0x1d6b8, 1, 5643 },
+ { 0x1d6b9, 1, 676 },
+ { 0x1d6ba, 1, 5644 },
+ { 0x1d6bb, 1, 5645 },
+ { 0x1d6bc, 1, 670 },
+ { 0x1d6bd, 1, 5646 },
+ { 0x1d6be, 1, 5647 },
+ { 0x1d6bf, 1, 5648 },
+ { 0x1d6c0, 1, 2221 },
+ { 0x1d6c1, 1, 5649 },
+ { 0x1d6c2, 1, 5650 },
+ { 0x1d6c3, 1, 668 },
+ { 0x1d6c4, 1, 2232 },
+ { 0x1d6c5, 1, 5651 },
+ { 0x1d6c6, 1, 677 },
+ { 0x1d6c7, 1, 5652 },
+ { 0x1d6c8, 1, 5653 },
+ { 0x1d6c9, 1, 669 },
+ { 0x1d6ca, 1, 2025 },
+ { 0x1d6cb, 1, 673 },
+ { 0x1d6cc, 1, 5654 },
+ { 0x1d6cd, 1, 10 },
+ { 0x1d6ce, 1, 5655 },
+ { 0x1d6cf, 1, 5656 },
+ { 0x1d6d0, 1, 5657 },
+ { 0x1d6d1, 1, 672 },
+ { 0x1d6d2, 1, 674 },
+ { 0x1d6d3, 1, 675 },
+ { 0x1d6d4, 1, 5658 },
+ { 0x1d6d5, 1, 5659 },
+ { 0x1d6d6, 1, 5660 },
+ { 0x1d6d7, 1, 671 },
+ { 0x1d6d8, 1, 5661 },
+ { 0x1d6d9, 1, 5662 },
+ { 0x1d6da, 1, 5663 },
+ { 0x1d6db, 1, 5664 },
+ { 0x1d6dc, 1, 677 },
+ { 0x1d6dd, 1, 669 },
+ { 0x1d6de, 1, 673 },
+ { 0x1d6df, 1, 671 },
+ { 0x1d6e0, 1, 674 },
+ { 0x1d6e1, 1, 672 },
+ { 0x1d6e2, 1, 5630 },
+ { 0x1d6e3, 1, 5631 },
+ { 0x1d6e4, 1, 2233 },
+ { 0x1d6e5, 1, 5632 },
+ { 0x1d6e6, 1, 5633 },
+ { 0x1d6e7, 1, 5634 },
+ { 0x1d6e8, 1, 5635 },
+ { 0x1d6e9, 1, 676 },
+ { 0x1d6ea, 1, 5636 },
+ { 0x1d6eb, 1, 5637 },
+ { 0x1d6ec, 1, 5638 },
+ { 0x1d6ed, 1, 5639 },
+ { 0x1d6ee, 1, 5640 },
+ { 0x1d6ef, 1, 5641 },
+ { 0x1d6f0, 1, 5642 },
+ { 0x1d6f1, 1, 2234 },
+ { 0x1d6f2, 1, 5643 },
+ { 0x1d6f3, 1, 676 },
+ { 0x1d6f4, 1, 5644 },
+ { 0x1d6f5, 1, 5645 },
+ { 0x1d6f6, 1, 670 },
+ { 0x1d6f7, 1, 5646 },
+ { 0x1d6f8, 1, 5647 },
+ { 0x1d6f9, 1, 5648 },
+ { 0x1d6fa, 1, 2221 },
+ { 0x1d6fb, 1, 5649 },
+ { 0x1d6fc, 1, 5650 },
+ { 0x1d6fd, 1, 668 },
+ { 0x1d6fe, 1, 2232 },
+ { 0x1d6ff, 1, 5651 },
+ { 0x1d700, 1, 677 },
+ { 0x1d701, 1, 5652 },
+ { 0x1d702, 1, 5653 },
+ { 0x1d703, 1, 669 },
+ { 0x1d704, 1, 2025 },
+ { 0x1d705, 1, 673 },
+ { 0x1d706, 1, 5654 },
+ { 0x1d707, 1, 10 },
+ { 0x1d708, 1, 5655 },
+ { 0x1d709, 1, 5656 },
+ { 0x1d70a, 1, 5657 },
+ { 0x1d70b, 1, 672 },
+ { 0x1d70c, 1, 674 },
+ { 0x1d70d, 1, 675 },
+ { 0x1d70e, 1, 5658 },
+ { 0x1d70f, 1, 5659 },
+ { 0x1d710, 1, 5660 },
+ { 0x1d711, 1, 671 },
+ { 0x1d712, 1, 5661 },
+ { 0x1d713, 1, 5662 },
+ { 0x1d714, 1, 5663 },
+ { 0x1d715, 1, 5664 },
+ { 0x1d716, 1, 677 },
+ { 0x1d717, 1, 669 },
+ { 0x1d718, 1, 673 },
+ { 0x1d719, 1, 671 },
+ { 0x1d71a, 1, 674 },
+ { 0x1d71b, 1, 672 },
+ { 0x1d71c, 1, 5630 },
+ { 0x1d71d, 1, 5631 },
+ { 0x1d71e, 1, 2233 },
+ { 0x1d71f, 1, 5632 },
+ { 0x1d720, 1, 5633 },
+ { 0x1d721, 1, 5634 },
+ { 0x1d722, 1, 5635 },
+ { 0x1d723, 1, 676 },
+ { 0x1d724, 1, 5636 },
+ { 0x1d725, 1, 5637 },
+ { 0x1d726, 1, 5638 },
+ { 0x1d727, 1, 5639 },
+ { 0x1d728, 1, 5640 },
+ { 0x1d729, 1, 5641 },
+ { 0x1d72a, 1, 5642 },
+ { 0x1d72b, 1, 2234 },
+ { 0x1d72c, 1, 5643 },
+ { 0x1d72d, 1, 676 },
+ { 0x1d72e, 1, 5644 },
+ { 0x1d72f, 1, 5645 },
+ { 0x1d730, 1, 670 },
+ { 0x1d731, 1, 5646 },
+ { 0x1d732, 1, 5647 },
+ { 0x1d733, 1, 5648 },
+ { 0x1d734, 1, 2221 },
+ { 0x1d735, 1, 5649 },
+ { 0x1d736, 1, 5650 },
+ { 0x1d737, 1, 668 },
+ { 0x1d738, 1, 2232 },
+ { 0x1d739, 1, 5651 },
+ { 0x1d73a, 1, 677 },
+ { 0x1d73b, 1, 5652 },
+ { 0x1d73c, 1, 5653 },
+ { 0x1d73d, 1, 669 },
+ { 0x1d73e, 1, 2025 },
+ { 0x1d73f, 1, 673 },
+ { 0x1d740, 1, 5654 },
+ { 0x1d741, 1, 10 },
+ { 0x1d742, 1, 5655 },
+ { 0x1d743, 1, 5656 },
+ { 0x1d744, 1, 5657 },
+ { 0x1d745, 1, 672 },
+ { 0x1d746, 1, 674 },
+ { 0x1d747, 1, 675 },
+ { 0x1d748, 1, 5658 },
+ { 0x1d749, 1, 5659 },
+ { 0x1d74a, 1, 5660 },
+ { 0x1d74b, 1, 671 },
+ { 0x1d74c, 1, 5661 },
+ { 0x1d74d, 1, 5662 },
+ { 0x1d74e, 1, 5663 },
+ { 0x1d74f, 1, 5664 },
+ { 0x1d750, 1, 677 },
+ { 0x1d751, 1, 669 },
+ { 0x1d752, 1, 673 },
+ { 0x1d753, 1, 671 },
+ { 0x1d754, 1, 674 },
+ { 0x1d755, 1, 672 },
+ { 0x1d756, 1, 5630 },
+ { 0x1d757, 1, 5631 },
+ { 0x1d758, 1, 2233 },
+ { 0x1d759, 1, 5632 },
+ { 0x1d75a, 1, 5633 },
+ { 0x1d75b, 1, 5634 },
+ { 0x1d75c, 1, 5635 },
+ { 0x1d75d, 1, 676 },
+ { 0x1d75e, 1, 5636 },
+ { 0x1d75f, 1, 5637 },
+ { 0x1d760, 1, 5638 },
+ { 0x1d761, 1, 5639 },
+ { 0x1d762, 1, 5640 },
+ { 0x1d763, 1, 5641 },
+ { 0x1d764, 1, 5642 },
+ { 0x1d765, 1, 2234 },
+ { 0x1d766, 1, 5643 },
+ { 0x1d767, 1, 676 },
+ { 0x1d768, 1, 5644 },
+ { 0x1d769, 1, 5645 },
+ { 0x1d76a, 1, 670 },
+ { 0x1d76b, 1, 5646 },
+ { 0x1d76c, 1, 5647 },
+ { 0x1d76d, 1, 5648 },
+ { 0x1d76e, 1, 2221 },
+ { 0x1d76f, 1, 5649 },
+ { 0x1d770, 1, 5650 },
+ { 0x1d771, 1, 668 },
+ { 0x1d772, 1, 2232 },
+ { 0x1d773, 1, 5651 },
+ { 0x1d774, 1, 677 },
+ { 0x1d775, 1, 5652 },
+ { 0x1d776, 1, 5653 },
+ { 0x1d777, 1, 669 },
+ { 0x1d778, 1, 2025 },
+ { 0x1d779, 1, 673 },
+ { 0x1d77a, 1, 5654 },
+ { 0x1d77b, 1, 10 },
+ { 0x1d77c, 1, 5655 },
+ { 0x1d77d, 1, 5656 },
+ { 0x1d77e, 1, 5657 },
+ { 0x1d77f, 1, 672 },
+ { 0x1d780, 1, 674 },
+ { 0x1d781, 1, 675 },
+ { 0x1d782, 1, 5658 },
+ { 0x1d783, 1, 5659 },
+ { 0x1d784, 1, 5660 },
+ { 0x1d785, 1, 671 },
+ { 0x1d786, 1, 5661 },
+ { 0x1d787, 1, 5662 },
+ { 0x1d788, 1, 5663 },
+ { 0x1d789, 1, 5664 },
+ { 0x1d78a, 1, 677 },
+ { 0x1d78b, 1, 669 },
+ { 0x1d78c, 1, 673 },
+ { 0x1d78d, 1, 671 },
+ { 0x1d78e, 1, 674 },
+ { 0x1d78f, 1, 672 },
+ { 0x1d790, 1, 5630 },
+ { 0x1d791, 1, 5631 },
+ { 0x1d792, 1, 2233 },
+ { 0x1d793, 1, 5632 },
+ { 0x1d794, 1, 5633 },
+ { 0x1d795, 1, 5634 },
+ { 0x1d796, 1, 5635 },
+ { 0x1d797, 1, 676 },
+ { 0x1d798, 1, 5636 },
+ { 0x1d799, 1, 5637 },
+ { 0x1d79a, 1, 5638 },
+ { 0x1d79b, 1, 5639 },
+ { 0x1d79c, 1, 5640 },
+ { 0x1d79d, 1, 5641 },
+ { 0x1d79e, 1, 5642 },
+ { 0x1d79f, 1, 2234 },
+ { 0x1d7a0, 1, 5643 },
+ { 0x1d7a1, 1, 676 },
+ { 0x1d7a2, 1, 5644 },
+ { 0x1d7a3, 1, 5645 },
+ { 0x1d7a4, 1, 670 },
+ { 0x1d7a5, 1, 5646 },
+ { 0x1d7a6, 1, 5647 },
+ { 0x1d7a7, 1, 5648 },
+ { 0x1d7a8, 1, 2221 },
+ { 0x1d7a9, 1, 5649 },
+ { 0x1d7aa, 1, 5650 },
+ { 0x1d7ab, 1, 668 },
+ { 0x1d7ac, 1, 2232 },
+ { 0x1d7ad, 1, 5651 },
+ { 0x1d7ae, 1, 677 },
+ { 0x1d7af, 1, 5652 },
+ { 0x1d7b0, 1, 5653 },
+ { 0x1d7b1, 1, 669 },
+ { 0x1d7b2, 1, 2025 },
+ { 0x1d7b3, 1, 673 },
+ { 0x1d7b4, 1, 5654 },
+ { 0x1d7b5, 1, 10 },
+ { 0x1d7b6, 1, 5655 },
+ { 0x1d7b7, 1, 5656 },
+ { 0x1d7b8, 1, 5657 },
+ { 0x1d7b9, 1, 672 },
+ { 0x1d7ba, 1, 674 },
+ { 0x1d7bb, 1, 675 },
+ { 0x1d7bc, 1, 5658 },
+ { 0x1d7bd, 1, 5659 },
+ { 0x1d7be, 1, 5660 },
+ { 0x1d7bf, 1, 671 },
+ { 0x1d7c0, 1, 5661 },
+ { 0x1d7c1, 1, 5662 },
+ { 0x1d7c2, 1, 5663 },
+ { 0x1d7c3, 1, 5664 },
+ { 0x1d7c4, 1, 677 },
+ { 0x1d7c5, 1, 669 },
+ { 0x1d7c6, 1, 673 },
+ { 0x1d7c7, 1, 671 },
+ { 0x1d7c8, 1, 674 },
+ { 0x1d7c9, 1, 672 },
+ { 0x1d7ce, 1, 2168 },
+ { 0x1d7cf, 1, 13 },
+ { 0x1d7d0, 1, 6 },
+ { 0x1d7d1, 1, 7 },
+ { 0x1d7d2, 1, 2170 },
+ { 0x1d7d3, 1, 2171 },
+ { 0x1d7d4, 1, 2172 },
+ { 0x1d7d5, 1, 2173 },
+ { 0x1d7d6, 1, 2174 },
+ { 0x1d7d7, 1, 2175 },
+ { 0x1d7d8, 1, 2168 },
+ { 0x1d7d9, 1, 13 },
+ { 0x1d7da, 1, 6 },
+ { 0x1d7db, 1, 7 },
+ { 0x1d7dc, 1, 2170 },
+ { 0x1d7dd, 1, 2171 },
+ { 0x1d7de, 1, 2172 },
+ { 0x1d7df, 1, 2173 },
+ { 0x1d7e0, 1, 2174 },
+ { 0x1d7e1, 1, 2175 },
+ { 0x1d7e2, 1, 2168 },
+ { 0x1d7e3, 1, 13 },
+ { 0x1d7e4, 1, 6 },
+ { 0x1d7e5, 1, 7 },
+ { 0x1d7e6, 1, 2170 },
+ { 0x1d7e7, 1, 2171 },
+ { 0x1d7e8, 1, 2172 },
+ { 0x1d7e9, 1, 2173 },
+ { 0x1d7ea, 1, 2174 },
+ { 0x1d7eb, 1, 2175 },
+ { 0x1d7ec, 1, 2168 },
+ { 0x1d7ed, 1, 13 },
+ { 0x1d7ee, 1, 6 },
+ { 0x1d7ef, 1, 7 },
+ { 0x1d7f0, 1, 2170 },
+ { 0x1d7f1, 1, 2171 },
+ { 0x1d7f2, 1, 2172 },
+ { 0x1d7f3, 1, 2173 },
+ { 0x1d7f4, 1, 2174 },
+ { 0x1d7f5, 1, 2175 },
+ { 0x1d7f6, 1, 2168 },
+ { 0x1d7f7, 1, 13 },
+ { 0x1d7f8, 1, 6 },
+ { 0x1d7f9, 1, 7 },
+ { 0x1d7fa, 1, 2170 },
+ { 0x1d7fb, 1, 2171 },
+ { 0x1d7fc, 1, 2172 },
+ { 0x1d7fd, 1, 2173 },
+ { 0x1d7fe, 1, 2174 },
+ { 0x1d7ff, 1, 2175 },
+ { 0x2f800, 1, 5665 },
+ { 0x2f801, 1, 5666 },
+ { 0x2f802, 1, 5667 },
+ { 0x2f803, 1, 5668 },
+ { 0x2f804, 1, 5669 },
+ { 0x2f805, 1, 4549 },
+ { 0x2f806, 1, 5670 },
+ { 0x2f807, 1, 5671 },
+ { 0x2f808, 1, 5672 },
+ { 0x2f809, 1, 5673 },
+ { 0x2f80a, 1, 4550 },
+ { 0x2f80b, 1, 5674 },
+ { 0x2f80c, 1, 5675 },
+ { 0x2f80d, 1, 5676 },
+ { 0x2f80e, 1, 4551 },
+ { 0x2f80f, 1, 5677 },
+ { 0x2f810, 1, 5678 },
+ { 0x2f811, 1, 5679 },
+ { 0x2f812, 1, 5680 },
+ { 0x2f813, 1, 5681 },
+ { 0x2f814, 1, 5682 },
+ { 0x2f815, 1, 5683 },
+ { 0x2f816, 1, 5684 },
+ { 0x2f817, 1, 5685 },
+ { 0x2f818, 1, 5686 },
+ { 0x2f819, 1, 5687 },
+ { 0x2f81a, 1, 5688 },
+ { 0x2f81b, 1, 5689 },
+ { 0x2f81c, 1, 5690 },
+ { 0x2f81d, 1, 2698 },
+ { 0x2f81e, 1, 5691 },
+ { 0x2f81f, 1, 5692 },
+ { 0x2f820, 1, 5693 },
+ { 0x2f821, 1, 5694 },
+ { 0x2f822, 1, 5695 },
+ { 0x2f823, 1, 5696 },
+ { 0x2f824, 1, 5697 },
+ { 0x2f825, 1, 5698 },
+ { 0x2f826, 1, 4552 },
+ { 0x2f827, 1, 4553 },
+ { 0x2f828, 1, 5699 },
+ { 0x2f829, 1, 5700 },
+ { 0x2f82a, 1, 5701 },
+ { 0x2f82b, 1, 4372 },
+ { 0x2f82c, 1, 5702 },
+ { 0x2f82d, 1, 4554 },
+ { 0x2f82e, 1, 5703 },
+ { 0x2f82f, 1, 5704 },
+ { 0x2f830, 1, 5705 },
+ { 0x2f831, 1, 5706 },
+ { 0x2f832, 1, 5706 },
+ { 0x2f833, 1, 5706 },
+ { 0x2f834, 1, 5707 },
+ { 0x2f835, 1, 5708 },
+ { 0x2f836, 1, 5709 },
+ { 0x2f837, 1, 5710 },
+ { 0x2f838, 1, 5711 },
+ { 0x2f839, 1, 5712 },
+ { 0x2f83a, 1, 5713 },
+ { 0x2f83b, 1, 5714 },
+ { 0x2f83c, 1, 5715 },
+ { 0x2f83d, 1, 5716 },
+ { 0x2f83e, 1, 5717 },
+ { 0x2f83f, 1, 5718 },
+ { 0x2f840, 1, 5719 },
+ { 0x2f841, 1, 5720 },
+ { 0x2f842, 1, 5721 },
+ { 0x2f843, 1, 5722 },
+ { 0x2f844, 1, 5723 },
+ { 0x2f845, 1, 5724 },
+ { 0x2f846, 1, 5724 },
+ { 0x2f847, 1, 5725 },
+ { 0x2f848, 1, 5726 },
+ { 0x2f849, 1, 5727 },
+ { 0x2f84a, 1, 5728 },
+ { 0x2f84b, 1, 5729 },
+ { 0x2f84c, 1, 4556 },
+ { 0x2f84d, 1, 5730 },
+ { 0x2f84e, 1, 5731 },
+ { 0x2f84f, 1, 5732 },
+ { 0x2f850, 1, 4518 },
+ { 0x2f851, 1, 5733 },
+ { 0x2f852, 1, 5734 },
+ { 0x2f853, 1, 5735 },
+ { 0x2f854, 1, 5736 },
+ { 0x2f855, 1, 5737 },
+ { 0x2f856, 1, 5738 },
+ { 0x2f857, 1, 5739 },
+ { 0x2f858, 1, 5740 },
+ { 0x2f859, 1, 5741 },
+ { 0x2f85a, 1, 5742 },
+ { 0x2f85b, 1, 5743 },
+ { 0x2f85c, 1, 5744 },
+ { 0x2f85d, 1, 5745 },
+ { 0x2f85e, 1, 5746 },
+ { 0x2f85f, 1, 5747 },
+ { 0x2f860, 1, 5748 },
+ { 0x2f861, 1, 5749 },
+ { 0x2f862, 1, 5750 },
+ { 0x2f863, 1, 5751 },
+ { 0x2f864, 1, 5752 },
+ { 0x2f865, 1, 5753 },
+ { 0x2f866, 1, 5754 },
+ { 0x2f867, 1, 5755 },
+ { 0x2f868, 1, 5756 },
+ { 0x2f869, 1, 5757 },
+ { 0x2f86a, 1, 5758 },
+ { 0x2f86b, 1, 5758 },
+ { 0x2f86c, 1, 5759 },
+ { 0x2f86d, 1, 5760 },
+ { 0x2f86e, 1, 5761 },
+ { 0x2f86f, 1, 4368 },
+ { 0x2f870, 1, 5762 },
+ { 0x2f871, 1, 5763 },
+ { 0x2f872, 1, 5764 },
+ { 0x2f873, 1, 5765 },
+ { 0x2f874, 1, 5766 },
+ { 0x2f875, 1, 2724 },
+ { 0x2f876, 1, 5767 },
+ { 0x2f877, 1, 5768 },
+ { 0x2f878, 1, 2726 },
+ { 0x2f879, 1, 5769 },
+ { 0x2f87a, 1, 5770 },
+ { 0x2f87b, 1, 5771 },
+ { 0x2f87c, 1, 5772 },
+ { 0x2f87d, 1, 5773 },
+ { 0x2f87e, 1, 5774 },
+ { 0x2f87f, 1, 5775 },
+ { 0x2f880, 1, 5776 },
+ { 0x2f881, 1, 5777 },
+ { 0x2f882, 1, 5778 },
+ { 0x2f883, 1, 5779 },
+ { 0x2f884, 1, 5780 },
+ { 0x2f885, 1, 5781 },
+ { 0x2f886, 1, 5782 },
+ { 0x2f887, 1, 5783 },
+ { 0x2f888, 1, 5784 },
+ { 0x2f889, 1, 5785 },
+ { 0x2f88a, 1, 5786 },
+ { 0x2f88b, 1, 5787 },
+ { 0x2f88c, 1, 5788 },
+ { 0x2f88d, 1, 5789 },
+ { 0x2f88e, 1, 4316 },
+ { 0x2f88f, 1, 5790 },
+ { 0x2f890, 1, 2736 },
+ { 0x2f891, 1, 5791 },
+ { 0x2f892, 1, 5791 },
+ { 0x2f893, 1, 5792 },
+ { 0x2f894, 1, 5793 },
+ { 0x2f895, 1, 5793 },
+ { 0x2f896, 1, 5794 },
+ { 0x2f897, 1, 5795 },
+ { 0x2f898, 1, 5796 },
+ { 0x2f899, 1, 5797 },
+ { 0x2f89a, 1, 5798 },
+ { 0x2f89b, 1, 5799 },
+ { 0x2f89c, 1, 5800 },
+ { 0x2f89d, 1, 5801 },
+ { 0x2f89e, 1, 5802 },
+ { 0x2f89f, 1, 5803 },
+ { 0x2f8a0, 1, 5804 },
+ { 0x2f8a1, 1, 5805 },
+ { 0x2f8a2, 1, 5806 },
+ { 0x2f8a3, 1, 4561 },
+ { 0x2f8a4, 1, 5807 },
+ { 0x2f8a5, 1, 5808 },
+ { 0x2f8a6, 1, 5809 },
+ { 0x2f8a7, 1, 5810 },
+ { 0x2f8a8, 1, 5811 },
+ { 0x2f8a9, 1, 5810 },
+ { 0x2f8aa, 1, 5812 },
+ { 0x2f8ab, 1, 4563 },
+ { 0x2f8ac, 1, 5813 },
+ { 0x2f8ad, 1, 5814 },
+ { 0x2f8ae, 1, 5815 },
+ { 0x2f8af, 1, 5816 },
+ { 0x2f8b0, 1, 4564 },
+ { 0x2f8b1, 1, 4289 },
+ { 0x2f8b2, 1, 5817 },
+ { 0x2f8b3, 1, 5818 },
+ { 0x2f8b4, 1, 5819 },
+ { 0x2f8b5, 1, 5820 },
+ { 0x2f8b6, 1, 5821 },
+ { 0x2f8b7, 1, 5822 },
+ { 0x2f8b8, 1, 5823 },
+ { 0x2f8b9, 1, 5824 },
+ { 0x2f8ba, 1, 5825 },
+ { 0x2f8bb, 1, 5826 },
+ { 0x2f8bc, 1, 5827 },
+ { 0x2f8bd, 1, 5828 },
+ { 0x2f8be, 1, 5829 },
+ { 0x2f8bf, 1, 5830 },
+ { 0x2f8c0, 1, 5831 },
+ { 0x2f8c1, 1, 5832 },
+ { 0x2f8c2, 1, 5833 },
+ { 0x2f8c3, 1, 5834 },
+ { 0x2f8c4, 1, 5835 },
+ { 0x2f8c5, 1, 5836 },
+ { 0x2f8c6, 1, 5837 },
+ { 0x2f8c7, 1, 5838 },
+ { 0x2f8c8, 1, 4565 },
+ { 0x2f8c9, 1, 5839 },
+ { 0x2f8ca, 1, 5840 },
+ { 0x2f8cb, 1, 5841 },
+ { 0x2f8cc, 1, 5842 },
+ { 0x2f8cd, 1, 5843 },
+ { 0x2f8ce, 1, 5844 },
+ { 0x2f8cf, 1, 4567 },
+ { 0x2f8d0, 1, 5845 },
+ { 0x2f8d1, 1, 5846 },
+ { 0x2f8d2, 1, 5847 },
+ { 0x2f8d3, 1, 5848 },
+ { 0x2f8d4, 1, 5849 },
+ { 0x2f8d5, 1, 5850 },
+ { 0x2f8d6, 1, 5851 },
+ { 0x2f8d7, 1, 5852 },
+ { 0x2f8d8, 1, 4317 },
+ { 0x2f8d9, 1, 5853 },
+ { 0x2f8da, 1, 5854 },
+ { 0x2f8db, 1, 5855 },
+ { 0x2f8dc, 1, 5856 },
+ { 0x2f8dd, 1, 5857 },
+ { 0x2f8de, 1, 5858 },
+ { 0x2f8df, 1, 5859 },
+ { 0x2f8e0, 1, 5860 },
+ { 0x2f8e1, 1, 5861 },
+ { 0x2f8e2, 1, 4568 },
+ { 0x2f8e3, 1, 5862 },
+ { 0x2f8e4, 1, 5863 },
+ { 0x2f8e5, 1, 5864 },
+ { 0x2f8e6, 1, 5865 },
+ { 0x2f8e7, 1, 5866 },
+ { 0x2f8e8, 1, 5867 },
+ { 0x2f8e9, 1, 5868 },
+ { 0x2f8ea, 1, 5869 },
+ { 0x2f8eb, 1, 5870 },
+ { 0x2f8ec, 1, 5871 },
+ { 0x2f8ed, 1, 5872 },
+ { 0x2f8ee, 1, 5873 },
+ { 0x2f8ef, 1, 5874 },
+ { 0x2f8f0, 1, 5875 },
+ { 0x2f8f1, 1, 5876 },
+ { 0x2f8f2, 1, 5877 },
+ { 0x2f8f3, 1, 5878 },
+ { 0x2f8f4, 1, 5879 },
+ { 0x2f8f5, 1, 4385 },
+ { 0x2f8f6, 1, 5880 },
+ { 0x2f8f7, 1, 5881 },
+ { 0x2f8f8, 1, 5882 },
+ { 0x2f8f9, 1, 5883 },
+ { 0x2f8fa, 1, 5884 },
+ { 0x2f8fb, 1, 5885 },
+ { 0x2f8fc, 1, 5886 },
+ { 0x2f8fd, 1, 5887 },
+ { 0x2f8fe, 1, 5888 },
+ { 0x2f8ff, 1, 5889 },
+ { 0x2f900, 1, 5890 },
+ { 0x2f901, 1, 4569 },
+ { 0x2f902, 1, 4468 },
+ { 0x2f903, 1, 5891 },
+ { 0x2f904, 1, 5892 },
+ { 0x2f905, 1, 5893 },
+ { 0x2f906, 1, 5894 },
+ { 0x2f907, 1, 5895 },
+ { 0x2f908, 1, 5896 },
+ { 0x2f909, 1, 5897 },
+ { 0x2f90a, 1, 5898 },
+ { 0x2f90b, 1, 5899 },
+ { 0x2f90c, 1, 5900 },
+ { 0x2f90d, 1, 5901 },
+ { 0x2f90e, 1, 5902 },
+ { 0x2f90f, 1, 5903 },
+ { 0x2f910, 1, 5904 },
+ { 0x2f911, 1, 5905 },
+ { 0x2f912, 1, 5906 },
+ { 0x2f913, 1, 5907 },
+ { 0x2f914, 1, 5908 },
+ { 0x2f915, 1, 5909 },
+ { 0x2f916, 1, 5910 },
+ { 0x2f917, 1, 5911 },
+ { 0x2f918, 1, 5912 },
+ { 0x2f919, 1, 5913 },
+ { 0x2f91a, 1, 5914 },
+ { 0x2f91b, 1, 5915 },
+ { 0x2f91c, 1, 5916 },
+ { 0x2f91d, 1, 5917 },
+ { 0x2f91e, 1, 5918 },
+ { 0x2f91f, 1, 5919 },
+ { 0x2f920, 1, 5920 },
+ { 0x2f921, 1, 5921 },
+ { 0x2f922, 1, 5922 },
+ { 0x2f923, 1, 5923 },
+ { 0x2f924, 1, 5924 },
+ { 0x2f925, 1, 5925 },
+ { 0x2f926, 1, 5926 },
+ { 0x2f927, 1, 5927 },
+ { 0x2f928, 1, 5928 },
+ { 0x2f929, 1, 5929 },
+ { 0x2f92a, 1, 5930 },
+ { 0x2f92b, 1, 5931 },
+ { 0x2f92c, 1, 5932 },
+ { 0x2f92d, 1, 5932 },
+ { 0x2f92e, 1, 5933 },
+ { 0x2f92f, 1, 5934 },
+ { 0x2f930, 1, 5935 },
+ { 0x2f931, 1, 5936 },
+ { 0x2f932, 1, 5937 },
+ { 0x2f933, 1, 5938 },
+ { 0x2f934, 1, 5939 },
+ { 0x2f935, 1, 5940 },
+ { 0x2f936, 1, 5941 },
+ { 0x2f937, 1, 5942 },
+ { 0x2f938, 1, 4371 },
+ { 0x2f939, 1, 5943 },
+ { 0x2f93a, 1, 5944 },
+ { 0x2f93b, 1, 5945 },
+ { 0x2f93c, 1, 5946 },
+ { 0x2f93d, 1, 5947 },
+ { 0x2f93e, 1, 5948 },
+ { 0x2f93f, 1, 5949 },
+ { 0x2f940, 1, 5950 },
+ { 0x2f941, 1, 5951 },
+ { 0x2f942, 1, 5952 },
+ { 0x2f943, 1, 5953 },
+ { 0x2f944, 1, 5954 },
+ { 0x2f945, 1, 5955 },
+ { 0x2f946, 1, 5956 },
+ { 0x2f947, 1, 5956 },
+ { 0x2f948, 1, 5957 },
+ { 0x2f949, 1, 5958 },
+ { 0x2f94a, 1, 5959 },
+ { 0x2f94b, 1, 5960 },
+ { 0x2f94c, 1, 5961 },
+ { 0x2f94d, 1, 5962 },
+ { 0x2f94e, 1, 5963 },
+ { 0x2f94f, 1, 4334 },
+ { 0x2f950, 1, 5964 },
+ { 0x2f951, 1, 5965 },
+ { 0x2f952, 1, 5966 },
+ { 0x2f953, 1, 4579 },
+ { 0x2f954, 1, 5967 },
+ { 0x2f955, 1, 5968 },
+ { 0x2f956, 1, 4538 },
+ { 0x2f957, 1, 5969 },
+ { 0x2f958, 1, 5970 },
+ { 0x2f959, 1, 4582 },
+ { 0x2f95a, 1, 5971 },
+ { 0x2f95b, 1, 5972 },
+ { 0x2f95c, 1, 5973 },
+ { 0x2f95d, 1, 5974 },
+ { 0x2f95e, 1, 5974 },
+ { 0x2f95f, 1, 5975 },
+ { 0x2f960, 1, 5976 },
+ { 0x2f961, 1, 5977 },
+ { 0x2f962, 1, 5978 },
+ { 0x2f963, 1, 5979 },
+ { 0x2f964, 1, 5980 },
+ { 0x2f965, 1, 5981 },
+ { 0x2f966, 1, 5982 },
+ { 0x2f967, 1, 5983 },
+ { 0x2f968, 1, 5984 },
+ { 0x2f969, 1, 5985 },
+ { 0x2f96a, 1, 5986 },
+ { 0x2f96b, 1, 5987 },
+ { 0x2f96c, 1, 5988 },
+ { 0x2f96d, 1, 5989 },
+ { 0x2f96e, 1, 5990 },
+ { 0x2f96f, 1, 5991 },
+ { 0x2f970, 1, 5992 },
+ { 0x2f971, 1, 5993 },
+ { 0x2f972, 1, 5994 },
+ { 0x2f973, 1, 5995 },
+ { 0x2f974, 1, 5996 },
+ { 0x2f975, 1, 5997 },
+ { 0x2f976, 1, 5998 },
+ { 0x2f977, 1, 5999 },
+ { 0x2f978, 1, 6000 },
+ { 0x2f979, 1, 6001 },
+ { 0x2f97a, 1, 4588 },
+ { 0x2f97b, 1, 6002 },
+ { 0x2f97c, 1, 6003 },
+ { 0x2f97d, 1, 6004 },
+ { 0x2f97e, 1, 6005 },
+ { 0x2f97f, 1, 6006 },
+ { 0x2f980, 1, 6007 },
+ { 0x2f981, 1, 6008 },
+ { 0x2f982, 1, 6009 },
+ { 0x2f983, 1, 6010 },
+ { 0x2f984, 1, 6011 },
+ { 0x2f985, 1, 6012 },
+ { 0x2f986, 1, 6013 },
+ { 0x2f987, 1, 6014 },
+ { 0x2f988, 1, 6015 },
+ { 0x2f989, 1, 6016 },
+ { 0x2f98a, 1, 6017 },
+ { 0x2f98b, 1, 5792 },
+ { 0x2f98c, 1, 6018 },
+ { 0x2f98d, 1, 6019 },
+ { 0x2f98e, 1, 6020 },
+ { 0x2f98f, 1, 6021 },
+ { 0x2f990, 1, 6022 },
+ { 0x2f991, 1, 6023 },
+ { 0x2f992, 1, 6024 },
+ { 0x2f993, 1, 6025 },
+ { 0x2f994, 1, 6026 },
+ { 0x2f995, 1, 6027 },
+ { 0x2f996, 1, 6028 },
+ { 0x2f997, 1, 6029 },
+ { 0x2f998, 1, 4388 },
+ { 0x2f999, 1, 6030 },
+ { 0x2f99a, 1, 6031 },
+ { 0x2f99b, 1, 6032 },
+ { 0x2f99c, 1, 6033 },
+ { 0x2f99d, 1, 6034 },
+ { 0x2f99e, 1, 6035 },
+ { 0x2f99f, 1, 4591 },
+ { 0x2f9a0, 1, 6036 },
+ { 0x2f9a1, 1, 6037 },
+ { 0x2f9a2, 1, 6038 },
+ { 0x2f9a3, 1, 6039 },
+ { 0x2f9a4, 1, 6040 },
+ { 0x2f9a5, 1, 6041 },
+ { 0x2f9a6, 1, 6042 },
+ { 0x2f9a7, 1, 6043 },
+ { 0x2f9a8, 1, 6044 },
+ { 0x2f9a9, 1, 6045 },
+ { 0x2f9aa, 1, 6046 },
+ { 0x2f9ab, 1, 6047 },
+ { 0x2f9ac, 1, 6048 },
+ { 0x2f9ad, 1, 6049 },
+ { 0x2f9ae, 1, 6050 },
+ { 0x2f9af, 1, 6051 },
+ { 0x2f9b0, 1, 6052 },
+ { 0x2f9b1, 1, 6053 },
+ { 0x2f9b2, 1, 6054 },
+ { 0x2f9b3, 1, 6055 },
+ { 0x2f9b4, 1, 4329 },
+ { 0x2f9b5, 1, 6056 },
+ { 0x2f9b6, 1, 6057 },
+ { 0x2f9b7, 1, 6058 },
+ { 0x2f9b8, 1, 6059 },
+ { 0x2f9b9, 1, 6060 },
+ { 0x2f9ba, 1, 6061 },
+ { 0x2f9bb, 1, 6062 },
+ { 0x2f9bc, 1, 6063 },
+ { 0x2f9bd, 1, 6064 },
+ { 0x2f9be, 1, 6065 },
+ { 0x2f9bf, 1, 6066 },
+ { 0x2f9c0, 1, 6067 },
+ { 0x2f9c1, 1, 6068 },
+ { 0x2f9c2, 1, 6069 },
+ { 0x2f9c3, 1, 6070 },
+ { 0x2f9c4, 1, 2826 },
+ { 0x2f9c5, 1, 6071 },
+ { 0x2f9c6, 1, 6072 },
+ { 0x2f9c7, 1, 6073 },
+ { 0x2f9c8, 1, 6074 },
+ { 0x2f9c9, 1, 6075 },
+ { 0x2f9ca, 1, 6076 },
+ { 0x2f9cb, 1, 6077 },
+ { 0x2f9cc, 1, 6078 },
+ { 0x2f9cd, 1, 6079 },
+ { 0x2f9ce, 1, 6080 },
+ { 0x2f9cf, 1, 6081 },
+ { 0x2f9d0, 1, 6082 },
+ { 0x2f9d1, 1, 6083 },
+ { 0x2f9d2, 1, 2833 },
+ { 0x2f9d3, 1, 6084 },
+ { 0x2f9d4, 1, 6085 },
+ { 0x2f9d5, 1, 6086 },
+ { 0x2f9d6, 1, 6087 },
+ { 0x2f9d7, 1, 6088 },
+ { 0x2f9d8, 1, 6089 },
+ { 0x2f9d9, 1, 6090 },
+ { 0x2f9da, 1, 6091 },
+ { 0x2f9db, 1, 6092 },
+ { 0x2f9dc, 1, 6093 },
+ { 0x2f9dd, 1, 6094 },
+ { 0x2f9de, 1, 6095 },
+ { 0x2f9df, 1, 6096 },
+ { 0x2f9e0, 1, 6097 },
+ { 0x2f9e1, 1, 6098 },
+ { 0x2f9e2, 1, 6099 },
+ { 0x2f9e3, 1, 6100 },
+ { 0x2f9e4, 1, 6101 },
+ { 0x2f9e5, 1, 6102 },
+ { 0x2f9e6, 1, 6103 },
+ { 0x2f9e7, 1, 6104 },
+ { 0x2f9e8, 1, 6105 },
+ { 0x2f9e9, 1, 6106 },
+ { 0x2f9ea, 1, 6107 },
+ { 0x2f9eb, 1, 6108 },
+ { 0x2f9ec, 1, 6109 },
+ { 0x2f9ed, 1, 6110 },
+ { 0x2f9ee, 1, 6111 },
+ { 0x2f9ef, 1, 6112 },
+ { 0x2f9f0, 1, 6113 },
+ { 0x2f9f1, 1, 6114 },
+ { 0x2f9f2, 1, 6115 },
+ { 0x2f9f3, 1, 6116 },
+ { 0x2f9f4, 1, 6117 },
+ { 0x2f9f5, 1, 6118 },
+ { 0x2f9f6, 1, 6119 },
+ { 0x2f9f7, 1, 6120 },
+ { 0x2f9f8, 1, 6121 },
+ { 0x2f9f9, 1, 6122 },
+ { 0x2f9fa, 1, 6123 },
+ { 0x2f9fb, 1, 6124 },
+ { 0x2f9fc, 1, 6125 },
+ { 0x2f9fd, 1, 6126 },
+ { 0x2f9fe, 1, 6127 },
+ { 0x2f9ff, 1, 6127 },
+ { 0x2fa00, 1, 6128 },
+ { 0x2fa01, 1, 6129 },
+ { 0x2fa02, 1, 6130 },
+ { 0x2fa03, 1, 6131 },
+ { 0x2fa04, 1, 6132 },
+ { 0x2fa05, 1, 6133 },
+ { 0x2fa06, 1, 6134 },
+ { 0x2fa07, 1, 6135 },
+ { 0x2fa08, 1, 6136 },
+ { 0x2fa09, 1, 6137 },
+ { 0x2fa0a, 1, 6138 },
+ { 0x2fa0b, 1, 6139 },
+ { 0x2fa0c, 1, 6140 },
+ { 0x2fa0d, 1, 6141 },
+ { 0x2fa0e, 1, 6142 },
+ { 0x2fa0f, 1, 6143 },
+ { 0x2fa10, 1, 6144 },
+ { 0x2fa11, 1, 6145 },
+ { 0x2fa12, 1, 6146 },
+ { 0x2fa13, 1, 6147 },
+ { 0x2fa14, 1, 6148 },
+ { 0x2fa15, 1, 2881 },
+ { 0x2fa16, 1, 6149 },
+ { 0x2fa17, 1, 2885 },
+ { 0x2fa18, 1, 6150 },
+ { 0x2fa19, 1, 6151 },
+ { 0x2fa1a, 1, 6152 },
+ { 0x2fa1b, 1, 6153 },
+ { 0x2fa1c, 1, 2890 },
+ { 0x2fa1d, 1, 6154 }
+};
+
+static const Unicode decomp_expansion[] = {
+ 0x20 /* offset 0 */ ,
+ 0x20, 0x308 /* offset 1 */ ,
+ 0x61 /* offset 3 */ ,
+ 0x20, 0x304 /* offset 4 */ ,
+ 0x32 /* offset 6 */ ,
+ 0x33 /* offset 7 */ ,
+ 0x20, 0x301 /* offset 8 */ ,
+ 0x3bc /* offset 10 */ ,
+ 0x20, 0x327 /* offset 11 */ ,
+ 0x31 /* offset 13 */ ,
+ 0x6f /* offset 14 */ ,
+ 0x31, 0x2044, 0x34 /* offset 15 */ ,
+ 0x31, 0x2044, 0x32 /* offset 18 */ ,
+ 0x33, 0x2044, 0x34 /* offset 21 */ ,
+ 0x41, 0x300 /* offset 24 */ ,
+ 0x41, 0x301 /* offset 26 */ ,
+ 0x41, 0x302 /* offset 28 */ ,
+ 0x41, 0x303 /* offset 30 */ ,
+ 0x41, 0x308 /* offset 32 */ ,
+ 0x41, 0x30a /* offset 34 */ ,
+ 0x43, 0x327 /* offset 36 */ ,
+ 0x45, 0x300 /* offset 38 */ ,
+ 0x45, 0x301 /* offset 40 */ ,
+ 0x45, 0x302 /* offset 42 */ ,
+ 0x45, 0x308 /* offset 44 */ ,
+ 0x49, 0x300 /* offset 46 */ ,
+ 0x49, 0x301 /* offset 48 */ ,
+ 0x49, 0x302 /* offset 50 */ ,
+ 0x49, 0x308 /* offset 52 */ ,
+ 0x4e, 0x303 /* offset 54 */ ,
+ 0x4f, 0x300 /* offset 56 */ ,
+ 0x4f, 0x301 /* offset 58 */ ,
+ 0x4f, 0x302 /* offset 60 */ ,
+ 0x4f, 0x303 /* offset 62 */ ,
+ 0x4f, 0x308 /* offset 64 */ ,
+ 0x55, 0x300 /* offset 66 */ ,
+ 0x55, 0x301 /* offset 68 */ ,
+ 0x55, 0x302 /* offset 70 */ ,
+ 0x55, 0x308 /* offset 72 */ ,
+ 0x59, 0x301 /* offset 74 */ ,
+ 0x61, 0x300 /* offset 76 */ ,
+ 0x61, 0x301 /* offset 78 */ ,
+ 0x61, 0x302 /* offset 80 */ ,
+ 0x61, 0x303 /* offset 82 */ ,
+ 0x61, 0x308 /* offset 84 */ ,
+ 0x61, 0x30a /* offset 86 */ ,
+ 0x63, 0x327 /* offset 88 */ ,
+ 0x65, 0x300 /* offset 90 */ ,
+ 0x65, 0x301 /* offset 92 */ ,
+ 0x65, 0x302 /* offset 94 */ ,
+ 0x65, 0x308 /* offset 96 */ ,
+ 0x69, 0x300 /* offset 98 */ ,
+ 0x69, 0x301 /* offset 100 */ ,
+ 0x69, 0x302 /* offset 102 */ ,
+ 0x69, 0x308 /* offset 104 */ ,
+ 0x6e, 0x303 /* offset 106 */ ,
+ 0x6f, 0x300 /* offset 108 */ ,
+ 0x6f, 0x301 /* offset 110 */ ,
+ 0x6f, 0x302 /* offset 112 */ ,
+ 0x6f, 0x303 /* offset 114 */ ,
+ 0x6f, 0x308 /* offset 116 */ ,
+ 0x75, 0x300 /* offset 118 */ ,
+ 0x75, 0x301 /* offset 120 */ ,
+ 0x75, 0x302 /* offset 122 */ ,
+ 0x75, 0x308 /* offset 124 */ ,
+ 0x79, 0x301 /* offset 126 */ ,
+ 0x79, 0x308 /* offset 128 */ ,
+ 0x41, 0x304 /* offset 130 */ ,
+ 0x61, 0x304 /* offset 132 */ ,
+ 0x41, 0x306 /* offset 134 */ ,
+ 0x61, 0x306 /* offset 136 */ ,
+ 0x41, 0x328 /* offset 138 */ ,
+ 0x61, 0x328 /* offset 140 */ ,
+ 0x43, 0x301 /* offset 142 */ ,
+ 0x63, 0x301 /* offset 144 */ ,
+ 0x43, 0x302 /* offset 146 */ ,
+ 0x63, 0x302 /* offset 148 */ ,
+ 0x43, 0x307 /* offset 150 */ ,
+ 0x63, 0x307 /* offset 152 */ ,
+ 0x43, 0x30c /* offset 154 */ ,
+ 0x63, 0x30c /* offset 156 */ ,
+ 0x44, 0x30c /* offset 158 */ ,
+ 0x64, 0x30c /* offset 160 */ ,
+ 0x45, 0x304 /* offset 162 */ ,
+ 0x65, 0x304 /* offset 164 */ ,
+ 0x45, 0x306 /* offset 166 */ ,
+ 0x65, 0x306 /* offset 168 */ ,
+ 0x45, 0x307 /* offset 170 */ ,
+ 0x65, 0x307 /* offset 172 */ ,
+ 0x45, 0x328 /* offset 174 */ ,
+ 0x65, 0x328 /* offset 176 */ ,
+ 0x45, 0x30c /* offset 178 */ ,
+ 0x65, 0x30c /* offset 180 */ ,
+ 0x47, 0x302 /* offset 182 */ ,
+ 0x67, 0x302 /* offset 184 */ ,
+ 0x47, 0x306 /* offset 186 */ ,
+ 0x67, 0x306 /* offset 188 */ ,
+ 0x47, 0x307 /* offset 190 */ ,
+ 0x67, 0x307 /* offset 192 */ ,
+ 0x47, 0x327 /* offset 194 */ ,
+ 0x67, 0x327 /* offset 196 */ ,
+ 0x48, 0x302 /* offset 198 */ ,
+ 0x68, 0x302 /* offset 200 */ ,
+ 0x49, 0x303 /* offset 202 */ ,
+ 0x69, 0x303 /* offset 204 */ ,
+ 0x49, 0x304 /* offset 206 */ ,
+ 0x69, 0x304 /* offset 208 */ ,
+ 0x49, 0x306 /* offset 210 */ ,
+ 0x69, 0x306 /* offset 212 */ ,
+ 0x49, 0x328 /* offset 214 */ ,
+ 0x69, 0x328 /* offset 216 */ ,
+ 0x49, 0x307 /* offset 218 */ ,
+ 0x49, 0x4a /* offset 220 */ ,
+ 0x69, 0x6a /* offset 222 */ ,
+ 0x4a, 0x302 /* offset 224 */ ,
+ 0x6a, 0x302 /* offset 226 */ ,
+ 0x4b, 0x327 /* offset 228 */ ,
+ 0x6b, 0x327 /* offset 230 */ ,
+ 0x4c, 0x301 /* offset 232 */ ,
+ 0x6c, 0x301 /* offset 234 */ ,
+ 0x4c, 0x327 /* offset 236 */ ,
+ 0x6c, 0x327 /* offset 238 */ ,
+ 0x4c, 0x30c /* offset 240 */ ,
+ 0x6c, 0x30c /* offset 242 */ ,
+ 0x4c, 0xb7 /* offset 244 */ ,
+ 0x6c, 0xb7 /* offset 246 */ ,
+ 0x4e, 0x301 /* offset 248 */ ,
+ 0x6e, 0x301 /* offset 250 */ ,
+ 0x4e, 0x327 /* offset 252 */ ,
+ 0x6e, 0x327 /* offset 254 */ ,
+ 0x4e, 0x30c /* offset 256 */ ,
+ 0x6e, 0x30c /* offset 258 */ ,
+ 0x2bc, 0x6e /* offset 260 */ ,
+ 0x4f, 0x304 /* offset 262 */ ,
+ 0x6f, 0x304 /* offset 264 */ ,
+ 0x4f, 0x306 /* offset 266 */ ,
+ 0x6f, 0x306 /* offset 268 */ ,
+ 0x4f, 0x30b /* offset 270 */ ,
+ 0x6f, 0x30b /* offset 272 */ ,
+ 0x52, 0x301 /* offset 274 */ ,
+ 0x72, 0x301 /* offset 276 */ ,
+ 0x52, 0x327 /* offset 278 */ ,
+ 0x72, 0x327 /* offset 280 */ ,
+ 0x52, 0x30c /* offset 282 */ ,
+ 0x72, 0x30c /* offset 284 */ ,
+ 0x53, 0x301 /* offset 286 */ ,
+ 0x73, 0x301 /* offset 288 */ ,
+ 0x53, 0x302 /* offset 290 */ ,
+ 0x73, 0x302 /* offset 292 */ ,
+ 0x53, 0x327 /* offset 294 */ ,
+ 0x73, 0x327 /* offset 296 */ ,
+ 0x53, 0x30c /* offset 298 */ ,
+ 0x73, 0x30c /* offset 300 */ ,
+ 0x54, 0x327 /* offset 302 */ ,
+ 0x74, 0x327 /* offset 304 */ ,
+ 0x54, 0x30c /* offset 306 */ ,
+ 0x74, 0x30c /* offset 308 */ ,
+ 0x55, 0x303 /* offset 310 */ ,
+ 0x75, 0x303 /* offset 312 */ ,
+ 0x55, 0x304 /* offset 314 */ ,
+ 0x75, 0x304 /* offset 316 */ ,
+ 0x55, 0x306 /* offset 318 */ ,
+ 0x75, 0x306 /* offset 320 */ ,
+ 0x55, 0x30a /* offset 322 */ ,
+ 0x75, 0x30a /* offset 324 */ ,
+ 0x55, 0x30b /* offset 326 */ ,
+ 0x75, 0x30b /* offset 328 */ ,
+ 0x55, 0x328 /* offset 330 */ ,
+ 0x75, 0x328 /* offset 332 */ ,
+ 0x57, 0x302 /* offset 334 */ ,
+ 0x77, 0x302 /* offset 336 */ ,
+ 0x59, 0x302 /* offset 338 */ ,
+ 0x79, 0x302 /* offset 340 */ ,
+ 0x59, 0x308 /* offset 342 */ ,
+ 0x5a, 0x301 /* offset 344 */ ,
+ 0x7a, 0x301 /* offset 346 */ ,
+ 0x5a, 0x307 /* offset 348 */ ,
+ 0x7a, 0x307 /* offset 350 */ ,
+ 0x5a, 0x30c /* offset 352 */ ,
+ 0x7a, 0x30c /* offset 354 */ ,
+ 0x73 /* offset 356 */ ,
+ 0x4f, 0x31b /* offset 357 */ ,
+ 0x6f, 0x31b /* offset 359 */ ,
+ 0x55, 0x31b /* offset 361 */ ,
+ 0x75, 0x31b /* offset 363 */ ,
+ 0x44, 0x5a, 0x30c /* offset 365 */ ,
+ 0x44, 0x7a, 0x30c /* offset 368 */ ,
+ 0x64, 0x7a, 0x30c /* offset 371 */ ,
+ 0x4c, 0x4a /* offset 374 */ ,
+ 0x4c, 0x6a /* offset 376 */ ,
+ 0x6c, 0x6a /* offset 378 */ ,
+ 0x4e, 0x4a /* offset 380 */ ,
+ 0x4e, 0x6a /* offset 382 */ ,
+ 0x6e, 0x6a /* offset 384 */ ,
+ 0x41, 0x30c /* offset 386 */ ,
+ 0x61, 0x30c /* offset 388 */ ,
+ 0x49, 0x30c /* offset 390 */ ,
+ 0x69, 0x30c /* offset 392 */ ,
+ 0x4f, 0x30c /* offset 394 */ ,
+ 0x6f, 0x30c /* offset 396 */ ,
+ 0x55, 0x30c /* offset 398 */ ,
+ 0x75, 0x30c /* offset 400 */ ,
+ 0x55, 0x308, 0x304 /* offset 402 */ ,
+ 0x75, 0x308, 0x304 /* offset 405 */ ,
+ 0x55, 0x308, 0x301 /* offset 408 */ ,
+ 0x75, 0x308, 0x301 /* offset 411 */ ,
+ 0x55, 0x308, 0x30c /* offset 414 */ ,
+ 0x75, 0x308, 0x30c /* offset 417 */ ,
+ 0x55, 0x308, 0x300 /* offset 420 */ ,
+ 0x75, 0x308, 0x300 /* offset 423 */ ,
+ 0x41, 0x308, 0x304 /* offset 426 */ ,
+ 0x61, 0x308, 0x304 /* offset 429 */ ,
+ 0x41, 0x307, 0x304 /* offset 432 */ ,
+ 0x61, 0x307, 0x304 /* offset 435 */ ,
+ 0xc6, 0x304 /* offset 438 */ ,
+ 0xe6, 0x304 /* offset 440 */ ,
+ 0x47, 0x30c /* offset 442 */ ,
+ 0x67, 0x30c /* offset 444 */ ,
+ 0x4b, 0x30c /* offset 446 */ ,
+ 0x6b, 0x30c /* offset 448 */ ,
+ 0x4f, 0x328 /* offset 450 */ ,
+ 0x6f, 0x328 /* offset 452 */ ,
+ 0x4f, 0x328, 0x304 /* offset 454 */ ,
+ 0x6f, 0x328, 0x304 /* offset 457 */ ,
+ 0x1b7, 0x30c /* offset 460 */ ,
+ 0x292, 0x30c /* offset 462 */ ,
+ 0x6a, 0x30c /* offset 464 */ ,
+ 0x44, 0x5a /* offset 466 */ ,
+ 0x44, 0x7a /* offset 468 */ ,
+ 0x64, 0x7a /* offset 470 */ ,
+ 0x47, 0x301 /* offset 472 */ ,
+ 0x67, 0x301 /* offset 474 */ ,
+ 0x4e, 0x300 /* offset 476 */ ,
+ 0x6e, 0x300 /* offset 478 */ ,
+ 0x41, 0x30a, 0x301 /* offset 480 */ ,
+ 0x61, 0x30a, 0x301 /* offset 483 */ ,
+ 0xc6, 0x301 /* offset 486 */ ,
+ 0xe6, 0x301 /* offset 488 */ ,
+ 0xd8, 0x301 /* offset 490 */ ,
+ 0xf8, 0x301 /* offset 492 */ ,
+ 0x41, 0x30f /* offset 494 */ ,
+ 0x61, 0x30f /* offset 496 */ ,
+ 0x41, 0x311 /* offset 498 */ ,
+ 0x61, 0x311 /* offset 500 */ ,
+ 0x45, 0x30f /* offset 502 */ ,
+ 0x65, 0x30f /* offset 504 */ ,
+ 0x45, 0x311 /* offset 506 */ ,
+ 0x65, 0x311 /* offset 508 */ ,
+ 0x49, 0x30f /* offset 510 */ ,
+ 0x69, 0x30f /* offset 512 */ ,
+ 0x49, 0x311 /* offset 514 */ ,
+ 0x69, 0x311 /* offset 516 */ ,
+ 0x4f, 0x30f /* offset 518 */ ,
+ 0x6f, 0x30f /* offset 520 */ ,
+ 0x4f, 0x311 /* offset 522 */ ,
+ 0x6f, 0x311 /* offset 524 */ ,
+ 0x52, 0x30f /* offset 526 */ ,
+ 0x72, 0x30f /* offset 528 */ ,
+ 0x52, 0x311 /* offset 530 */ ,
+ 0x72, 0x311 /* offset 532 */ ,
+ 0x55, 0x30f /* offset 534 */ ,
+ 0x75, 0x30f /* offset 536 */ ,
+ 0x55, 0x311 /* offset 538 */ ,
+ 0x75, 0x311 /* offset 540 */ ,
+ 0x53, 0x326 /* offset 542 */ ,
+ 0x73, 0x326 /* offset 544 */ ,
+ 0x54, 0x326 /* offset 546 */ ,
+ 0x74, 0x326 /* offset 548 */ ,
+ 0x48, 0x30c /* offset 550 */ ,
+ 0x68, 0x30c /* offset 552 */ ,
+ 0x41, 0x307 /* offset 554 */ ,
+ 0x61, 0x307 /* offset 556 */ ,
+ 0x45, 0x327 /* offset 558 */ ,
+ 0x65, 0x327 /* offset 560 */ ,
+ 0x4f, 0x308, 0x304 /* offset 562 */ ,
+ 0x6f, 0x308, 0x304 /* offset 565 */ ,
+ 0x4f, 0x303, 0x304 /* offset 568 */ ,
+ 0x6f, 0x303, 0x304 /* offset 571 */ ,
+ 0x4f, 0x307 /* offset 574 */ ,
+ 0x6f, 0x307 /* offset 576 */ ,
+ 0x4f, 0x307, 0x304 /* offset 578 */ ,
+ 0x6f, 0x307, 0x304 /* offset 581 */ ,
+ 0x59, 0x304 /* offset 584 */ ,
+ 0x79, 0x304 /* offset 586 */ ,
+ 0x68 /* offset 588 */ ,
+ 0x266 /* offset 589 */ ,
+ 0x6a /* offset 590 */ ,
+ 0x72 /* offset 591 */ ,
+ 0x279 /* offset 592 */ ,
+ 0x27b /* offset 593 */ ,
+ 0x281 /* offset 594 */ ,
+ 0x77 /* offset 595 */ ,
+ 0x79 /* offset 596 */ ,
+ 0x20, 0x306 /* offset 597 */ ,
+ 0x20, 0x307 /* offset 599 */ ,
+ 0x20, 0x30a /* offset 601 */ ,
+ 0x20, 0x328 /* offset 603 */ ,
+ 0x20, 0x303 /* offset 605 */ ,
+ 0x20, 0x30b /* offset 607 */ ,
+ 0x263 /* offset 609 */ ,
+ 0x6c /* offset 610 */ ,
+ 0x78 /* offset 611 */ ,
+ 0x295 /* offset 612 */ ,
+ 0x300 /* offset 613 */ ,
+ 0x301 /* offset 614 */ ,
+ 0x313 /* offset 615 */ ,
+ 0x308, 0x301 /* offset 616 */ ,
+ 0x2b9 /* offset 618 */ ,
+ 0x20, 0x345 /* offset 619 */ ,
+ 0x3b /* offset 621 */ ,
+ 0x20, 0x308, 0x301 /* offset 622 */ ,
+ 0x391, 0x301 /* offset 625 */ ,
+ 0xb7 /* offset 627 */ ,
+ 0x395, 0x301 /* offset 628 */ ,
+ 0x397, 0x301 /* offset 630 */ ,
+ 0x399, 0x301 /* offset 632 */ ,
+ 0x39f, 0x301 /* offset 634 */ ,
+ 0x3a5, 0x301 /* offset 636 */ ,
+ 0x3a9, 0x301 /* offset 638 */ ,
+ 0x3b9, 0x308, 0x301 /* offset 640 */ ,
+ 0x399, 0x308 /* offset 643 */ ,
+ 0x3a5, 0x308 /* offset 645 */ ,
+ 0x3b1, 0x301 /* offset 647 */ ,
+ 0x3b5, 0x301 /* offset 649 */ ,
+ 0x3b7, 0x301 /* offset 651 */ ,
+ 0x3b9, 0x301 /* offset 653 */ ,
+ 0x3c5, 0x308, 0x301 /* offset 655 */ ,
+ 0x3b9, 0x308 /* offset 658 */ ,
+ 0x3c5, 0x308 /* offset 660 */ ,
+ 0x3bf, 0x301 /* offset 662 */ ,
+ 0x3c5, 0x301 /* offset 664 */ ,
+ 0x3c9, 0x301 /* offset 666 */ ,
+ 0x3b2 /* offset 668 */ ,
+ 0x3b8 /* offset 669 */ ,
+ 0x3a5 /* offset 670 */ ,
+ 0x3c6 /* offset 671 */ ,
+ 0x3c0 /* offset 672 */ ,
+ 0x3ba /* offset 673 */ ,
+ 0x3c1 /* offset 674 */ ,
+ 0x3c2 /* offset 675 */ ,
+ 0x398 /* offset 676 */ ,
+ 0x3b5 /* offset 677 */ ,
+ 0x415, 0x300 /* offset 678 */ ,
+ 0x415, 0x308 /* offset 680 */ ,
+ 0x413, 0x301 /* offset 682 */ ,
+ 0x406, 0x308 /* offset 684 */ ,
+ 0x41a, 0x301 /* offset 686 */ ,
+ 0x418, 0x300 /* offset 688 */ ,
+ 0x423, 0x306 /* offset 690 */ ,
+ 0x418, 0x306 /* offset 692 */ ,
+ 0x438, 0x306 /* offset 694 */ ,
+ 0x435, 0x300 /* offset 696 */ ,
+ 0x435, 0x308 /* offset 698 */ ,
+ 0x433, 0x301 /* offset 700 */ ,
+ 0x456, 0x308 /* offset 702 */ ,
+ 0x43a, 0x301 /* offset 704 */ ,
+ 0x438, 0x300 /* offset 706 */ ,
+ 0x443, 0x306 /* offset 708 */ ,
+ 0x474, 0x30f /* offset 710 */ ,
+ 0x475, 0x30f /* offset 712 */ ,
+ 0x416, 0x306 /* offset 714 */ ,
+ 0x436, 0x306 /* offset 716 */ ,
+ 0x410, 0x306 /* offset 718 */ ,
+ 0x430, 0x306 /* offset 720 */ ,
+ 0x410, 0x308 /* offset 722 */ ,
+ 0x430, 0x308 /* offset 724 */ ,
+ 0x415, 0x306 /* offset 726 */ ,
+ 0x435, 0x306 /* offset 728 */ ,
+ 0x4d8, 0x308 /* offset 730 */ ,
+ 0x4d9, 0x308 /* offset 732 */ ,
+ 0x416, 0x308 /* offset 734 */ ,
+ 0x436, 0x308 /* offset 736 */ ,
+ 0x417, 0x308 /* offset 738 */ ,
+ 0x437, 0x308 /* offset 740 */ ,
+ 0x418, 0x304 /* offset 742 */ ,
+ 0x438, 0x304 /* offset 744 */ ,
+ 0x418, 0x308 /* offset 746 */ ,
+ 0x438, 0x308 /* offset 748 */ ,
+ 0x41e, 0x308 /* offset 750 */ ,
+ 0x43e, 0x308 /* offset 752 */ ,
+ 0x4e8, 0x308 /* offset 754 */ ,
+ 0x4e9, 0x308 /* offset 756 */ ,
+ 0x42d, 0x308 /* offset 758 */ ,
+ 0x44d, 0x308 /* offset 760 */ ,
+ 0x423, 0x304 /* offset 762 */ ,
+ 0x443, 0x304 /* offset 764 */ ,
+ 0x423, 0x308 /* offset 766 */ ,
+ 0x443, 0x308 /* offset 768 */ ,
+ 0x423, 0x30b /* offset 770 */ ,
+ 0x443, 0x30b /* offset 772 */ ,
+ 0x427, 0x308 /* offset 774 */ ,
+ 0x447, 0x308 /* offset 776 */ ,
+ 0x42b, 0x308 /* offset 778 */ ,
+ 0x44b, 0x308 /* offset 780 */ ,
+ 0x565, 0x582 /* offset 782 */ ,
+ 0x627, 0x653 /* offset 784 */ ,
+ 0x627, 0x654 /* offset 786 */ ,
+ 0x648, 0x654 /* offset 788 */ ,
+ 0x627, 0x655 /* offset 790 */ ,
+ 0x64a, 0x654 /* offset 792 */ ,
+ 0x627, 0x674 /* offset 794 */ ,
+ 0x648, 0x674 /* offset 796 */ ,
+ 0x6c7, 0x674 /* offset 798 */ ,
+ 0x64a, 0x674 /* offset 800 */ ,
+ 0x6d5, 0x654 /* offset 802 */ ,
+ 0x6c1, 0x654 /* offset 804 */ ,
+ 0x6d2, 0x654 /* offset 806 */ ,
+ 0x928, 0x93c /* offset 808 */ ,
+ 0x930, 0x93c /* offset 810 */ ,
+ 0x933, 0x93c /* offset 812 */ ,
+ 0x915, 0x93c /* offset 814 */ ,
+ 0x916, 0x93c /* offset 816 */ ,
+ 0x917, 0x93c /* offset 818 */ ,
+ 0x91c, 0x93c /* offset 820 */ ,
+ 0x921, 0x93c /* offset 822 */ ,
+ 0x922, 0x93c /* offset 824 */ ,
+ 0x92b, 0x93c /* offset 826 */ ,
+ 0x92f, 0x93c /* offset 828 */ ,
+ 0x9c7, 0x9be /* offset 830 */ ,
+ 0x9c7, 0x9d7 /* offset 832 */ ,
+ 0x9a1, 0x9bc /* offset 834 */ ,
+ 0x9a2, 0x9bc /* offset 836 */ ,
+ 0x9af, 0x9bc /* offset 838 */ ,
+ 0xa32, 0xa3c /* offset 840 */ ,
+ 0xa38, 0xa3c /* offset 842 */ ,
+ 0xa16, 0xa3c /* offset 844 */ ,
+ 0xa17, 0xa3c /* offset 846 */ ,
+ 0xa1c, 0xa3c /* offset 848 */ ,
+ 0xa2b, 0xa3c /* offset 850 */ ,
+ 0xb47, 0xb56 /* offset 852 */ ,
+ 0xb47, 0xb3e /* offset 854 */ ,
+ 0xb47, 0xb57 /* offset 856 */ ,
+ 0xb21, 0xb3c /* offset 858 */ ,
+ 0xb22, 0xb3c /* offset 860 */ ,
+ 0xb92, 0xbd7 /* offset 862 */ ,
+ 0xbc6, 0xbbe /* offset 864 */ ,
+ 0xbc7, 0xbbe /* offset 866 */ ,
+ 0xbc6, 0xbd7 /* offset 868 */ ,
+ 0xc46, 0xc56 /* offset 870 */ ,
+ 0xcbf, 0xcd5 /* offset 872 */ ,
+ 0xcc6, 0xcd5 /* offset 874 */ ,
+ 0xcc6, 0xcd6 /* offset 876 */ ,
+ 0xcc6, 0xcc2 /* offset 878 */ ,
+ 0xcc6, 0xcc2, 0xcd5 /* offset 880 */ ,
+ 0xd46, 0xd3e /* offset 883 */ ,
+ 0xd47, 0xd3e /* offset 885 */ ,
+ 0xd46, 0xd57 /* offset 887 */ ,
+ 0xdd9, 0xdca /* offset 889 */ ,
+ 0xdd9, 0xdcf /* offset 891 */ ,
+ 0xdd9, 0xdcf, 0xdca /* offset 893 */ ,
+ 0xdd9, 0xddf /* offset 896 */ ,
+ 0xe4d, 0xe32 /* offset 898 */ ,
+ 0xecd, 0xeb2 /* offset 900 */ ,
+ 0xeab, 0xe99 /* offset 902 */ ,
+ 0xeab, 0xea1 /* offset 904 */ ,
+ 0xf0b /* offset 906 */ ,
+ 0xf42, 0xfb7 /* offset 907 */ ,
+ 0xf4c, 0xfb7 /* offset 909 */ ,
+ 0xf51, 0xfb7 /* offset 911 */ ,
+ 0xf56, 0xfb7 /* offset 913 */ ,
+ 0xf5b, 0xfb7 /* offset 915 */ ,
+ 0xf40, 0xfb5 /* offset 917 */ ,
+ 0xf71, 0xf72 /* offset 919 */ ,
+ 0xf71, 0xf74 /* offset 921 */ ,
+ 0xfb2, 0xf80 /* offset 923 */ ,
+ 0xfb2, 0xf71, 0xf80 /* offset 925 */ ,
+ 0xfb3, 0xf80 /* offset 928 */ ,
+ 0xfb3, 0xf71, 0xf80 /* offset 930 */ ,
+ 0xf71, 0xf80 /* offset 933 */ ,
+ 0xf92, 0xfb7 /* offset 935 */ ,
+ 0xf9c, 0xfb7 /* offset 937 */ ,
+ 0xfa1, 0xfb7 /* offset 939 */ ,
+ 0xfa6, 0xfb7 /* offset 941 */ ,
+ 0xfab, 0xfb7 /* offset 943 */ ,
+ 0xf90, 0xfb5 /* offset 945 */ ,
+ 0x1025, 0x102e /* offset 947 */ ,
+ 0x41, 0x325 /* offset 949 */ ,
+ 0x61, 0x325 /* offset 951 */ ,
+ 0x42, 0x307 /* offset 953 */ ,
+ 0x62, 0x307 /* offset 955 */ ,
+ 0x42, 0x323 /* offset 957 */ ,
+ 0x62, 0x323 /* offset 959 */ ,
+ 0x42, 0x331 /* offset 961 */ ,
+ 0x62, 0x331 /* offset 963 */ ,
+ 0x43, 0x327, 0x301 /* offset 965 */ ,
+ 0x63, 0x327, 0x301 /* offset 968 */ ,
+ 0x44, 0x307 /* offset 971 */ ,
+ 0x64, 0x307 /* offset 973 */ ,
+ 0x44, 0x323 /* offset 975 */ ,
+ 0x64, 0x323 /* offset 977 */ ,
+ 0x44, 0x331 /* offset 979 */ ,
+ 0x64, 0x331 /* offset 981 */ ,
+ 0x44, 0x327 /* offset 983 */ ,
+ 0x64, 0x327 /* offset 985 */ ,
+ 0x44, 0x32d /* offset 987 */ ,
+ 0x64, 0x32d /* offset 989 */ ,
+ 0x45, 0x304, 0x300 /* offset 991 */ ,
+ 0x65, 0x304, 0x300 /* offset 994 */ ,
+ 0x45, 0x304, 0x301 /* offset 997 */ ,
+ 0x65, 0x304, 0x301 /* offset 1000 */ ,
+ 0x45, 0x32d /* offset 1003 */ ,
+ 0x65, 0x32d /* offset 1005 */ ,
+ 0x45, 0x330 /* offset 1007 */ ,
+ 0x65, 0x330 /* offset 1009 */ ,
+ 0x45, 0x327, 0x306 /* offset 1011 */ ,
+ 0x65, 0x327, 0x306 /* offset 1014 */ ,
+ 0x46, 0x307 /* offset 1017 */ ,
+ 0x66, 0x307 /* offset 1019 */ ,
+ 0x47, 0x304 /* offset 1021 */ ,
+ 0x67, 0x304 /* offset 1023 */ ,
+ 0x48, 0x307 /* offset 1025 */ ,
+ 0x68, 0x307 /* offset 1027 */ ,
+ 0x48, 0x323 /* offset 1029 */ ,
+ 0x68, 0x323 /* offset 1031 */ ,
+ 0x48, 0x308 /* offset 1033 */ ,
+ 0x68, 0x308 /* offset 1035 */ ,
+ 0x48, 0x327 /* offset 1037 */ ,
+ 0x68, 0x327 /* offset 1039 */ ,
+ 0x48, 0x32e /* offset 1041 */ ,
+ 0x68, 0x32e /* offset 1043 */ ,
+ 0x49, 0x330 /* offset 1045 */ ,
+ 0x69, 0x330 /* offset 1047 */ ,
+ 0x49, 0x308, 0x301 /* offset 1049 */ ,
+ 0x69, 0x308, 0x301 /* offset 1052 */ ,
+ 0x4b, 0x301 /* offset 1055 */ ,
+ 0x6b, 0x301 /* offset 1057 */ ,
+ 0x4b, 0x323 /* offset 1059 */ ,
+ 0x6b, 0x323 /* offset 1061 */ ,
+ 0x4b, 0x331 /* offset 1063 */ ,
+ 0x6b, 0x331 /* offset 1065 */ ,
+ 0x4c, 0x323 /* offset 1067 */ ,
+ 0x6c, 0x323 /* offset 1069 */ ,
+ 0x4c, 0x323, 0x304 /* offset 1071 */ ,
+ 0x6c, 0x323, 0x304 /* offset 1074 */ ,
+ 0x4c, 0x331 /* offset 1077 */ ,
+ 0x6c, 0x331 /* offset 1079 */ ,
+ 0x4c, 0x32d /* offset 1081 */ ,
+ 0x6c, 0x32d /* offset 1083 */ ,
+ 0x4d, 0x301 /* offset 1085 */ ,
+ 0x6d, 0x301 /* offset 1087 */ ,
+ 0x4d, 0x307 /* offset 1089 */ ,
+ 0x6d, 0x307 /* offset 1091 */ ,
+ 0x4d, 0x323 /* offset 1093 */ ,
+ 0x6d, 0x323 /* offset 1095 */ ,
+ 0x4e, 0x307 /* offset 1097 */ ,
+ 0x6e, 0x307 /* offset 1099 */ ,
+ 0x4e, 0x323 /* offset 1101 */ ,
+ 0x6e, 0x323 /* offset 1103 */ ,
+ 0x4e, 0x331 /* offset 1105 */ ,
+ 0x6e, 0x331 /* offset 1107 */ ,
+ 0x4e, 0x32d /* offset 1109 */ ,
+ 0x6e, 0x32d /* offset 1111 */ ,
+ 0x4f, 0x303, 0x301 /* offset 1113 */ ,
+ 0x6f, 0x303, 0x301 /* offset 1116 */ ,
+ 0x4f, 0x303, 0x308 /* offset 1119 */ ,
+ 0x6f, 0x303, 0x308 /* offset 1122 */ ,
+ 0x4f, 0x304, 0x300 /* offset 1125 */ ,
+ 0x6f, 0x304, 0x300 /* offset 1128 */ ,
+ 0x4f, 0x304, 0x301 /* offset 1131 */ ,
+ 0x6f, 0x304, 0x301 /* offset 1134 */ ,
+ 0x50, 0x301 /* offset 1137 */ ,
+ 0x70, 0x301 /* offset 1139 */ ,
+ 0x50, 0x307 /* offset 1141 */ ,
+ 0x70, 0x307 /* offset 1143 */ ,
+ 0x52, 0x307 /* offset 1145 */ ,
+ 0x72, 0x307 /* offset 1147 */ ,
+ 0x52, 0x323 /* offset 1149 */ ,
+ 0x72, 0x323 /* offset 1151 */ ,
+ 0x52, 0x323, 0x304 /* offset 1153 */ ,
+ 0x72, 0x323, 0x304 /* offset 1156 */ ,
+ 0x52, 0x331 /* offset 1159 */ ,
+ 0x72, 0x331 /* offset 1161 */ ,
+ 0x53, 0x307 /* offset 1163 */ ,
+ 0x73, 0x307 /* offset 1165 */ ,
+ 0x53, 0x323 /* offset 1167 */ ,
+ 0x73, 0x323 /* offset 1169 */ ,
+ 0x53, 0x301, 0x307 /* offset 1171 */ ,
+ 0x73, 0x301, 0x307 /* offset 1174 */ ,
+ 0x53, 0x30c, 0x307 /* offset 1177 */ ,
+ 0x73, 0x30c, 0x307 /* offset 1180 */ ,
+ 0x53, 0x323, 0x307 /* offset 1183 */ ,
+ 0x73, 0x323, 0x307 /* offset 1186 */ ,
+ 0x54, 0x307 /* offset 1189 */ ,
+ 0x74, 0x307 /* offset 1191 */ ,
+ 0x54, 0x323 /* offset 1193 */ ,
+ 0x74, 0x323 /* offset 1195 */ ,
+ 0x54, 0x331 /* offset 1197 */ ,
+ 0x74, 0x331 /* offset 1199 */ ,
+ 0x54, 0x32d /* offset 1201 */ ,
+ 0x74, 0x32d /* offset 1203 */ ,
+ 0x55, 0x324 /* offset 1205 */ ,
+ 0x75, 0x324 /* offset 1207 */ ,
+ 0x55, 0x330 /* offset 1209 */ ,
+ 0x75, 0x330 /* offset 1211 */ ,
+ 0x55, 0x32d /* offset 1213 */ ,
+ 0x75, 0x32d /* offset 1215 */ ,
+ 0x55, 0x303, 0x301 /* offset 1217 */ ,
+ 0x75, 0x303, 0x301 /* offset 1220 */ ,
+ 0x55, 0x304, 0x308 /* offset 1223 */ ,
+ 0x75, 0x304, 0x308 /* offset 1226 */ ,
+ 0x56, 0x303 /* offset 1229 */ ,
+ 0x76, 0x303 /* offset 1231 */ ,
+ 0x56, 0x323 /* offset 1233 */ ,
+ 0x76, 0x323 /* offset 1235 */ ,
+ 0x57, 0x300 /* offset 1237 */ ,
+ 0x77, 0x300 /* offset 1239 */ ,
+ 0x57, 0x301 /* offset 1241 */ ,
+ 0x77, 0x301 /* offset 1243 */ ,
+ 0x57, 0x308 /* offset 1245 */ ,
+ 0x77, 0x308 /* offset 1247 */ ,
+ 0x57, 0x307 /* offset 1249 */ ,
+ 0x77, 0x307 /* offset 1251 */ ,
+ 0x57, 0x323 /* offset 1253 */ ,
+ 0x77, 0x323 /* offset 1255 */ ,
+ 0x58, 0x307 /* offset 1257 */ ,
+ 0x78, 0x307 /* offset 1259 */ ,
+ 0x58, 0x308 /* offset 1261 */ ,
+ 0x78, 0x308 /* offset 1263 */ ,
+ 0x59, 0x307 /* offset 1265 */ ,
+ 0x79, 0x307 /* offset 1267 */ ,
+ 0x5a, 0x302 /* offset 1269 */ ,
+ 0x7a, 0x302 /* offset 1271 */ ,
+ 0x5a, 0x323 /* offset 1273 */ ,
+ 0x7a, 0x323 /* offset 1275 */ ,
+ 0x5a, 0x331 /* offset 1277 */ ,
+ 0x7a, 0x331 /* offset 1279 */ ,
+ 0x68, 0x331 /* offset 1281 */ ,
+ 0x74, 0x308 /* offset 1283 */ ,
+ 0x77, 0x30a /* offset 1285 */ ,
+ 0x79, 0x30a /* offset 1287 */ ,
+ 0x61, 0x2be /* offset 1289 */ ,
+ 0x41, 0x323 /* offset 1291 */ ,
+ 0x61, 0x323 /* offset 1293 */ ,
+ 0x41, 0x309 /* offset 1295 */ ,
+ 0x61, 0x309 /* offset 1297 */ ,
+ 0x41, 0x302, 0x301 /* offset 1299 */ ,
+ 0x61, 0x302, 0x301 /* offset 1302 */ ,
+ 0x41, 0x302, 0x300 /* offset 1305 */ ,
+ 0x61, 0x302, 0x300 /* offset 1308 */ ,
+ 0x41, 0x302, 0x309 /* offset 1311 */ ,
+ 0x61, 0x302, 0x309 /* offset 1314 */ ,
+ 0x41, 0x302, 0x303 /* offset 1317 */ ,
+ 0x61, 0x302, 0x303 /* offset 1320 */ ,
+ 0x41, 0x323, 0x302 /* offset 1323 */ ,
+ 0x61, 0x323, 0x302 /* offset 1326 */ ,
+ 0x41, 0x306, 0x301 /* offset 1329 */ ,
+ 0x61, 0x306, 0x301 /* offset 1332 */ ,
+ 0x41, 0x306, 0x300 /* offset 1335 */ ,
+ 0x61, 0x306, 0x300 /* offset 1338 */ ,
+ 0x41, 0x306, 0x309 /* offset 1341 */ ,
+ 0x61, 0x306, 0x309 /* offset 1344 */ ,
+ 0x41, 0x306, 0x303 /* offset 1347 */ ,
+ 0x61, 0x306, 0x303 /* offset 1350 */ ,
+ 0x41, 0x323, 0x306 /* offset 1353 */ ,
+ 0x61, 0x323, 0x306 /* offset 1356 */ ,
+ 0x45, 0x323 /* offset 1359 */ ,
+ 0x65, 0x323 /* offset 1361 */ ,
+ 0x45, 0x309 /* offset 1363 */ ,
+ 0x65, 0x309 /* offset 1365 */ ,
+ 0x45, 0x303 /* offset 1367 */ ,
+ 0x65, 0x303 /* offset 1369 */ ,
+ 0x45, 0x302, 0x301 /* offset 1371 */ ,
+ 0x65, 0x302, 0x301 /* offset 1374 */ ,
+ 0x45, 0x302, 0x300 /* offset 1377 */ ,
+ 0x65, 0x302, 0x300 /* offset 1380 */ ,
+ 0x45, 0x302, 0x309 /* offset 1383 */ ,
+ 0x65, 0x302, 0x309 /* offset 1386 */ ,
+ 0x45, 0x302, 0x303 /* offset 1389 */ ,
+ 0x65, 0x302, 0x303 /* offset 1392 */ ,
+ 0x45, 0x323, 0x302 /* offset 1395 */ ,
+ 0x65, 0x323, 0x302 /* offset 1398 */ ,
+ 0x49, 0x309 /* offset 1401 */ ,
+ 0x69, 0x309 /* offset 1403 */ ,
+ 0x49, 0x323 /* offset 1405 */ ,
+ 0x69, 0x323 /* offset 1407 */ ,
+ 0x4f, 0x323 /* offset 1409 */ ,
+ 0x6f, 0x323 /* offset 1411 */ ,
+ 0x4f, 0x309 /* offset 1413 */ ,
+ 0x6f, 0x309 /* offset 1415 */ ,
+ 0x4f, 0x302, 0x301 /* offset 1417 */ ,
+ 0x6f, 0x302, 0x301 /* offset 1420 */ ,
+ 0x4f, 0x302, 0x300 /* offset 1423 */ ,
+ 0x6f, 0x302, 0x300 /* offset 1426 */ ,
+ 0x4f, 0x302, 0x309 /* offset 1429 */ ,
+ 0x6f, 0x302, 0x309 /* offset 1432 */ ,
+ 0x4f, 0x302, 0x303 /* offset 1435 */ ,
+ 0x6f, 0x302, 0x303 /* offset 1438 */ ,
+ 0x4f, 0x323, 0x302 /* offset 1441 */ ,
+ 0x6f, 0x323, 0x302 /* offset 1444 */ ,
+ 0x4f, 0x31b, 0x301 /* offset 1447 */ ,
+ 0x6f, 0x31b, 0x301 /* offset 1450 */ ,
+ 0x4f, 0x31b, 0x300 /* offset 1453 */ ,
+ 0x6f, 0x31b, 0x300 /* offset 1456 */ ,
+ 0x4f, 0x31b, 0x309 /* offset 1459 */ ,
+ 0x6f, 0x31b, 0x309 /* offset 1462 */ ,
+ 0x4f, 0x31b, 0x303 /* offset 1465 */ ,
+ 0x6f, 0x31b, 0x303 /* offset 1468 */ ,
+ 0x4f, 0x31b, 0x323 /* offset 1471 */ ,
+ 0x6f, 0x31b, 0x323 /* offset 1474 */ ,
+ 0x55, 0x323 /* offset 1477 */ ,
+ 0x75, 0x323 /* offset 1479 */ ,
+ 0x55, 0x309 /* offset 1481 */ ,
+ 0x75, 0x309 /* offset 1483 */ ,
+ 0x55, 0x31b, 0x301 /* offset 1485 */ ,
+ 0x75, 0x31b, 0x301 /* offset 1488 */ ,
+ 0x55, 0x31b, 0x300 /* offset 1491 */ ,
+ 0x75, 0x31b, 0x300 /* offset 1494 */ ,
+ 0x55, 0x31b, 0x309 /* offset 1497 */ ,
+ 0x75, 0x31b, 0x309 /* offset 1500 */ ,
+ 0x55, 0x31b, 0x303 /* offset 1503 */ ,
+ 0x75, 0x31b, 0x303 /* offset 1506 */ ,
+ 0x55, 0x31b, 0x323 /* offset 1509 */ ,
+ 0x75, 0x31b, 0x323 /* offset 1512 */ ,
+ 0x59, 0x300 /* offset 1515 */ ,
+ 0x79, 0x300 /* offset 1517 */ ,
+ 0x59, 0x323 /* offset 1519 */ ,
+ 0x79, 0x323 /* offset 1521 */ ,
+ 0x59, 0x309 /* offset 1523 */ ,
+ 0x79, 0x309 /* offset 1525 */ ,
+ 0x59, 0x303 /* offset 1527 */ ,
+ 0x79, 0x303 /* offset 1529 */ ,
+ 0x3b1, 0x313 /* offset 1531 */ ,
+ 0x3b1, 0x314 /* offset 1533 */ ,
+ 0x3b1, 0x313, 0x300 /* offset 1535 */ ,
+ 0x3b1, 0x314, 0x300 /* offset 1538 */ ,
+ 0x3b1, 0x313, 0x301 /* offset 1541 */ ,
+ 0x3b1, 0x314, 0x301 /* offset 1544 */ ,
+ 0x3b1, 0x313, 0x342 /* offset 1547 */ ,
+ 0x3b1, 0x314, 0x342 /* offset 1550 */ ,
+ 0x391, 0x313 /* offset 1553 */ ,
+ 0x391, 0x314 /* offset 1555 */ ,
+ 0x391, 0x313, 0x300 /* offset 1557 */ ,
+ 0x391, 0x314, 0x300 /* offset 1560 */ ,
+ 0x391, 0x313, 0x301 /* offset 1563 */ ,
+ 0x391, 0x314, 0x301 /* offset 1566 */ ,
+ 0x391, 0x313, 0x342 /* offset 1569 */ ,
+ 0x391, 0x314, 0x342 /* offset 1572 */ ,
+ 0x3b5, 0x313 /* offset 1575 */ ,
+ 0x3b5, 0x314 /* offset 1577 */ ,
+ 0x3b5, 0x313, 0x300 /* offset 1579 */ ,
+ 0x3b5, 0x314, 0x300 /* offset 1582 */ ,
+ 0x3b5, 0x313, 0x301 /* offset 1585 */ ,
+ 0x3b5, 0x314, 0x301 /* offset 1588 */ ,
+ 0x395, 0x313 /* offset 1591 */ ,
+ 0x395, 0x314 /* offset 1593 */ ,
+ 0x395, 0x313, 0x300 /* offset 1595 */ ,
+ 0x395, 0x314, 0x300 /* offset 1598 */ ,
+ 0x395, 0x313, 0x301 /* offset 1601 */ ,
+ 0x395, 0x314, 0x301 /* offset 1604 */ ,
+ 0x3b7, 0x313 /* offset 1607 */ ,
+ 0x3b7, 0x314 /* offset 1609 */ ,
+ 0x3b7, 0x313, 0x300 /* offset 1611 */ ,
+ 0x3b7, 0x314, 0x300 /* offset 1614 */ ,
+ 0x3b7, 0x313, 0x301 /* offset 1617 */ ,
+ 0x3b7, 0x314, 0x301 /* offset 1620 */ ,
+ 0x3b7, 0x313, 0x342 /* offset 1623 */ ,
+ 0x3b7, 0x314, 0x342 /* offset 1626 */ ,
+ 0x397, 0x313 /* offset 1629 */ ,
+ 0x397, 0x314 /* offset 1631 */ ,
+ 0x397, 0x313, 0x300 /* offset 1633 */ ,
+ 0x397, 0x314, 0x300 /* offset 1636 */ ,
+ 0x397, 0x313, 0x301 /* offset 1639 */ ,
+ 0x397, 0x314, 0x301 /* offset 1642 */ ,
+ 0x397, 0x313, 0x342 /* offset 1645 */ ,
+ 0x397, 0x314, 0x342 /* offset 1648 */ ,
+ 0x3b9, 0x313 /* offset 1651 */ ,
+ 0x3b9, 0x314 /* offset 1653 */ ,
+ 0x3b9, 0x313, 0x300 /* offset 1655 */ ,
+ 0x3b9, 0x314, 0x300 /* offset 1658 */ ,
+ 0x3b9, 0x313, 0x301 /* offset 1661 */ ,
+ 0x3b9, 0x314, 0x301 /* offset 1664 */ ,
+ 0x3b9, 0x313, 0x342 /* offset 1667 */ ,
+ 0x3b9, 0x314, 0x342 /* offset 1670 */ ,
+ 0x399, 0x313 /* offset 1673 */ ,
+ 0x399, 0x314 /* offset 1675 */ ,
+ 0x399, 0x313, 0x300 /* offset 1677 */ ,
+ 0x399, 0x314, 0x300 /* offset 1680 */ ,
+ 0x399, 0x313, 0x301 /* offset 1683 */ ,
+ 0x399, 0x314, 0x301 /* offset 1686 */ ,
+ 0x399, 0x313, 0x342 /* offset 1689 */ ,
+ 0x399, 0x314, 0x342 /* offset 1692 */ ,
+ 0x3bf, 0x313 /* offset 1695 */ ,
+ 0x3bf, 0x314 /* offset 1697 */ ,
+ 0x3bf, 0x313, 0x300 /* offset 1699 */ ,
+ 0x3bf, 0x314, 0x300 /* offset 1702 */ ,
+ 0x3bf, 0x313, 0x301 /* offset 1705 */ ,
+ 0x3bf, 0x314, 0x301 /* offset 1708 */ ,
+ 0x39f, 0x313 /* offset 1711 */ ,
+ 0x39f, 0x314 /* offset 1713 */ ,
+ 0x39f, 0x313, 0x300 /* offset 1715 */ ,
+ 0x39f, 0x314, 0x300 /* offset 1718 */ ,
+ 0x39f, 0x313, 0x301 /* offset 1721 */ ,
+ 0x39f, 0x314, 0x301 /* offset 1724 */ ,
+ 0x3c5, 0x313 /* offset 1727 */ ,
+ 0x3c5, 0x314 /* offset 1729 */ ,
+ 0x3c5, 0x313, 0x300 /* offset 1731 */ ,
+ 0x3c5, 0x314, 0x300 /* offset 1734 */ ,
+ 0x3c5, 0x313, 0x301 /* offset 1737 */ ,
+ 0x3c5, 0x314, 0x301 /* offset 1740 */ ,
+ 0x3c5, 0x313, 0x342 /* offset 1743 */ ,
+ 0x3c5, 0x314, 0x342 /* offset 1746 */ ,
+ 0x3a5, 0x314 /* offset 1749 */ ,
+ 0x3a5, 0x314, 0x300 /* offset 1751 */ ,
+ 0x3a5, 0x314, 0x301 /* offset 1754 */ ,
+ 0x3a5, 0x314, 0x342 /* offset 1757 */ ,
+ 0x3c9, 0x313 /* offset 1760 */ ,
+ 0x3c9, 0x314 /* offset 1762 */ ,
+ 0x3c9, 0x313, 0x300 /* offset 1764 */ ,
+ 0x3c9, 0x314, 0x300 /* offset 1767 */ ,
+ 0x3c9, 0x313, 0x301 /* offset 1770 */ ,
+ 0x3c9, 0x314, 0x301 /* offset 1773 */ ,
+ 0x3c9, 0x313, 0x342 /* offset 1776 */ ,
+ 0x3c9, 0x314, 0x342 /* offset 1779 */ ,
+ 0x3a9, 0x313 /* offset 1782 */ ,
+ 0x3a9, 0x314 /* offset 1784 */ ,
+ 0x3a9, 0x313, 0x300 /* offset 1786 */ ,
+ 0x3a9, 0x314, 0x300 /* offset 1789 */ ,
+ 0x3a9, 0x313, 0x301 /* offset 1792 */ ,
+ 0x3a9, 0x314, 0x301 /* offset 1795 */ ,
+ 0x3a9, 0x313, 0x342 /* offset 1798 */ ,
+ 0x3a9, 0x314, 0x342 /* offset 1801 */ ,
+ 0x3b1, 0x300 /* offset 1804 */ ,
+ 0x3b5, 0x300 /* offset 1806 */ ,
+ 0x3b7, 0x300 /* offset 1808 */ ,
+ 0x3b9, 0x300 /* offset 1810 */ ,
+ 0x3bf, 0x300 /* offset 1812 */ ,
+ 0x3c5, 0x300 /* offset 1814 */ ,
+ 0x3c9, 0x300 /* offset 1816 */ ,
+ 0x3b1, 0x313, 0x345 /* offset 1818 */ ,
+ 0x3b1, 0x314, 0x345 /* offset 1821 */ ,
+ 0x3b1, 0x313, 0x300, 0x345 /* offset 1824 */ ,
+ 0x3b1, 0x314, 0x300, 0x345 /* offset 1828 */ ,
+ 0x3b1, 0x313, 0x301, 0x345 /* offset 1832 */ ,
+ 0x3b1, 0x314, 0x301, 0x345 /* offset 1836 */ ,
+ 0x3b1, 0x313, 0x342, 0x345 /* offset 1840 */ ,
+ 0x3b1, 0x314, 0x342, 0x345 /* offset 1844 */ ,
+ 0x391, 0x313, 0x345 /* offset 1848 */ ,
+ 0x391, 0x314, 0x345 /* offset 1851 */ ,
+ 0x391, 0x313, 0x300, 0x345 /* offset 1854 */ ,
+ 0x391, 0x314, 0x300, 0x345 /* offset 1858 */ ,
+ 0x391, 0x313, 0x301, 0x345 /* offset 1862 */ ,
+ 0x391, 0x314, 0x301, 0x345 /* offset 1866 */ ,
+ 0x391, 0x313, 0x342, 0x345 /* offset 1870 */ ,
+ 0x391, 0x314, 0x342, 0x345 /* offset 1874 */ ,
+ 0x3b7, 0x313, 0x345 /* offset 1878 */ ,
+ 0x3b7, 0x314, 0x345 /* offset 1881 */ ,
+ 0x3b7, 0x313, 0x300, 0x345 /* offset 1884 */ ,
+ 0x3b7, 0x314, 0x300, 0x345 /* offset 1888 */ ,
+ 0x3b7, 0x313, 0x301, 0x345 /* offset 1892 */ ,
+ 0x3b7, 0x314, 0x301, 0x345 /* offset 1896 */ ,
+ 0x3b7, 0x313, 0x342, 0x345 /* offset 1900 */ ,
+ 0x3b7, 0x314, 0x342, 0x345 /* offset 1904 */ ,
+ 0x397, 0x313, 0x345 /* offset 1908 */ ,
+ 0x397, 0x314, 0x345 /* offset 1911 */ ,
+ 0x397, 0x313, 0x300, 0x345 /* offset 1914 */ ,
+ 0x397, 0x314, 0x300, 0x345 /* offset 1918 */ ,
+ 0x397, 0x313, 0x301, 0x345 /* offset 1922 */ ,
+ 0x397, 0x314, 0x301, 0x345 /* offset 1926 */ ,
+ 0x397, 0x313, 0x342, 0x345 /* offset 1930 */ ,
+ 0x397, 0x314, 0x342, 0x345 /* offset 1934 */ ,
+ 0x3c9, 0x313, 0x345 /* offset 1938 */ ,
+ 0x3c9, 0x314, 0x345 /* offset 1941 */ ,
+ 0x3c9, 0x313, 0x300, 0x345 /* offset 1944 */ ,
+ 0x3c9, 0x314, 0x300, 0x345 /* offset 1948 */ ,
+ 0x3c9, 0x313, 0x301, 0x345 /* offset 1952 */ ,
+ 0x3c9, 0x314, 0x301, 0x345 /* offset 1956 */ ,
+ 0x3c9, 0x313, 0x342, 0x345 /* offset 1960 */ ,
+ 0x3c9, 0x314, 0x342, 0x345 /* offset 1964 */ ,
+ 0x3a9, 0x313, 0x345 /* offset 1968 */ ,
+ 0x3a9, 0x314, 0x345 /* offset 1971 */ ,
+ 0x3a9, 0x313, 0x300, 0x345 /* offset 1974 */ ,
+ 0x3a9, 0x314, 0x300, 0x345 /* offset 1978 */ ,
+ 0x3a9, 0x313, 0x301, 0x345 /* offset 1982 */ ,
+ 0x3a9, 0x314, 0x301, 0x345 /* offset 1986 */ ,
+ 0x3a9, 0x313, 0x342, 0x345 /* offset 1990 */ ,
+ 0x3a9, 0x314, 0x342, 0x345 /* offset 1994 */ ,
+ 0x3b1, 0x306 /* offset 1998 */ ,
+ 0x3b1, 0x304 /* offset 2000 */ ,
+ 0x3b1, 0x300, 0x345 /* offset 2002 */ ,
+ 0x3b1, 0x345 /* offset 2005 */ ,
+ 0x3b1, 0x301, 0x345 /* offset 2007 */ ,
+ 0x3b1, 0x342 /* offset 2010 */ ,
+ 0x3b1, 0x342, 0x345 /* offset 2012 */ ,
+ 0x391, 0x306 /* offset 2015 */ ,
+ 0x391, 0x304 /* offset 2017 */ ,
+ 0x391, 0x300 /* offset 2019 */ ,
+ 0x391, 0x345 /* offset 2021 */ ,
+ 0x20, 0x313 /* offset 2023 */ ,
+ 0x3b9 /* offset 2025 */ ,
+ 0x20, 0x342 /* offset 2026 */ ,
+ 0x20, 0x308, 0x342 /* offset 2028 */ ,
+ 0x3b7, 0x300, 0x345 /* offset 2031 */ ,
+ 0x3b7, 0x345 /* offset 2034 */ ,
+ 0x3b7, 0x301, 0x345 /* offset 2036 */ ,
+ 0x3b7, 0x342 /* offset 2039 */ ,
+ 0x3b7, 0x342, 0x345 /* offset 2041 */ ,
+ 0x395, 0x300 /* offset 2044 */ ,
+ 0x397, 0x300 /* offset 2046 */ ,
+ 0x397, 0x345 /* offset 2048 */ ,
+ 0x20, 0x313, 0x300 /* offset 2050 */ ,
+ 0x20, 0x313, 0x301 /* offset 2053 */ ,
+ 0x20, 0x313, 0x342 /* offset 2056 */ ,
+ 0x3b9, 0x306 /* offset 2059 */ ,
+ 0x3b9, 0x304 /* offset 2061 */ ,
+ 0x3b9, 0x308, 0x300 /* offset 2063 */ ,
+ 0x3b9, 0x342 /* offset 2066 */ ,
+ 0x3b9, 0x308, 0x342 /* offset 2068 */ ,
+ 0x399, 0x306 /* offset 2071 */ ,
+ 0x399, 0x304 /* offset 2073 */ ,
+ 0x399, 0x300 /* offset 2075 */ ,
+ 0x20, 0x314, 0x300 /* offset 2077 */ ,
+ 0x20, 0x314, 0x301 /* offset 2080 */ ,
+ 0x20, 0x314, 0x342 /* offset 2083 */ ,
+ 0x3c5, 0x306 /* offset 2086 */ ,
+ 0x3c5, 0x304 /* offset 2088 */ ,
+ 0x3c5, 0x308, 0x300 /* offset 2090 */ ,
+ 0x3c1, 0x313 /* offset 2093 */ ,
+ 0x3c1, 0x314 /* offset 2095 */ ,
+ 0x3c5, 0x342 /* offset 2097 */ ,
+ 0x3c5, 0x308, 0x342 /* offset 2099 */ ,
+ 0x3a5, 0x306 /* offset 2102 */ ,
+ 0x3a5, 0x304 /* offset 2104 */ ,
+ 0x3a5, 0x300 /* offset 2106 */ ,
+ 0x3a1, 0x314 /* offset 2108 */ ,
+ 0x20, 0x308, 0x300 /* offset 2110 */ ,
+ 0x60 /* offset 2113 */ ,
+ 0x3c9, 0x300, 0x345 /* offset 2114 */ ,
+ 0x3c9, 0x345 /* offset 2117 */ ,
+ 0x3c9, 0x301, 0x345 /* offset 2119 */ ,
+ 0x3c9, 0x342 /* offset 2122 */ ,
+ 0x3c9, 0x342, 0x345 /* offset 2124 */ ,
+ 0x39f, 0x300 /* offset 2127 */ ,
+ 0x3a9, 0x300 /* offset 2129 */ ,
+ 0x3a9, 0x345 /* offset 2131 */ ,
+ 0x20, 0x314 /* offset 2133 */ ,
+ 0x2010 /* offset 2135 */ ,
+ 0x20, 0x333 /* offset 2136 */ ,
+ 0x2e /* offset 2138 */ ,
+ 0x2e, 0x2e /* offset 2139 */ ,
+ 0x2e, 0x2e, 0x2e /* offset 2141 */ ,
+ 0x2032, 0x2032 /* offset 2144 */ ,
+ 0x2032, 0x2032, 0x2032 /* offset 2146 */ ,
+ 0x2035, 0x2035 /* offset 2149 */ ,
+ 0x2035, 0x2035, 0x2035 /* offset 2151 */ ,
+ 0x21, 0x21 /* offset 2154 */ ,
+ 0x20, 0x305 /* offset 2156 */ ,
+ 0x3f, 0x3f /* offset 2158 */ ,
+ 0x3f, 0x21 /* offset 2160 */ ,
+ 0x21, 0x3f /* offset 2162 */ ,
+ 0x2032, 0x2032, 0x2032, 0x2032 /* offset 2164 */ ,
+ 0x30 /* offset 2168 */ ,
+ 0x69 /* offset 2169 */ ,
+ 0x34 /* offset 2170 */ ,
+ 0x35 /* offset 2171 */ ,
+ 0x36 /* offset 2172 */ ,
+ 0x37 /* offset 2173 */ ,
+ 0x38 /* offset 2174 */ ,
+ 0x39 /* offset 2175 */ ,
+ 0x2b /* offset 2176 */ ,
+ 0x2212 /* offset 2177 */ ,
+ 0x3d /* offset 2178 */ ,
+ 0x28 /* offset 2179 */ ,
+ 0x29 /* offset 2180 */ ,
+ 0x6e /* offset 2181 */ ,
+ 0x52, 0x73 /* offset 2182 */ ,
+ 0x61, 0x2f, 0x63 /* offset 2184 */ ,
+ 0x61, 0x2f, 0x73 /* offset 2187 */ ,
+ 0x43 /* offset 2190 */ ,
+ 0xb0, 0x43 /* offset 2191 */ ,
+ 0x63, 0x2f, 0x6f /* offset 2193 */ ,
+ 0x63, 0x2f, 0x75 /* offset 2196 */ ,
+ 0x190 /* offset 2199 */ ,
+ 0xb0, 0x46 /* offset 2200 */ ,
+ 0x67 /* offset 2202 */ ,
+ 0x48 /* offset 2203 */ ,
+ 0x127 /* offset 2204 */ ,
+ 0x49 /* offset 2205 */ ,
+ 0x4c /* offset 2206 */ ,
+ 0x4e /* offset 2207 */ ,
+ 0x4e, 0x6f /* offset 2208 */ ,
+ 0x50 /* offset 2210 */ ,
+ 0x51 /* offset 2211 */ ,
+ 0x52 /* offset 2212 */ ,
+ 0x53, 0x4d /* offset 2213 */ ,
+ 0x54, 0x45, 0x4c /* offset 2215 */ ,
+ 0x54, 0x4d /* offset 2218 */ ,
+ 0x5a /* offset 2220 */ ,
+ 0x3a9 /* offset 2221 */ ,
+ 0x4b /* offset 2222 */ ,
+ 0x42 /* offset 2223 */ ,
+ 0x65 /* offset 2224 */ ,
+ 0x45 /* offset 2225 */ ,
+ 0x46 /* offset 2226 */ ,
+ 0x4d /* offset 2227 */ ,
+ 0x5d0 /* offset 2228 */ ,
+ 0x5d1 /* offset 2229 */ ,
+ 0x5d2 /* offset 2230 */ ,
+ 0x5d3 /* offset 2231 */ ,
+ 0x3b3 /* offset 2232 */ ,
+ 0x393 /* offset 2233 */ ,
+ 0x3a0 /* offset 2234 */ ,
+ 0x2211 /* offset 2235 */ ,
+ 0x44 /* offset 2236 */ ,
+ 0x64 /* offset 2237 */ ,
+ 0x31, 0x2044, 0x33 /* offset 2238 */ ,
+ 0x32, 0x2044, 0x33 /* offset 2241 */ ,
+ 0x31, 0x2044, 0x35 /* offset 2244 */ ,
+ 0x32, 0x2044, 0x35 /* offset 2247 */ ,
+ 0x33, 0x2044, 0x35 /* offset 2250 */ ,
+ 0x34, 0x2044, 0x35 /* offset 2253 */ ,
+ 0x31, 0x2044, 0x36 /* offset 2256 */ ,
+ 0x35, 0x2044, 0x36 /* offset 2259 */ ,
+ 0x31, 0x2044, 0x38 /* offset 2262 */ ,
+ 0x33, 0x2044, 0x38 /* offset 2265 */ ,
+ 0x35, 0x2044, 0x38 /* offset 2268 */ ,
+ 0x37, 0x2044, 0x38 /* offset 2271 */ ,
+ 0x31, 0x2044 /* offset 2274 */ ,
+ 0x49, 0x49 /* offset 2276 */ ,
+ 0x49, 0x49, 0x49 /* offset 2278 */ ,
+ 0x49, 0x56 /* offset 2281 */ ,
+ 0x56 /* offset 2283 */ ,
+ 0x56, 0x49 /* offset 2284 */ ,
+ 0x56, 0x49, 0x49 /* offset 2286 */ ,
+ 0x56, 0x49, 0x49, 0x49 /* offset 2289 */ ,
+ 0x49, 0x58 /* offset 2293 */ ,
+ 0x58 /* offset 2295 */ ,
+ 0x58, 0x49 /* offset 2296 */ ,
+ 0x58, 0x49, 0x49 /* offset 2298 */ ,
+ 0x69, 0x69 /* offset 2301 */ ,
+ 0x69, 0x69, 0x69 /* offset 2303 */ ,
+ 0x69, 0x76 /* offset 2306 */ ,
+ 0x76 /* offset 2308 */ ,
+ 0x76, 0x69 /* offset 2309 */ ,
+ 0x76, 0x69, 0x69 /* offset 2311 */ ,
+ 0x76, 0x69, 0x69, 0x69 /* offset 2314 */ ,
+ 0x69, 0x78 /* offset 2318 */ ,
+ 0x78, 0x69 /* offset 2320 */ ,
+ 0x78, 0x69, 0x69 /* offset 2322 */ ,
+ 0x63 /* offset 2325 */ ,
+ 0x6d /* offset 2326 */ ,
+ 0x2190, 0x338 /* offset 2327 */ ,
+ 0x2192, 0x338 /* offset 2329 */ ,
+ 0x2194, 0x338 /* offset 2331 */ ,
+ 0x21d0, 0x338 /* offset 2333 */ ,
+ 0x21d4, 0x338 /* offset 2335 */ ,
+ 0x21d2, 0x338 /* offset 2337 */ ,
+ 0x2203, 0x338 /* offset 2339 */ ,
+ 0x2208, 0x338 /* offset 2341 */ ,
+ 0x220b, 0x338 /* offset 2343 */ ,
+ 0x2223, 0x338 /* offset 2345 */ ,
+ 0x2225, 0x338 /* offset 2347 */ ,
+ 0x222b, 0x222b /* offset 2349 */ ,
+ 0x222b, 0x222b, 0x222b /* offset 2351 */ ,
+ 0x222e, 0x222e /* offset 2354 */ ,
+ 0x222e, 0x222e, 0x222e /* offset 2356 */ ,
+ 0x223c, 0x338 /* offset 2359 */ ,
+ 0x2243, 0x338 /* offset 2361 */ ,
+ 0x2245, 0x338 /* offset 2363 */ ,
+ 0x2248, 0x338 /* offset 2365 */ ,
+ 0x3d, 0x338 /* offset 2367 */ ,
+ 0x2261, 0x338 /* offset 2369 */ ,
+ 0x224d, 0x338 /* offset 2371 */ ,
+ 0x3c, 0x338 /* offset 2373 */ ,
+ 0x3e, 0x338 /* offset 2375 */ ,
+ 0x2264, 0x338 /* offset 2377 */ ,
+ 0x2265, 0x338 /* offset 2379 */ ,
+ 0x2272, 0x338 /* offset 2381 */ ,
+ 0x2273, 0x338 /* offset 2383 */ ,
+ 0x2276, 0x338 /* offset 2385 */ ,
+ 0x2277, 0x338 /* offset 2387 */ ,
+ 0x227a, 0x338 /* offset 2389 */ ,
+ 0x227b, 0x338 /* offset 2391 */ ,
+ 0x2282, 0x338 /* offset 2393 */ ,
+ 0x2283, 0x338 /* offset 2395 */ ,
+ 0x2286, 0x338 /* offset 2397 */ ,
+ 0x2287, 0x338 /* offset 2399 */ ,
+ 0x22a2, 0x338 /* offset 2401 */ ,
+ 0x22a8, 0x338 /* offset 2403 */ ,
+ 0x22a9, 0x338 /* offset 2405 */ ,
+ 0x22ab, 0x338 /* offset 2407 */ ,
+ 0x227c, 0x338 /* offset 2409 */ ,
+ 0x227d, 0x338 /* offset 2411 */ ,
+ 0x2291, 0x338 /* offset 2413 */ ,
+ 0x2292, 0x338 /* offset 2415 */ ,
+ 0x22b2, 0x338 /* offset 2417 */ ,
+ 0x22b3, 0x338 /* offset 2419 */ ,
+ 0x22b4, 0x338 /* offset 2421 */ ,
+ 0x22b5, 0x338 /* offset 2423 */ ,
+ 0x3008 /* offset 2425 */ ,
+ 0x3009 /* offset 2426 */ ,
+ 0x31, 0x30 /* offset 2427 */ ,
+ 0x31, 0x31 /* offset 2429 */ ,
+ 0x31, 0x32 /* offset 2431 */ ,
+ 0x31, 0x33 /* offset 2433 */ ,
+ 0x31, 0x34 /* offset 2435 */ ,
+ 0x31, 0x35 /* offset 2437 */ ,
+ 0x31, 0x36 /* offset 2439 */ ,
+ 0x31, 0x37 /* offset 2441 */ ,
+ 0x31, 0x38 /* offset 2443 */ ,
+ 0x31, 0x39 /* offset 2445 */ ,
+ 0x32, 0x30 /* offset 2447 */ ,
+ 0x28, 0x31, 0x29 /* offset 2449 */ ,
+ 0x28, 0x32, 0x29 /* offset 2452 */ ,
+ 0x28, 0x33, 0x29 /* offset 2455 */ ,
+ 0x28, 0x34, 0x29 /* offset 2458 */ ,
+ 0x28, 0x35, 0x29 /* offset 2461 */ ,
+ 0x28, 0x36, 0x29 /* offset 2464 */ ,
+ 0x28, 0x37, 0x29 /* offset 2467 */ ,
+ 0x28, 0x38, 0x29 /* offset 2470 */ ,
+ 0x28, 0x39, 0x29 /* offset 2473 */ ,
+ 0x28, 0x31, 0x30, 0x29 /* offset 2476 */ ,
+ 0x28, 0x31, 0x31, 0x29 /* offset 2480 */ ,
+ 0x28, 0x31, 0x32, 0x29 /* offset 2484 */ ,
+ 0x28, 0x31, 0x33, 0x29 /* offset 2488 */ ,
+ 0x28, 0x31, 0x34, 0x29 /* offset 2492 */ ,
+ 0x28, 0x31, 0x35, 0x29 /* offset 2496 */ ,
+ 0x28, 0x31, 0x36, 0x29 /* offset 2500 */ ,
+ 0x28, 0x31, 0x37, 0x29 /* offset 2504 */ ,
+ 0x28, 0x31, 0x38, 0x29 /* offset 2508 */ ,
+ 0x28, 0x31, 0x39, 0x29 /* offset 2512 */ ,
+ 0x28, 0x32, 0x30, 0x29 /* offset 2516 */ ,
+ 0x31, 0x2e /* offset 2520 */ ,
+ 0x32, 0x2e /* offset 2522 */ ,
+ 0x33, 0x2e /* offset 2524 */ ,
+ 0x34, 0x2e /* offset 2526 */ ,
+ 0x35, 0x2e /* offset 2528 */ ,
+ 0x36, 0x2e /* offset 2530 */ ,
+ 0x37, 0x2e /* offset 2532 */ ,
+ 0x38, 0x2e /* offset 2534 */ ,
+ 0x39, 0x2e /* offset 2536 */ ,
+ 0x31, 0x30, 0x2e /* offset 2538 */ ,
+ 0x31, 0x31, 0x2e /* offset 2541 */ ,
+ 0x31, 0x32, 0x2e /* offset 2544 */ ,
+ 0x31, 0x33, 0x2e /* offset 2547 */ ,
+ 0x31, 0x34, 0x2e /* offset 2550 */ ,
+ 0x31, 0x35, 0x2e /* offset 2553 */ ,
+ 0x31, 0x36, 0x2e /* offset 2556 */ ,
+ 0x31, 0x37, 0x2e /* offset 2559 */ ,
+ 0x31, 0x38, 0x2e /* offset 2562 */ ,
+ 0x31, 0x39, 0x2e /* offset 2565 */ ,
+ 0x32, 0x30, 0x2e /* offset 2568 */ ,
+ 0x28, 0x61, 0x29 /* offset 2571 */ ,
+ 0x28, 0x62, 0x29 /* offset 2574 */ ,
+ 0x28, 0x63, 0x29 /* offset 2577 */ ,
+ 0x28, 0x64, 0x29 /* offset 2580 */ ,
+ 0x28, 0x65, 0x29 /* offset 2583 */ ,
+ 0x28, 0x66, 0x29 /* offset 2586 */ ,
+ 0x28, 0x67, 0x29 /* offset 2589 */ ,
+ 0x28, 0x68, 0x29 /* offset 2592 */ ,
+ 0x28, 0x69, 0x29 /* offset 2595 */ ,
+ 0x28, 0x6a, 0x29 /* offset 2598 */ ,
+ 0x28, 0x6b, 0x29 /* offset 2601 */ ,
+ 0x28, 0x6c, 0x29 /* offset 2604 */ ,
+ 0x28, 0x6d, 0x29 /* offset 2607 */ ,
+ 0x28, 0x6e, 0x29 /* offset 2610 */ ,
+ 0x28, 0x6f, 0x29 /* offset 2613 */ ,
+ 0x28, 0x70, 0x29 /* offset 2616 */ ,
+ 0x28, 0x71, 0x29 /* offset 2619 */ ,
+ 0x28, 0x72, 0x29 /* offset 2622 */ ,
+ 0x28, 0x73, 0x29 /* offset 2625 */ ,
+ 0x28, 0x74, 0x29 /* offset 2628 */ ,
+ 0x28, 0x75, 0x29 /* offset 2631 */ ,
+ 0x28, 0x76, 0x29 /* offset 2634 */ ,
+ 0x28, 0x77, 0x29 /* offset 2637 */ ,
+ 0x28, 0x78, 0x29 /* offset 2640 */ ,
+ 0x28, 0x79, 0x29 /* offset 2643 */ ,
+ 0x28, 0x7a, 0x29 /* offset 2646 */ ,
+ 0x41 /* offset 2649 */ ,
+ 0x47 /* offset 2650 */ ,
+ 0x4a /* offset 2651 */ ,
+ 0x4f /* offset 2652 */ ,
+ 0x53 /* offset 2653 */ ,
+ 0x54 /* offset 2654 */ ,
+ 0x55 /* offset 2655 */ ,
+ 0x57 /* offset 2656 */ ,
+ 0x59 /* offset 2657 */ ,
+ 0x62 /* offset 2658 */ ,
+ 0x66 /* offset 2659 */ ,
+ 0x6b /* offset 2660 */ ,
+ 0x70 /* offset 2661 */ ,
+ 0x71 /* offset 2662 */ ,
+ 0x74 /* offset 2663 */ ,
+ 0x75 /* offset 2664 */ ,
+ 0x7a /* offset 2665 */ ,
+ 0x222b, 0x222b, 0x222b, 0x222b /* offset 2666 */ ,
+ 0x3a, 0x3a, 0x3d /* offset 2670 */ ,
+ 0x3d, 0x3d /* offset 2673 */ ,
+ 0x3d, 0x3d, 0x3d /* offset 2675 */ ,
+ 0x2add, 0x338 /* offset 2678 */ ,
+ 0x6bcd /* offset 2680 */ ,
+ 0x9f9f /* offset 2681 */ ,
+ 0x4e00 /* offset 2682 */ ,
+ 0x4e28 /* offset 2683 */ ,
+ 0x4e36 /* offset 2684 */ ,
+ 0x4e3f /* offset 2685 */ ,
+ 0x4e59 /* offset 2686 */ ,
+ 0x4e85 /* offset 2687 */ ,
+ 0x4e8c /* offset 2688 */ ,
+ 0x4ea0 /* offset 2689 */ ,
+ 0x4eba /* offset 2690 */ ,
+ 0x513f /* offset 2691 */ ,
+ 0x5165 /* offset 2692 */ ,
+ 0x516b /* offset 2693 */ ,
+ 0x5182 /* offset 2694 */ ,
+ 0x5196 /* offset 2695 */ ,
+ 0x51ab /* offset 2696 */ ,
+ 0x51e0 /* offset 2697 */ ,
+ 0x51f5 /* offset 2698 */ ,
+ 0x5200 /* offset 2699 */ ,
+ 0x529b /* offset 2700 */ ,
+ 0x52f9 /* offset 2701 */ ,
+ 0x5315 /* offset 2702 */ ,
+ 0x531a /* offset 2703 */ ,
+ 0x5338 /* offset 2704 */ ,
+ 0x5341 /* offset 2705 */ ,
+ 0x535c /* offset 2706 */ ,
+ 0x5369 /* offset 2707 */ ,
+ 0x5382 /* offset 2708 */ ,
+ 0x53b6 /* offset 2709 */ ,
+ 0x53c8 /* offset 2710 */ ,
+ 0x53e3 /* offset 2711 */ ,
+ 0x56d7 /* offset 2712 */ ,
+ 0x571f /* offset 2713 */ ,
+ 0x58eb /* offset 2714 */ ,
+ 0x5902 /* offset 2715 */ ,
+ 0x590a /* offset 2716 */ ,
+ 0x5915 /* offset 2717 */ ,
+ 0x5927 /* offset 2718 */ ,
+ 0x5973 /* offset 2719 */ ,
+ 0x5b50 /* offset 2720 */ ,
+ 0x5b80 /* offset 2721 */ ,
+ 0x5bf8 /* offset 2722 */ ,
+ 0x5c0f /* offset 2723 */ ,
+ 0x5c22 /* offset 2724 */ ,
+ 0x5c38 /* offset 2725 */ ,
+ 0x5c6e /* offset 2726 */ ,
+ 0x5c71 /* offset 2727 */ ,
+ 0x5ddb /* offset 2728 */ ,
+ 0x5de5 /* offset 2729 */ ,
+ 0x5df1 /* offset 2730 */ ,
+ 0x5dfe /* offset 2731 */ ,
+ 0x5e72 /* offset 2732 */ ,
+ 0x5e7a /* offset 2733 */ ,
+ 0x5e7f /* offset 2734 */ ,
+ 0x5ef4 /* offset 2735 */ ,
+ 0x5efe /* offset 2736 */ ,
+ 0x5f0b /* offset 2737 */ ,
+ 0x5f13 /* offset 2738 */ ,
+ 0x5f50 /* offset 2739 */ ,
+ 0x5f61 /* offset 2740 */ ,
+ 0x5f73 /* offset 2741 */ ,
+ 0x5fc3 /* offset 2742 */ ,
+ 0x6208 /* offset 2743 */ ,
+ 0x6236 /* offset 2744 */ ,
+ 0x624b /* offset 2745 */ ,
+ 0x652f /* offset 2746 */ ,
+ 0x6534 /* offset 2747 */ ,
+ 0x6587 /* offset 2748 */ ,
+ 0x6597 /* offset 2749 */ ,
+ 0x65a4 /* offset 2750 */ ,
+ 0x65b9 /* offset 2751 */ ,
+ 0x65e0 /* offset 2752 */ ,
+ 0x65e5 /* offset 2753 */ ,
+ 0x66f0 /* offset 2754 */ ,
+ 0x6708 /* offset 2755 */ ,
+ 0x6728 /* offset 2756 */ ,
+ 0x6b20 /* offset 2757 */ ,
+ 0x6b62 /* offset 2758 */ ,
+ 0x6b79 /* offset 2759 */ ,
+ 0x6bb3 /* offset 2760 */ ,
+ 0x6bcb /* offset 2761 */ ,
+ 0x6bd4 /* offset 2762 */ ,
+ 0x6bdb /* offset 2763 */ ,
+ 0x6c0f /* offset 2764 */ ,
+ 0x6c14 /* offset 2765 */ ,
+ 0x6c34 /* offset 2766 */ ,
+ 0x706b /* offset 2767 */ ,
+ 0x722a /* offset 2768 */ ,
+ 0x7236 /* offset 2769 */ ,
+ 0x723b /* offset 2770 */ ,
+ 0x723f /* offset 2771 */ ,
+ 0x7247 /* offset 2772 */ ,
+ 0x7259 /* offset 2773 */ ,
+ 0x725b /* offset 2774 */ ,
+ 0x72ac /* offset 2775 */ ,
+ 0x7384 /* offset 2776 */ ,
+ 0x7389 /* offset 2777 */ ,
+ 0x74dc /* offset 2778 */ ,
+ 0x74e6 /* offset 2779 */ ,
+ 0x7518 /* offset 2780 */ ,
+ 0x751f /* offset 2781 */ ,
+ 0x7528 /* offset 2782 */ ,
+ 0x7530 /* offset 2783 */ ,
+ 0x758b /* offset 2784 */ ,
+ 0x7592 /* offset 2785 */ ,
+ 0x7676 /* offset 2786 */ ,
+ 0x767d /* offset 2787 */ ,
+ 0x76ae /* offset 2788 */ ,
+ 0x76bf /* offset 2789 */ ,
+ 0x76ee /* offset 2790 */ ,
+ 0x77db /* offset 2791 */ ,
+ 0x77e2 /* offset 2792 */ ,
+ 0x77f3 /* offset 2793 */ ,
+ 0x793a /* offset 2794 */ ,
+ 0x79b8 /* offset 2795 */ ,
+ 0x79be /* offset 2796 */ ,
+ 0x7a74 /* offset 2797 */ ,
+ 0x7acb /* offset 2798 */ ,
+ 0x7af9 /* offset 2799 */ ,
+ 0x7c73 /* offset 2800 */ ,
+ 0x7cf8 /* offset 2801 */ ,
+ 0x7f36 /* offset 2802 */ ,
+ 0x7f51 /* offset 2803 */ ,
+ 0x7f8a /* offset 2804 */ ,
+ 0x7fbd /* offset 2805 */ ,
+ 0x8001 /* offset 2806 */ ,
+ 0x800c /* offset 2807 */ ,
+ 0x8012 /* offset 2808 */ ,
+ 0x8033 /* offset 2809 */ ,
+ 0x807f /* offset 2810 */ ,
+ 0x8089 /* offset 2811 */ ,
+ 0x81e3 /* offset 2812 */ ,
+ 0x81ea /* offset 2813 */ ,
+ 0x81f3 /* offset 2814 */ ,
+ 0x81fc /* offset 2815 */ ,
+ 0x820c /* offset 2816 */ ,
+ 0x821b /* offset 2817 */ ,
+ 0x821f /* offset 2818 */ ,
+ 0x826e /* offset 2819 */ ,
+ 0x8272 /* offset 2820 */ ,
+ 0x8278 /* offset 2821 */ ,
+ 0x864d /* offset 2822 */ ,
+ 0x866b /* offset 2823 */ ,
+ 0x8840 /* offset 2824 */ ,
+ 0x884c /* offset 2825 */ ,
+ 0x8863 /* offset 2826 */ ,
+ 0x897e /* offset 2827 */ ,
+ 0x898b /* offset 2828 */ ,
+ 0x89d2 /* offset 2829 */ ,
+ 0x8a00 /* offset 2830 */ ,
+ 0x8c37 /* offset 2831 */ ,
+ 0x8c46 /* offset 2832 */ ,
+ 0x8c55 /* offset 2833 */ ,
+ 0x8c78 /* offset 2834 */ ,
+ 0x8c9d /* offset 2835 */ ,
+ 0x8d64 /* offset 2836 */ ,
+ 0x8d70 /* offset 2837 */ ,
+ 0x8db3 /* offset 2838 */ ,
+ 0x8eab /* offset 2839 */ ,
+ 0x8eca /* offset 2840 */ ,
+ 0x8f9b /* offset 2841 */ ,
+ 0x8fb0 /* offset 2842 */ ,
+ 0x8fb5 /* offset 2843 */ ,
+ 0x9091 /* offset 2844 */ ,
+ 0x9149 /* offset 2845 */ ,
+ 0x91c6 /* offset 2846 */ ,
+ 0x91cc /* offset 2847 */ ,
+ 0x91d1 /* offset 2848 */ ,
+ 0x9577 /* offset 2849 */ ,
+ 0x9580 /* offset 2850 */ ,
+ 0x961c /* offset 2851 */ ,
+ 0x96b6 /* offset 2852 */ ,
+ 0x96b9 /* offset 2853 */ ,
+ 0x96e8 /* offset 2854 */ ,
+ 0x9751 /* offset 2855 */ ,
+ 0x975e /* offset 2856 */ ,
+ 0x9762 /* offset 2857 */ ,
+ 0x9769 /* offset 2858 */ ,
+ 0x97cb /* offset 2859 */ ,
+ 0x97ed /* offset 2860 */ ,
+ 0x97f3 /* offset 2861 */ ,
+ 0x9801 /* offset 2862 */ ,
+ 0x98a8 /* offset 2863 */ ,
+ 0x98db /* offset 2864 */ ,
+ 0x98df /* offset 2865 */ ,
+ 0x9996 /* offset 2866 */ ,
+ 0x9999 /* offset 2867 */ ,
+ 0x99ac /* offset 2868 */ ,
+ 0x9aa8 /* offset 2869 */ ,
+ 0x9ad8 /* offset 2870 */ ,
+ 0x9adf /* offset 2871 */ ,
+ 0x9b25 /* offset 2872 */ ,
+ 0x9b2f /* offset 2873 */ ,
+ 0x9b32 /* offset 2874 */ ,
+ 0x9b3c /* offset 2875 */ ,
+ 0x9b5a /* offset 2876 */ ,
+ 0x9ce5 /* offset 2877 */ ,
+ 0x9e75 /* offset 2878 */ ,
+ 0x9e7f /* offset 2879 */ ,
+ 0x9ea5 /* offset 2880 */ ,
+ 0x9ebb /* offset 2881 */ ,
+ 0x9ec3 /* offset 2882 */ ,
+ 0x9ecd /* offset 2883 */ ,
+ 0x9ed1 /* offset 2884 */ ,
+ 0x9ef9 /* offset 2885 */ ,
+ 0x9efd /* offset 2886 */ ,
+ 0x9f0e /* offset 2887 */ ,
+ 0x9f13 /* offset 2888 */ ,
+ 0x9f20 /* offset 2889 */ ,
+ 0x9f3b /* offset 2890 */ ,
+ 0x9f4a /* offset 2891 */ ,
+ 0x9f52 /* offset 2892 */ ,
+ 0x9f8d /* offset 2893 */ ,
+ 0x9f9c /* offset 2894 */ ,
+ 0x9fa0 /* offset 2895 */ ,
+ 0x3012 /* offset 2896 */ ,
+ 0x5344 /* offset 2897 */ ,
+ 0x5345 /* offset 2898 */ ,
+ 0x304b, 0x3099 /* offset 2899 */ ,
+ 0x304d, 0x3099 /* offset 2901 */ ,
+ 0x304f, 0x3099 /* offset 2903 */ ,
+ 0x3051, 0x3099 /* offset 2905 */ ,
+ 0x3053, 0x3099 /* offset 2907 */ ,
+ 0x3055, 0x3099 /* offset 2909 */ ,
+ 0x3057, 0x3099 /* offset 2911 */ ,
+ 0x3059, 0x3099 /* offset 2913 */ ,
+ 0x305b, 0x3099 /* offset 2915 */ ,
+ 0x305d, 0x3099 /* offset 2917 */ ,
+ 0x305f, 0x3099 /* offset 2919 */ ,
+ 0x3061, 0x3099 /* offset 2921 */ ,
+ 0x3064, 0x3099 /* offset 2923 */ ,
+ 0x3066, 0x3099 /* offset 2925 */ ,
+ 0x3068, 0x3099 /* offset 2927 */ ,
+ 0x306f, 0x3099 /* offset 2929 */ ,
+ 0x306f, 0x309a /* offset 2931 */ ,
+ 0x3072, 0x3099 /* offset 2933 */ ,
+ 0x3072, 0x309a /* offset 2935 */ ,
+ 0x3075, 0x3099 /* offset 2937 */ ,
+ 0x3075, 0x309a /* offset 2939 */ ,
+ 0x3078, 0x3099 /* offset 2941 */ ,
+ 0x3078, 0x309a /* offset 2943 */ ,
+ 0x307b, 0x3099 /* offset 2945 */ ,
+ 0x307b, 0x309a /* offset 2947 */ ,
+ 0x3046, 0x3099 /* offset 2949 */ ,
+ 0x20, 0x3099 /* offset 2951 */ ,
+ 0x20, 0x309a /* offset 2953 */ ,
+ 0x309d, 0x3099 /* offset 2955 */ ,
+ 0x3088, 0x308a /* offset 2957 */ ,
+ 0x30ab, 0x3099 /* offset 2959 */ ,
+ 0x30ad, 0x3099 /* offset 2961 */ ,
+ 0x30af, 0x3099 /* offset 2963 */ ,
+ 0x30b1, 0x3099 /* offset 2965 */ ,
+ 0x30b3, 0x3099 /* offset 2967 */ ,
+ 0x30b5, 0x3099 /* offset 2969 */ ,
+ 0x30b7, 0x3099 /* offset 2971 */ ,
+ 0x30b9, 0x3099 /* offset 2973 */ ,
+ 0x30bb, 0x3099 /* offset 2975 */ ,
+ 0x30bd, 0x3099 /* offset 2977 */ ,
+ 0x30bf, 0x3099 /* offset 2979 */ ,
+ 0x30c1, 0x3099 /* offset 2981 */ ,
+ 0x30c4, 0x3099 /* offset 2983 */ ,
+ 0x30c6, 0x3099 /* offset 2985 */ ,
+ 0x30c8, 0x3099 /* offset 2987 */ ,
+ 0x30cf, 0x3099 /* offset 2989 */ ,
+ 0x30cf, 0x309a /* offset 2991 */ ,
+ 0x30d2, 0x3099 /* offset 2993 */ ,
+ 0x30d2, 0x309a /* offset 2995 */ ,
+ 0x30d5, 0x3099 /* offset 2997 */ ,
+ 0x30d5, 0x309a /* offset 2999 */ ,
+ 0x30d8, 0x3099 /* offset 3001 */ ,
+ 0x30d8, 0x309a /* offset 3003 */ ,
+ 0x30db, 0x3099 /* offset 3005 */ ,
+ 0x30db, 0x309a /* offset 3007 */ ,
+ 0x30a6, 0x3099 /* offset 3009 */ ,
+ 0x30ef, 0x3099 /* offset 3011 */ ,
+ 0x30f0, 0x3099 /* offset 3013 */ ,
+ 0x30f1, 0x3099 /* offset 3015 */ ,
+ 0x30f2, 0x3099 /* offset 3017 */ ,
+ 0x30fd, 0x3099 /* offset 3019 */ ,
+ 0x30b3, 0x30c8 /* offset 3021 */ ,
+ 0x1100 /* offset 3023 */ ,
+ 0x1101 /* offset 3024 */ ,
+ 0x11aa /* offset 3025 */ ,
+ 0x1102 /* offset 3026 */ ,
+ 0x11ac /* offset 3027 */ ,
+ 0x11ad /* offset 3028 */ ,
+ 0x1103 /* offset 3029 */ ,
+ 0x1104 /* offset 3030 */ ,
+ 0x1105 /* offset 3031 */ ,
+ 0x11b0 /* offset 3032 */ ,
+ 0x11b1 /* offset 3033 */ ,
+ 0x11b2 /* offset 3034 */ ,
+ 0x11b3 /* offset 3035 */ ,
+ 0x11b4 /* offset 3036 */ ,
+ 0x11b5 /* offset 3037 */ ,
+ 0x111a /* offset 3038 */ ,
+ 0x1106 /* offset 3039 */ ,
+ 0x1107 /* offset 3040 */ ,
+ 0x1108 /* offset 3041 */ ,
+ 0x1121 /* offset 3042 */ ,
+ 0x1109 /* offset 3043 */ ,
+ 0x110a /* offset 3044 */ ,
+ 0x110b /* offset 3045 */ ,
+ 0x110c /* offset 3046 */ ,
+ 0x110d /* offset 3047 */ ,
+ 0x110e /* offset 3048 */ ,
+ 0x110f /* offset 3049 */ ,
+ 0x1110 /* offset 3050 */ ,
+ 0x1111 /* offset 3051 */ ,
+ 0x1112 /* offset 3052 */ ,
+ 0x1161 /* offset 3053 */ ,
+ 0x1162 /* offset 3054 */ ,
+ 0x1163 /* offset 3055 */ ,
+ 0x1164 /* offset 3056 */ ,
+ 0x1165 /* offset 3057 */ ,
+ 0x1166 /* offset 3058 */ ,
+ 0x1167 /* offset 3059 */ ,
+ 0x1168 /* offset 3060 */ ,
+ 0x1169 /* offset 3061 */ ,
+ 0x116a /* offset 3062 */ ,
+ 0x116b /* offset 3063 */ ,
+ 0x116c /* offset 3064 */ ,
+ 0x116d /* offset 3065 */ ,
+ 0x116e /* offset 3066 */ ,
+ 0x116f /* offset 3067 */ ,
+ 0x1170 /* offset 3068 */ ,
+ 0x1171 /* offset 3069 */ ,
+ 0x1172 /* offset 3070 */ ,
+ 0x1173 /* offset 3071 */ ,
+ 0x1174 /* offset 3072 */ ,
+ 0x1175 /* offset 3073 */ ,
+ 0x1160 /* offset 3074 */ ,
+ 0x1114 /* offset 3075 */ ,
+ 0x1115 /* offset 3076 */ ,
+ 0x11c7 /* offset 3077 */ ,
+ 0x11c8 /* offset 3078 */ ,
+ 0x11cc /* offset 3079 */ ,
+ 0x11ce /* offset 3080 */ ,
+ 0x11d3 /* offset 3081 */ ,
+ 0x11d7 /* offset 3082 */ ,
+ 0x11d9 /* offset 3083 */ ,
+ 0x111c /* offset 3084 */ ,
+ 0x11dd /* offset 3085 */ ,
+ 0x11df /* offset 3086 */ ,
+ 0x111d /* offset 3087 */ ,
+ 0x111e /* offset 3088 */ ,
+ 0x1120 /* offset 3089 */ ,
+ 0x1122 /* offset 3090 */ ,
+ 0x1123 /* offset 3091 */ ,
+ 0x1127 /* offset 3092 */ ,
+ 0x1129 /* offset 3093 */ ,
+ 0x112b /* offset 3094 */ ,
+ 0x112c /* offset 3095 */ ,
+ 0x112d /* offset 3096 */ ,
+ 0x112e /* offset 3097 */ ,
+ 0x112f /* offset 3098 */ ,
+ 0x1132 /* offset 3099 */ ,
+ 0x1136 /* offset 3100 */ ,
+ 0x1140 /* offset 3101 */ ,
+ 0x1147 /* offset 3102 */ ,
+ 0x114c /* offset 3103 */ ,
+ 0x11f1 /* offset 3104 */ ,
+ 0x11f2 /* offset 3105 */ ,
+ 0x1157 /* offset 3106 */ ,
+ 0x1158 /* offset 3107 */ ,
+ 0x1159 /* offset 3108 */ ,
+ 0x1184 /* offset 3109 */ ,
+ 0x1185 /* offset 3110 */ ,
+ 0x1188 /* offset 3111 */ ,
+ 0x1191 /* offset 3112 */ ,
+ 0x1192 /* offset 3113 */ ,
+ 0x1194 /* offset 3114 */ ,
+ 0x119e /* offset 3115 */ ,
+ 0x11a1 /* offset 3116 */ ,
+ 0x4e09 /* offset 3117 */ ,
+ 0x56db /* offset 3118 */ ,
+ 0x4e0a /* offset 3119 */ ,
+ 0x4e2d /* offset 3120 */ ,
+ 0x4e0b /* offset 3121 */ ,
+ 0x7532 /* offset 3122 */ ,
+ 0x4e19 /* offset 3123 */ ,
+ 0x4e01 /* offset 3124 */ ,
+ 0x5929 /* offset 3125 */ ,
+ 0x5730 /* offset 3126 */ ,
+ 0x28, 0x1100, 0x29 /* offset 3127 */ ,
+ 0x28, 0x1102, 0x29 /* offset 3130 */ ,
+ 0x28, 0x1103, 0x29 /* offset 3133 */ ,
+ 0x28, 0x1105, 0x29 /* offset 3136 */ ,
+ 0x28, 0x1106, 0x29 /* offset 3139 */ ,
+ 0x28, 0x1107, 0x29 /* offset 3142 */ ,
+ 0x28, 0x1109, 0x29 /* offset 3145 */ ,
+ 0x28, 0x110b, 0x29 /* offset 3148 */ ,
+ 0x28, 0x110c, 0x29 /* offset 3151 */ ,
+ 0x28, 0x110e, 0x29 /* offset 3154 */ ,
+ 0x28, 0x110f, 0x29 /* offset 3157 */ ,
+ 0x28, 0x1110, 0x29 /* offset 3160 */ ,
+ 0x28, 0x1111, 0x29 /* offset 3163 */ ,
+ 0x28, 0x1112, 0x29 /* offset 3166 */ ,
+ 0x28, 0x1100, 0x1161, 0x29 /* offset 3169 */ ,
+ 0x28, 0x1102, 0x1161, 0x29 /* offset 3173 */ ,
+ 0x28, 0x1103, 0x1161, 0x29 /* offset 3177 */ ,
+ 0x28, 0x1105, 0x1161, 0x29 /* offset 3181 */ ,
+ 0x28, 0x1106, 0x1161, 0x29 /* offset 3185 */ ,
+ 0x28, 0x1107, 0x1161, 0x29 /* offset 3189 */ ,
+ 0x28, 0x1109, 0x1161, 0x29 /* offset 3193 */ ,
+ 0x28, 0x110b, 0x1161, 0x29 /* offset 3197 */ ,
+ 0x28, 0x110c, 0x1161, 0x29 /* offset 3201 */ ,
+ 0x28, 0x110e, 0x1161, 0x29 /* offset 3205 */ ,
+ 0x28, 0x110f, 0x1161, 0x29 /* offset 3209 */ ,
+ 0x28, 0x1110, 0x1161, 0x29 /* offset 3213 */ ,
+ 0x28, 0x1111, 0x1161, 0x29 /* offset 3217 */ ,
+ 0x28, 0x1112, 0x1161, 0x29 /* offset 3221 */ ,
+ 0x28, 0x110c, 0x116e, 0x29 /* offset 3225 */ ,
+ 0x28, 0x4e00, 0x29 /* offset 3229 */ ,
+ 0x28, 0x4e8c, 0x29 /* offset 3232 */ ,
+ 0x28, 0x4e09, 0x29 /* offset 3235 */ ,
+ 0x28, 0x56db, 0x29 /* offset 3238 */ ,
+ 0x28, 0x4e94, 0x29 /* offset 3241 */ ,
+ 0x28, 0x516d, 0x29 /* offset 3244 */ ,
+ 0x28, 0x4e03, 0x29 /* offset 3247 */ ,
+ 0x28, 0x516b, 0x29 /* offset 3250 */ ,
+ 0x28, 0x4e5d, 0x29 /* offset 3253 */ ,
+ 0x28, 0x5341, 0x29 /* offset 3256 */ ,
+ 0x28, 0x6708, 0x29 /* offset 3259 */ ,
+ 0x28, 0x706b, 0x29 /* offset 3262 */ ,
+ 0x28, 0x6c34, 0x29 /* offset 3265 */ ,
+ 0x28, 0x6728, 0x29 /* offset 3268 */ ,
+ 0x28, 0x91d1, 0x29 /* offset 3271 */ ,
+ 0x28, 0x571f, 0x29 /* offset 3274 */ ,
+ 0x28, 0x65e5, 0x29 /* offset 3277 */ ,
+ 0x28, 0x682a, 0x29 /* offset 3280 */ ,
+ 0x28, 0x6709, 0x29 /* offset 3283 */ ,
+ 0x28, 0x793e, 0x29 /* offset 3286 */ ,
+ 0x28, 0x540d, 0x29 /* offset 3289 */ ,
+ 0x28, 0x7279, 0x29 /* offset 3292 */ ,
+ 0x28, 0x8ca1, 0x29 /* offset 3295 */ ,
+ 0x28, 0x795d, 0x29 /* offset 3298 */ ,
+ 0x28, 0x52b4, 0x29 /* offset 3301 */ ,
+ 0x28, 0x4ee3, 0x29 /* offset 3304 */ ,
+ 0x28, 0x547c, 0x29 /* offset 3307 */ ,
+ 0x28, 0x5b66, 0x29 /* offset 3310 */ ,
+ 0x28, 0x76e3, 0x29 /* offset 3313 */ ,
+ 0x28, 0x4f01, 0x29 /* offset 3316 */ ,
+ 0x28, 0x8cc7, 0x29 /* offset 3319 */ ,
+ 0x28, 0x5354, 0x29 /* offset 3322 */ ,
+ 0x28, 0x796d, 0x29 /* offset 3325 */ ,
+ 0x28, 0x4f11, 0x29 /* offset 3328 */ ,
+ 0x28, 0x81ea, 0x29 /* offset 3331 */ ,
+ 0x28, 0x81f3, 0x29 /* offset 3334 */ ,
+ 0x32, 0x31 /* offset 3337 */ ,
+ 0x32, 0x32 /* offset 3339 */ ,
+ 0x32, 0x33 /* offset 3341 */ ,
+ 0x32, 0x34 /* offset 3343 */ ,
+ 0x32, 0x35 /* offset 3345 */ ,
+ 0x32, 0x36 /* offset 3347 */ ,
+ 0x32, 0x37 /* offset 3349 */ ,
+ 0x32, 0x38 /* offset 3351 */ ,
+ 0x32, 0x39 /* offset 3353 */ ,
+ 0x33, 0x30 /* offset 3355 */ ,
+ 0x33, 0x31 /* offset 3357 */ ,
+ 0x33, 0x32 /* offset 3359 */ ,
+ 0x33, 0x33 /* offset 3361 */ ,
+ 0x33, 0x34 /* offset 3363 */ ,
+ 0x33, 0x35 /* offset 3365 */ ,
+ 0x1100, 0x1161 /* offset 3367 */ ,
+ 0x1102, 0x1161 /* offset 3369 */ ,
+ 0x1103, 0x1161 /* offset 3371 */ ,
+ 0x1105, 0x1161 /* offset 3373 */ ,
+ 0x1106, 0x1161 /* offset 3375 */ ,
+ 0x1107, 0x1161 /* offset 3377 */ ,
+ 0x1109, 0x1161 /* offset 3379 */ ,
+ 0x110b, 0x1161 /* offset 3381 */ ,
+ 0x110c, 0x1161 /* offset 3383 */ ,
+ 0x110e, 0x1161 /* offset 3385 */ ,
+ 0x110f, 0x1161 /* offset 3387 */ ,
+ 0x1110, 0x1161 /* offset 3389 */ ,
+ 0x1111, 0x1161 /* offset 3391 */ ,
+ 0x1112, 0x1161 /* offset 3393 */ ,
+ 0x4e94 /* offset 3395 */ ,
+ 0x516d /* offset 3396 */ ,
+ 0x4e03 /* offset 3397 */ ,
+ 0x4e5d /* offset 3398 */ ,
+ 0x682a /* offset 3399 */ ,
+ 0x6709 /* offset 3400 */ ,
+ 0x793e /* offset 3401 */ ,
+ 0x540d /* offset 3402 */ ,
+ 0x7279 /* offset 3403 */ ,
+ 0x8ca1 /* offset 3404 */ ,
+ 0x795d /* offset 3405 */ ,
+ 0x52b4 /* offset 3406 */ ,
+ 0x79d8 /* offset 3407 */ ,
+ 0x7537 /* offset 3408 */ ,
+ 0x9069 /* offset 3409 */ ,
+ 0x512a /* offset 3410 */ ,
+ 0x5370 /* offset 3411 */ ,
+ 0x6ce8 /* offset 3412 */ ,
+ 0x9805 /* offset 3413 */ ,
+ 0x4f11 /* offset 3414 */ ,
+ 0x5199 /* offset 3415 */ ,
+ 0x6b63 /* offset 3416 */ ,
+ 0x5de6 /* offset 3417 */ ,
+ 0x53f3 /* offset 3418 */ ,
+ 0x533b /* offset 3419 */ ,
+ 0x5b97 /* offset 3420 */ ,
+ 0x5b66 /* offset 3421 */ ,
+ 0x76e3 /* offset 3422 */ ,
+ 0x4f01 /* offset 3423 */ ,
+ 0x8cc7 /* offset 3424 */ ,
+ 0x5354 /* offset 3425 */ ,
+ 0x591c /* offset 3426 */ ,
+ 0x33, 0x36 /* offset 3427 */ ,
+ 0x33, 0x37 /* offset 3429 */ ,
+ 0x33, 0x38 /* offset 3431 */ ,
+ 0x33, 0x39 /* offset 3433 */ ,
+ 0x34, 0x30 /* offset 3435 */ ,
+ 0x34, 0x31 /* offset 3437 */ ,
+ 0x34, 0x32 /* offset 3439 */ ,
+ 0x34, 0x33 /* offset 3441 */ ,
+ 0x34, 0x34 /* offset 3443 */ ,
+ 0x34, 0x35 /* offset 3445 */ ,
+ 0x34, 0x36 /* offset 3447 */ ,
+ 0x34, 0x37 /* offset 3449 */ ,
+ 0x34, 0x38 /* offset 3451 */ ,
+ 0x34, 0x39 /* offset 3453 */ ,
+ 0x35, 0x30 /* offset 3455 */ ,
+ 0x31, 0x6708 /* offset 3457 */ ,
+ 0x32, 0x6708 /* offset 3459 */ ,
+ 0x33, 0x6708 /* offset 3461 */ ,
+ 0x34, 0x6708 /* offset 3463 */ ,
+ 0x35, 0x6708 /* offset 3465 */ ,
+ 0x36, 0x6708 /* offset 3467 */ ,
+ 0x37, 0x6708 /* offset 3469 */ ,
+ 0x38, 0x6708 /* offset 3471 */ ,
+ 0x39, 0x6708 /* offset 3473 */ ,
+ 0x31, 0x30, 0x6708 /* offset 3475 */ ,
+ 0x31, 0x31, 0x6708 /* offset 3478 */ ,
+ 0x31, 0x32, 0x6708 /* offset 3481 */ ,
+ 0x30a2 /* offset 3484 */ ,
+ 0x30a4 /* offset 3485 */ ,
+ 0x30a6 /* offset 3486 */ ,
+ 0x30a8 /* offset 3487 */ ,
+ 0x30aa /* offset 3488 */ ,
+ 0x30ab /* offset 3489 */ ,
+ 0x30ad /* offset 3490 */ ,
+ 0x30af /* offset 3491 */ ,
+ 0x30b1 /* offset 3492 */ ,
+ 0x30b3 /* offset 3493 */ ,
+ 0x30b5 /* offset 3494 */ ,
+ 0x30b7 /* offset 3495 */ ,
+ 0x30b9 /* offset 3496 */ ,
+ 0x30bb /* offset 3497 */ ,
+ 0x30bd /* offset 3498 */ ,
+ 0x30bf /* offset 3499 */ ,
+ 0x30c1 /* offset 3500 */ ,
+ 0x30c4 /* offset 3501 */ ,
+ 0x30c6 /* offset 3502 */ ,
+ 0x30c8 /* offset 3503 */ ,
+ 0x30ca /* offset 3504 */ ,
+ 0x30cb /* offset 3505 */ ,
+ 0x30cc /* offset 3506 */ ,
+ 0x30cd /* offset 3507 */ ,
+ 0x30ce /* offset 3508 */ ,
+ 0x30cf /* offset 3509 */ ,
+ 0x30d2 /* offset 3510 */ ,
+ 0x30d5 /* offset 3511 */ ,
+ 0x30d8 /* offset 3512 */ ,
+ 0x30db /* offset 3513 */ ,
+ 0x30de /* offset 3514 */ ,
+ 0x30df /* offset 3515 */ ,
+ 0x30e0 /* offset 3516 */ ,
+ 0x30e1 /* offset 3517 */ ,
+ 0x30e2 /* offset 3518 */ ,
+ 0x30e4 /* offset 3519 */ ,
+ 0x30e6 /* offset 3520 */ ,
+ 0x30e8 /* offset 3521 */ ,
+ 0x30e9 /* offset 3522 */ ,
+ 0x30ea /* offset 3523 */ ,
+ 0x30eb /* offset 3524 */ ,
+ 0x30ec /* offset 3525 */ ,
+ 0x30ed /* offset 3526 */ ,
+ 0x30ef /* offset 3527 */ ,
+ 0x30f0 /* offset 3528 */ ,
+ 0x30f1 /* offset 3529 */ ,
+ 0x30f2 /* offset 3530 */ ,
+ 0x30a2, 0x30cf, 0x309a, 0x30fc, 0x30c8 /* offset 3531 */ ,
+ 0x30a2, 0x30eb, 0x30d5, 0x30a1 /* offset 3536 */ ,
+ 0x30a2, 0x30f3, 0x30d8, 0x309a, 0x30a2 /* offset 3540 */ ,
+ 0x30a2, 0x30fc, 0x30eb /* offset 3545 */ ,
+ 0x30a4, 0x30cb, 0x30f3, 0x30af, 0x3099 /* offset 3548 */ ,
+ 0x30a4, 0x30f3, 0x30c1 /* offset 3553 */ ,
+ 0x30a6, 0x30a9, 0x30f3 /* offset 3556 */ ,
+ 0x30a8, 0x30b9, 0x30af, 0x30fc, 0x30c8, 0x3099 /* offset 3559 */ ,
+ 0x30a8, 0x30fc, 0x30ab, 0x30fc /* offset 3565 */ ,
+ 0x30aa, 0x30f3, 0x30b9 /* offset 3569 */ ,
+ 0x30aa, 0x30fc, 0x30e0 /* offset 3572 */ ,
+ 0x30ab, 0x30a4, 0x30ea /* offset 3575 */ ,
+ 0x30ab, 0x30e9, 0x30c3, 0x30c8 /* offset 3578 */ ,
+ 0x30ab, 0x30ed, 0x30ea, 0x30fc /* offset 3582 */ ,
+ 0x30ab, 0x3099, 0x30ed, 0x30f3 /* offset 3586 */ ,
+ 0x30ab, 0x3099, 0x30f3, 0x30de /* offset 3590 */ ,
+ 0x30ad, 0x3099, 0x30ab, 0x3099 /* offset 3594 */ ,
+ 0x30ad, 0x3099, 0x30cb, 0x30fc /* offset 3598 */ ,
+ 0x30ad, 0x30e5, 0x30ea, 0x30fc /* offset 3602 */ ,
+ 0x30ad, 0x3099, 0x30eb, 0x30bf, 0x3099, 0x30fc /* offset 3606 */ ,
+ 0x30ad, 0x30ed /* offset 3612 */ ,
+ 0x30ad, 0x30ed, 0x30af, 0x3099, 0x30e9, 0x30e0 /* offset 3614 */ ,
+ 0x30ad, 0x30ed, 0x30e1, 0x30fc, 0x30c8, 0x30eb /* offset 3620 */ ,
+ 0x30ad, 0x30ed, 0x30ef, 0x30c3, 0x30c8 /* offset 3626 */ ,
+ 0x30af, 0x3099, 0x30e9, 0x30e0 /* offset 3631 */ ,
+ 0x30af, 0x3099, 0x30e9, 0x30e0, 0x30c8, 0x30f3 /* offset 3635 */ ,
+ 0x30af, 0x30eb, 0x30bb, 0x3099, 0x30a4, 0x30ed /* offset 3641 */ ,
+ 0x30af, 0x30ed, 0x30fc, 0x30cd /* offset 3647 */ ,
+ 0x30b1, 0x30fc, 0x30b9 /* offset 3651 */ ,
+ 0x30b3, 0x30eb, 0x30ca /* offset 3654 */ ,
+ 0x30b3, 0x30fc, 0x30db, 0x309a /* offset 3657 */ ,
+ 0x30b5, 0x30a4, 0x30af, 0x30eb /* offset 3661 */ ,
+ 0x30b5, 0x30f3, 0x30c1, 0x30fc, 0x30e0 /* offset 3665 */ ,
+ 0x30b7, 0x30ea, 0x30f3, 0x30af, 0x3099 /* offset 3670 */ ,
+ 0x30bb, 0x30f3, 0x30c1 /* offset 3675 */ ,
+ 0x30bb, 0x30f3, 0x30c8 /* offset 3678 */ ,
+ 0x30bf, 0x3099, 0x30fc, 0x30b9 /* offset 3681 */ ,
+ 0x30c6, 0x3099, 0x30b7 /* offset 3685 */ ,
+ 0x30c8, 0x3099, 0x30eb /* offset 3688 */ ,
+ 0x30c8, 0x30f3 /* offset 3691 */ ,
+ 0x30ca, 0x30ce /* offset 3693 */ ,
+ 0x30ce, 0x30c3, 0x30c8 /* offset 3695 */ ,
+ 0x30cf, 0x30a4, 0x30c4 /* offset 3698 */ ,
+ 0x30cf, 0x309a, 0x30fc, 0x30bb, 0x30f3, 0x30c8 /* offset 3701 */ ,
+ 0x30cf, 0x309a, 0x30fc, 0x30c4 /* offset 3707 */ ,
+ 0x30cf, 0x3099, 0x30fc, 0x30ec, 0x30eb /* offset 3711 */ ,
+ 0x30d2, 0x309a, 0x30a2, 0x30b9, 0x30c8, 0x30eb /* offset 3716 */ ,
+ 0x30d2, 0x309a, 0x30af, 0x30eb /* offset 3722 */ ,
+ 0x30d2, 0x309a, 0x30b3 /* offset 3726 */ ,
+ 0x30d2, 0x3099, 0x30eb /* offset 3729 */ ,
+ 0x30d5, 0x30a1, 0x30e9, 0x30c3, 0x30c8, 0x3099 /* offset 3732 */ ,
+ 0x30d5, 0x30a3, 0x30fc, 0x30c8 /* offset 3738 */ ,
+ 0x30d5, 0x3099, 0x30c3, 0x30b7, 0x30a7, 0x30eb /* offset 3742 */ ,
+ 0x30d5, 0x30e9, 0x30f3 /* offset 3748 */ ,
+ 0x30d8, 0x30af, 0x30bf, 0x30fc, 0x30eb /* offset 3751 */ ,
+ 0x30d8, 0x309a, 0x30bd /* offset 3756 */ ,
+ 0x30d8, 0x309a, 0x30cb, 0x30d2 /* offset 3759 */ ,
+ 0x30d8, 0x30eb, 0x30c4 /* offset 3763 */ ,
+ 0x30d8, 0x309a, 0x30f3, 0x30b9 /* offset 3766 */ ,
+ 0x30d8, 0x309a, 0x30fc, 0x30b7, 0x3099 /* offset 3770 */ ,
+ 0x30d8, 0x3099, 0x30fc, 0x30bf /* offset 3775 */ ,
+ 0x30db, 0x309a, 0x30a4, 0x30f3, 0x30c8 /* offset 3779 */ ,
+ 0x30db, 0x3099, 0x30eb, 0x30c8 /* offset 3784 */ ,
+ 0x30db, 0x30f3 /* offset 3788 */ ,
+ 0x30db, 0x309a, 0x30f3, 0x30c8, 0x3099 /* offset 3790 */ ,
+ 0x30db, 0x30fc, 0x30eb /* offset 3795 */ ,
+ 0x30db, 0x30fc, 0x30f3 /* offset 3798 */ ,
+ 0x30de, 0x30a4, 0x30af, 0x30ed /* offset 3801 */ ,
+ 0x30de, 0x30a4, 0x30eb /* offset 3805 */ ,
+ 0x30de, 0x30c3, 0x30cf /* offset 3808 */ ,
+ 0x30de, 0x30eb, 0x30af /* offset 3811 */ ,
+ 0x30de, 0x30f3, 0x30b7, 0x30e7, 0x30f3 /* offset 3814 */ ,
+ 0x30df, 0x30af, 0x30ed, 0x30f3 /* offset 3819 */ ,
+ 0x30df, 0x30ea /* offset 3823 */ ,
+ 0x30df, 0x30ea, 0x30cf, 0x3099, 0x30fc, 0x30eb /* offset 3825 */ ,
+ 0x30e1, 0x30ab, 0x3099 /* offset 3831 */ ,
+ 0x30e1, 0x30ab, 0x3099, 0x30c8, 0x30f3 /* offset 3834 */ ,
+ 0x30e1, 0x30fc, 0x30c8, 0x30eb /* offset 3839 */ ,
+ 0x30e4, 0x30fc, 0x30c8, 0x3099 /* offset 3843 */ ,
+ 0x30e4, 0x30fc, 0x30eb /* offset 3847 */ ,
+ 0x30e6, 0x30a2, 0x30f3 /* offset 3850 */ ,
+ 0x30ea, 0x30c3, 0x30c8, 0x30eb /* offset 3853 */ ,
+ 0x30ea, 0x30e9 /* offset 3857 */ ,
+ 0x30eb, 0x30d2, 0x309a, 0x30fc /* offset 3859 */ ,
+ 0x30eb, 0x30fc, 0x30d5, 0x3099, 0x30eb /* offset 3863 */ ,
+ 0x30ec, 0x30e0 /* offset 3868 */ ,
+ 0x30ec, 0x30f3, 0x30c8, 0x30b1, 0x3099, 0x30f3 /* offset 3870 */ ,
+ 0x30ef, 0x30c3, 0x30c8 /* offset 3876 */ ,
+ 0x30, 0x70b9 /* offset 3879 */ ,
+ 0x31, 0x70b9 /* offset 3881 */ ,
+ 0x32, 0x70b9 /* offset 3883 */ ,
+ 0x33, 0x70b9 /* offset 3885 */ ,
+ 0x34, 0x70b9 /* offset 3887 */ ,
+ 0x35, 0x70b9 /* offset 3889 */ ,
+ 0x36, 0x70b9 /* offset 3891 */ ,
+ 0x37, 0x70b9 /* offset 3893 */ ,
+ 0x38, 0x70b9 /* offset 3895 */ ,
+ 0x39, 0x70b9 /* offset 3897 */ ,
+ 0x31, 0x30, 0x70b9 /* offset 3899 */ ,
+ 0x31, 0x31, 0x70b9 /* offset 3902 */ ,
+ 0x31, 0x32, 0x70b9 /* offset 3905 */ ,
+ 0x31, 0x33, 0x70b9 /* offset 3908 */ ,
+ 0x31, 0x34, 0x70b9 /* offset 3911 */ ,
+ 0x31, 0x35, 0x70b9 /* offset 3914 */ ,
+ 0x31, 0x36, 0x70b9 /* offset 3917 */ ,
+ 0x31, 0x37, 0x70b9 /* offset 3920 */ ,
+ 0x31, 0x38, 0x70b9 /* offset 3923 */ ,
+ 0x31, 0x39, 0x70b9 /* offset 3926 */ ,
+ 0x32, 0x30, 0x70b9 /* offset 3929 */ ,
+ 0x32, 0x31, 0x70b9 /* offset 3932 */ ,
+ 0x32, 0x32, 0x70b9 /* offset 3935 */ ,
+ 0x32, 0x33, 0x70b9 /* offset 3938 */ ,
+ 0x32, 0x34, 0x70b9 /* offset 3941 */ ,
+ 0x68, 0x50, 0x61 /* offset 3944 */ ,
+ 0x64, 0x61 /* offset 3947 */ ,
+ 0x41, 0x55 /* offset 3949 */ ,
+ 0x62, 0x61, 0x72 /* offset 3951 */ ,
+ 0x6f, 0x56 /* offset 3954 */ ,
+ 0x70, 0x63 /* offset 3956 */ ,
+ 0x5e73, 0x6210 /* offset 3958 */ ,
+ 0x662d, 0x548c /* offset 3960 */ ,
+ 0x5927, 0x6b63 /* offset 3962 */ ,
+ 0x660e, 0x6cbb /* offset 3964 */ ,
+ 0x682a, 0x5f0f, 0x4f1a, 0x793e /* offset 3966 */ ,
+ 0x70, 0x41 /* offset 3970 */ ,
+ 0x6e, 0x41 /* offset 3972 */ ,
+ 0x3bc, 0x41 /* offset 3974 */ ,
+ 0x6d, 0x41 /* offset 3976 */ ,
+ 0x6b, 0x41 /* offset 3978 */ ,
+ 0x4b, 0x42 /* offset 3980 */ ,
+ 0x4d, 0x42 /* offset 3982 */ ,
+ 0x47, 0x42 /* offset 3984 */ ,
+ 0x63, 0x61, 0x6c /* offset 3986 */ ,
+ 0x6b, 0x63, 0x61, 0x6c /* offset 3989 */ ,
+ 0x70, 0x46 /* offset 3993 */ ,
+ 0x6e, 0x46 /* offset 3995 */ ,
+ 0x3bc, 0x46 /* offset 3997 */ ,
+ 0x3bc, 0x67 /* offset 3999 */ ,
+ 0x6d, 0x67 /* offset 4001 */ ,
+ 0x6b, 0x67 /* offset 4003 */ ,
+ 0x48, 0x7a /* offset 4005 */ ,
+ 0x6b, 0x48, 0x7a /* offset 4007 */ ,
+ 0x4d, 0x48, 0x7a /* offset 4010 */ ,
+ 0x47, 0x48, 0x7a /* offset 4013 */ ,
+ 0x54, 0x48, 0x7a /* offset 4016 */ ,
+ 0x3bc, 0x6c /* offset 4019 */ ,
+ 0x6d, 0x6c /* offset 4021 */ ,
+ 0x64, 0x6c /* offset 4023 */ ,
+ 0x6b, 0x6c /* offset 4025 */ ,
+ 0x66, 0x6d /* offset 4027 */ ,
+ 0x6e, 0x6d /* offset 4029 */ ,
+ 0x3bc, 0x6d /* offset 4031 */ ,
+ 0x6d, 0x6d /* offset 4033 */ ,
+ 0x63, 0x6d /* offset 4035 */ ,
+ 0x6b, 0x6d /* offset 4037 */ ,
+ 0x6d, 0x6d, 0x32 /* offset 4039 */ ,
+ 0x63, 0x6d, 0x32 /* offset 4042 */ ,
+ 0x6d, 0x32 /* offset 4045 */ ,
+ 0x6b, 0x6d, 0x32 /* offset 4047 */ ,
+ 0x6d, 0x6d, 0x33 /* offset 4050 */ ,
+ 0x63, 0x6d, 0x33 /* offset 4053 */ ,
+ 0x6d, 0x33 /* offset 4056 */ ,
+ 0x6b, 0x6d, 0x33 /* offset 4058 */ ,
+ 0x6d, 0x2215, 0x73 /* offset 4061 */ ,
+ 0x6d, 0x2215, 0x73, 0x32 /* offset 4064 */ ,
+ 0x50, 0x61 /* offset 4068 */ ,
+ 0x6b, 0x50, 0x61 /* offset 4070 */ ,
+ 0x4d, 0x50, 0x61 /* offset 4073 */ ,
+ 0x47, 0x50, 0x61 /* offset 4076 */ ,
+ 0x72, 0x61, 0x64 /* offset 4079 */ ,
+ 0x72, 0x61, 0x64, 0x2215, 0x73 /* offset 4082 */ ,
+ 0x72, 0x61, 0x64, 0x2215, 0x73, 0x32 /* offset 4087 */ ,
+ 0x70, 0x73 /* offset 4093 */ ,
+ 0x6e, 0x73 /* offset 4095 */ ,
+ 0x3bc, 0x73 /* offset 4097 */ ,
+ 0x6d, 0x73 /* offset 4099 */ ,
+ 0x70, 0x56 /* offset 4101 */ ,
+ 0x6e, 0x56 /* offset 4103 */ ,
+ 0x3bc, 0x56 /* offset 4105 */ ,
+ 0x6d, 0x56 /* offset 4107 */ ,
+ 0x6b, 0x56 /* offset 4109 */ ,
+ 0x4d, 0x56 /* offset 4111 */ ,
+ 0x70, 0x57 /* offset 4113 */ ,
+ 0x6e, 0x57 /* offset 4115 */ ,
+ 0x3bc, 0x57 /* offset 4117 */ ,
+ 0x6d, 0x57 /* offset 4119 */ ,
+ 0x6b, 0x57 /* offset 4121 */ ,
+ 0x4d, 0x57 /* offset 4123 */ ,
+ 0x6b, 0x3a9 /* offset 4125 */ ,
+ 0x4d, 0x3a9 /* offset 4127 */ ,
+ 0x61, 0x2e, 0x6d, 0x2e /* offset 4129 */ ,
+ 0x42, 0x71 /* offset 4133 */ ,
+ 0x63, 0x63 /* offset 4135 */ ,
+ 0x63, 0x64 /* offset 4137 */ ,
+ 0x43, 0x2215, 0x6b, 0x67 /* offset 4139 */ ,
+ 0x43, 0x6f, 0x2e /* offset 4143 */ ,
+ 0x64, 0x42 /* offset 4146 */ ,
+ 0x47, 0x79 /* offset 4148 */ ,
+ 0x68, 0x61 /* offset 4150 */ ,
+ 0x48, 0x50 /* offset 4152 */ ,
+ 0x69, 0x6e /* offset 4154 */ ,
+ 0x4b, 0x4b /* offset 4156 */ ,
+ 0x4b, 0x4d /* offset 4158 */ ,
+ 0x6b, 0x74 /* offset 4160 */ ,
+ 0x6c, 0x6d /* offset 4162 */ ,
+ 0x6c, 0x6e /* offset 4164 */ ,
+ 0x6c, 0x6f, 0x67 /* offset 4166 */ ,
+ 0x6c, 0x78 /* offset 4169 */ ,
+ 0x6d, 0x62 /* offset 4171 */ ,
+ 0x6d, 0x69, 0x6c /* offset 4173 */ ,
+ 0x6d, 0x6f, 0x6c /* offset 4176 */ ,
+ 0x50, 0x48 /* offset 4179 */ ,
+ 0x70, 0x2e, 0x6d, 0x2e /* offset 4181 */ ,
+ 0x50, 0x50, 0x4d /* offset 4185 */ ,
+ 0x50, 0x52 /* offset 4188 */ ,
+ 0x73, 0x72 /* offset 4190 */ ,
+ 0x53, 0x76 /* offset 4192 */ ,
+ 0x57, 0x62 /* offset 4194 */ ,
+ 0x31, 0x65e5 /* offset 4196 */ ,
+ 0x32, 0x65e5 /* offset 4198 */ ,
+ 0x33, 0x65e5 /* offset 4200 */ ,
+ 0x34, 0x65e5 /* offset 4202 */ ,
+ 0x35, 0x65e5 /* offset 4204 */ ,
+ 0x36, 0x65e5 /* offset 4206 */ ,
+ 0x37, 0x65e5 /* offset 4208 */ ,
+ 0x38, 0x65e5 /* offset 4210 */ ,
+ 0x39, 0x65e5 /* offset 4212 */ ,
+ 0x31, 0x30, 0x65e5 /* offset 4214 */ ,
+ 0x31, 0x31, 0x65e5 /* offset 4217 */ ,
+ 0x31, 0x32, 0x65e5 /* offset 4220 */ ,
+ 0x31, 0x33, 0x65e5 /* offset 4223 */ ,
+ 0x31, 0x34, 0x65e5 /* offset 4226 */ ,
+ 0x31, 0x35, 0x65e5 /* offset 4229 */ ,
+ 0x31, 0x36, 0x65e5 /* offset 4232 */ ,
+ 0x31, 0x37, 0x65e5 /* offset 4235 */ ,
+ 0x31, 0x38, 0x65e5 /* offset 4238 */ ,
+ 0x31, 0x39, 0x65e5 /* offset 4241 */ ,
+ 0x32, 0x30, 0x65e5 /* offset 4244 */ ,
+ 0x32, 0x31, 0x65e5 /* offset 4247 */ ,
+ 0x32, 0x32, 0x65e5 /* offset 4250 */ ,
+ 0x32, 0x33, 0x65e5 /* offset 4253 */ ,
+ 0x32, 0x34, 0x65e5 /* offset 4256 */ ,
+ 0x32, 0x35, 0x65e5 /* offset 4259 */ ,
+ 0x32, 0x36, 0x65e5 /* offset 4262 */ ,
+ 0x32, 0x37, 0x65e5 /* offset 4265 */ ,
+ 0x32, 0x38, 0x65e5 /* offset 4268 */ ,
+ 0x32, 0x39, 0x65e5 /* offset 4271 */ ,
+ 0x33, 0x30, 0x65e5 /* offset 4274 */ ,
+ 0x33, 0x31, 0x65e5 /* offset 4277 */ ,
+ 0x8c48 /* offset 4280 */ ,
+ 0x66f4 /* offset 4281 */ ,
+ 0x8cc8 /* offset 4282 */ ,
+ 0x6ed1 /* offset 4283 */ ,
+ 0x4e32 /* offset 4284 */ ,
+ 0x53e5 /* offset 4285 */ ,
+ 0x5951 /* offset 4286 */ ,
+ 0x5587 /* offset 4287 */ ,
+ 0x5948 /* offset 4288 */ ,
+ 0x61f6 /* offset 4289 */ ,
+ 0x7669 /* offset 4290 */ ,
+ 0x7f85 /* offset 4291 */ ,
+ 0x863f /* offset 4292 */ ,
+ 0x87ba /* offset 4293 */ ,
+ 0x88f8 /* offset 4294 */ ,
+ 0x908f /* offset 4295 */ ,
+ 0x6a02 /* offset 4296 */ ,
+ 0x6d1b /* offset 4297 */ ,
+ 0x70d9 /* offset 4298 */ ,
+ 0x73de /* offset 4299 */ ,
+ 0x843d /* offset 4300 */ ,
+ 0x916a /* offset 4301 */ ,
+ 0x99f1 /* offset 4302 */ ,
+ 0x4e82 /* offset 4303 */ ,
+ 0x5375 /* offset 4304 */ ,
+ 0x6b04 /* offset 4305 */ ,
+ 0x721b /* offset 4306 */ ,
+ 0x862d /* offset 4307 */ ,
+ 0x9e1e /* offset 4308 */ ,
+ 0x5d50 /* offset 4309 */ ,
+ 0x6feb /* offset 4310 */ ,
+ 0x85cd /* offset 4311 */ ,
+ 0x8964 /* offset 4312 */ ,
+ 0x62c9 /* offset 4313 */ ,
+ 0x81d8 /* offset 4314 */ ,
+ 0x881f /* offset 4315 */ ,
+ 0x5eca /* offset 4316 */ ,
+ 0x6717 /* offset 4317 */ ,
+ 0x6d6a /* offset 4318 */ ,
+ 0x72fc /* offset 4319 */ ,
+ 0x90ce /* offset 4320 */ ,
+ 0x4f86 /* offset 4321 */ ,
+ 0x51b7 /* offset 4322 */ ,
+ 0x52de /* offset 4323 */ ,
+ 0x64c4 /* offset 4324 */ ,
+ 0x6ad3 /* offset 4325 */ ,
+ 0x7210 /* offset 4326 */ ,
+ 0x76e7 /* offset 4327 */ ,
+ 0x8606 /* offset 4328 */ ,
+ 0x865c /* offset 4329 */ ,
+ 0x8def /* offset 4330 */ ,
+ 0x9732 /* offset 4331 */ ,
+ 0x9b6f /* offset 4332 */ ,
+ 0x9dfa /* offset 4333 */ ,
+ 0x788c /* offset 4334 */ ,
+ 0x797f /* offset 4335 */ ,
+ 0x7da0 /* offset 4336 */ ,
+ 0x83c9 /* offset 4337 */ ,
+ 0x9304 /* offset 4338 */ ,
+ 0x8ad6 /* offset 4339 */ ,
+ 0x58df /* offset 4340 */ ,
+ 0x5f04 /* offset 4341 */ ,
+ 0x7c60 /* offset 4342 */ ,
+ 0x807e /* offset 4343 */ ,
+ 0x7262 /* offset 4344 */ ,
+ 0x78ca /* offset 4345 */ ,
+ 0x8cc2 /* offset 4346 */ ,
+ 0x96f7 /* offset 4347 */ ,
+ 0x58d8 /* offset 4348 */ ,
+ 0x5c62 /* offset 4349 */ ,
+ 0x6a13 /* offset 4350 */ ,
+ 0x6dda /* offset 4351 */ ,
+ 0x6f0f /* offset 4352 */ ,
+ 0x7d2f /* offset 4353 */ ,
+ 0x7e37 /* offset 4354 */ ,
+ 0x964b /* offset 4355 */ ,
+ 0x52d2 /* offset 4356 */ ,
+ 0x808b /* offset 4357 */ ,
+ 0x51dc /* offset 4358 */ ,
+ 0x51cc /* offset 4359 */ ,
+ 0x7a1c /* offset 4360 */ ,
+ 0x7dbe /* offset 4361 */ ,
+ 0x83f1 /* offset 4362 */ ,
+ 0x9675 /* offset 4363 */ ,
+ 0x8b80 /* offset 4364 */ ,
+ 0x62cf /* offset 4365 */ ,
+ 0x8afe /* offset 4366 */ ,
+ 0x4e39 /* offset 4367 */ ,
+ 0x5be7 /* offset 4368 */ ,
+ 0x6012 /* offset 4369 */ ,
+ 0x7387 /* offset 4370 */ ,
+ 0x7570 /* offset 4371 */ ,
+ 0x5317 /* offset 4372 */ ,
+ 0x78fb /* offset 4373 */ ,
+ 0x4fbf /* offset 4374 */ ,
+ 0x5fa9 /* offset 4375 */ ,
+ 0x4e0d /* offset 4376 */ ,
+ 0x6ccc /* offset 4377 */ ,
+ 0x6578 /* offset 4378 */ ,
+ 0x7d22 /* offset 4379 */ ,
+ 0x53c3 /* offset 4380 */ ,
+ 0x585e /* offset 4381 */ ,
+ 0x7701 /* offset 4382 */ ,
+ 0x8449 /* offset 4383 */ ,
+ 0x8aaa /* offset 4384 */ ,
+ 0x6bba /* offset 4385 */ ,
+ 0x6c88 /* offset 4386 */ ,
+ 0x62fe /* offset 4387 */ ,
+ 0x82e5 /* offset 4388 */ ,
+ 0x63a0 /* offset 4389 */ ,
+ 0x7565 /* offset 4390 */ ,
+ 0x4eae /* offset 4391 */ ,
+ 0x5169 /* offset 4392 */ ,
+ 0x51c9 /* offset 4393 */ ,
+ 0x6881 /* offset 4394 */ ,
+ 0x7ce7 /* offset 4395 */ ,
+ 0x826f /* offset 4396 */ ,
+ 0x8ad2 /* offset 4397 */ ,
+ 0x91cf /* offset 4398 */ ,
+ 0x52f5 /* offset 4399 */ ,
+ 0x5442 /* offset 4400 */ ,
+ 0x5eec /* offset 4401 */ ,
+ 0x65c5 /* offset 4402 */ ,
+ 0x6ffe /* offset 4403 */ ,
+ 0x792a /* offset 4404 */ ,
+ 0x95ad /* offset 4405 */ ,
+ 0x9a6a /* offset 4406 */ ,
+ 0x9e97 /* offset 4407 */ ,
+ 0x9ece /* offset 4408 */ ,
+ 0x66c6 /* offset 4409 */ ,
+ 0x6b77 /* offset 4410 */ ,
+ 0x8f62 /* offset 4411 */ ,
+ 0x5e74 /* offset 4412 */ ,
+ 0x6190 /* offset 4413 */ ,
+ 0x6200 /* offset 4414 */ ,
+ 0x649a /* offset 4415 */ ,
+ 0x6f23 /* offset 4416 */ ,
+ 0x7149 /* offset 4417 */ ,
+ 0x7489 /* offset 4418 */ ,
+ 0x79ca /* offset 4419 */ ,
+ 0x7df4 /* offset 4420 */ ,
+ 0x806f /* offset 4421 */ ,
+ 0x8f26 /* offset 4422 */ ,
+ 0x84ee /* offset 4423 */ ,
+ 0x9023 /* offset 4424 */ ,
+ 0x934a /* offset 4425 */ ,
+ 0x5217 /* offset 4426 */ ,
+ 0x52a3 /* offset 4427 */ ,
+ 0x54bd /* offset 4428 */ ,
+ 0x70c8 /* offset 4429 */ ,
+ 0x88c2 /* offset 4430 */ ,
+ 0x5ec9 /* offset 4431 */ ,
+ 0x5ff5 /* offset 4432 */ ,
+ 0x637b /* offset 4433 */ ,
+ 0x6bae /* offset 4434 */ ,
+ 0x7c3e /* offset 4435 */ ,
+ 0x7375 /* offset 4436 */ ,
+ 0x4ee4 /* offset 4437 */ ,
+ 0x56f9 /* offset 4438 */ ,
+ 0x5dba /* offset 4439 */ ,
+ 0x601c /* offset 4440 */ ,
+ 0x73b2 /* offset 4441 */ ,
+ 0x7469 /* offset 4442 */ ,
+ 0x7f9a /* offset 4443 */ ,
+ 0x8046 /* offset 4444 */ ,
+ 0x9234 /* offset 4445 */ ,
+ 0x96f6 /* offset 4446 */ ,
+ 0x9748 /* offset 4447 */ ,
+ 0x9818 /* offset 4448 */ ,
+ 0x4f8b /* offset 4449 */ ,
+ 0x79ae /* offset 4450 */ ,
+ 0x91b4 /* offset 4451 */ ,
+ 0x96b8 /* offset 4452 */ ,
+ 0x60e1 /* offset 4453 */ ,
+ 0x4e86 /* offset 4454 */ ,
+ 0x50da /* offset 4455 */ ,
+ 0x5bee /* offset 4456 */ ,
+ 0x5c3f /* offset 4457 */ ,
+ 0x6599 /* offset 4458 */ ,
+ 0x71ce /* offset 4459 */ ,
+ 0x7642 /* offset 4460 */ ,
+ 0x84fc /* offset 4461 */ ,
+ 0x907c /* offset 4462 */ ,
+ 0x6688 /* offset 4463 */ ,
+ 0x962e /* offset 4464 */ ,
+ 0x5289 /* offset 4465 */ ,
+ 0x677b /* offset 4466 */ ,
+ 0x67f3 /* offset 4467 */ ,
+ 0x6d41 /* offset 4468 */ ,
+ 0x6e9c /* offset 4469 */ ,
+ 0x7409 /* offset 4470 */ ,
+ 0x7559 /* offset 4471 */ ,
+ 0x786b /* offset 4472 */ ,
+ 0x7d10 /* offset 4473 */ ,
+ 0x985e /* offset 4474 */ ,
+ 0x622e /* offset 4475 */ ,
+ 0x9678 /* offset 4476 */ ,
+ 0x502b /* offset 4477 */ ,
+ 0x5d19 /* offset 4478 */ ,
+ 0x6dea /* offset 4479 */ ,
+ 0x8f2a /* offset 4480 */ ,
+ 0x5f8b /* offset 4481 */ ,
+ 0x6144 /* offset 4482 */ ,
+ 0x6817 /* offset 4483 */ ,
+ 0x9686 /* offset 4484 */ ,
+ 0x5229 /* offset 4485 */ ,
+ 0x540f /* offset 4486 */ ,
+ 0x5c65 /* offset 4487 */ ,
+ 0x6613 /* offset 4488 */ ,
+ 0x674e /* offset 4489 */ ,
+ 0x68a8 /* offset 4490 */ ,
+ 0x6ce5 /* offset 4491 */ ,
+ 0x7406 /* offset 4492 */ ,
+ 0x75e2 /* offset 4493 */ ,
+ 0x7f79 /* offset 4494 */ ,
+ 0x88cf /* offset 4495 */ ,
+ 0x88e1 /* offset 4496 */ ,
+ 0x96e2 /* offset 4497 */ ,
+ 0x533f /* offset 4498 */ ,
+ 0x6eba /* offset 4499 */ ,
+ 0x541d /* offset 4500 */ ,
+ 0x71d0 /* offset 4501 */ ,
+ 0x7498 /* offset 4502 */ ,
+ 0x85fa /* offset 4503 */ ,
+ 0x96a3 /* offset 4504 */ ,
+ 0x9c57 /* offset 4505 */ ,
+ 0x9e9f /* offset 4506 */ ,
+ 0x6797 /* offset 4507 */ ,
+ 0x6dcb /* offset 4508 */ ,
+ 0x81e8 /* offset 4509 */ ,
+ 0x7b20 /* offset 4510 */ ,
+ 0x7c92 /* offset 4511 */ ,
+ 0x72c0 /* offset 4512 */ ,
+ 0x7099 /* offset 4513 */ ,
+ 0x8b58 /* offset 4514 */ ,
+ 0x4ec0 /* offset 4515 */ ,
+ 0x8336 /* offset 4516 */ ,
+ 0x523a /* offset 4517 */ ,
+ 0x5207 /* offset 4518 */ ,
+ 0x5ea6 /* offset 4519 */ ,
+ 0x62d3 /* offset 4520 */ ,
+ 0x7cd6 /* offset 4521 */ ,
+ 0x5b85 /* offset 4522 */ ,
+ 0x6d1e /* offset 4523 */ ,
+ 0x66b4 /* offset 4524 */ ,
+ 0x8f3b /* offset 4525 */ ,
+ 0x964d /* offset 4526 */ ,
+ 0x5ed3 /* offset 4527 */ ,
+ 0x5140 /* offset 4528 */ ,
+ 0x55c0 /* offset 4529 */ ,
+ 0x585a /* offset 4530 */ ,
+ 0x6674 /* offset 4531 */ ,
+ 0x51de /* offset 4532 */ ,
+ 0x732a /* offset 4533 */ ,
+ 0x76ca /* offset 4534 */ ,
+ 0x793c /* offset 4535 */ ,
+ 0x795e /* offset 4536 */ ,
+ 0x7965 /* offset 4537 */ ,
+ 0x798f /* offset 4538 */ ,
+ 0x9756 /* offset 4539 */ ,
+ 0x7cbe /* offset 4540 */ ,
+ 0x8612 /* offset 4541 */ ,
+ 0x8af8 /* offset 4542 */ ,
+ 0x9038 /* offset 4543 */ ,
+ 0x90fd /* offset 4544 */ ,
+ 0x98ef /* offset 4545 */ ,
+ 0x98fc /* offset 4546 */ ,
+ 0x9928 /* offset 4547 */ ,
+ 0x9db4 /* offset 4548 */ ,
+ 0x4fae /* offset 4549 */ ,
+ 0x50e7 /* offset 4550 */ ,
+ 0x514d /* offset 4551 */ ,
+ 0x52c9 /* offset 4552 */ ,
+ 0x52e4 /* offset 4553 */ ,
+ 0x5351 /* offset 4554 */ ,
+ 0x559d /* offset 4555 */ ,
+ 0x5606 /* offset 4556 */ ,
+ 0x5668 /* offset 4557 */ ,
+ 0x5840 /* offset 4558 */ ,
+ 0x58a8 /* offset 4559 */ ,
+ 0x5c64 /* offset 4560 */ ,
+ 0x6094 /* offset 4561 */ ,
+ 0x6168 /* offset 4562 */ ,
+ 0x618e /* offset 4563 */ ,
+ 0x61f2 /* offset 4564 */ ,
+ 0x654f /* offset 4565 */ ,
+ 0x65e2 /* offset 4566 */ ,
+ 0x6691 /* offset 4567 */ ,
+ 0x6885 /* offset 4568 */ ,
+ 0x6d77 /* offset 4569 */ ,
+ 0x6e1a /* offset 4570 */ ,
+ 0x6f22 /* offset 4571 */ ,
+ 0x716e /* offset 4572 */ ,
+ 0x722b /* offset 4573 */ ,
+ 0x7422 /* offset 4574 */ ,
+ 0x7891 /* offset 4575 */ ,
+ 0x7949 /* offset 4576 */ ,
+ 0x7948 /* offset 4577 */ ,
+ 0x7950 /* offset 4578 */ ,
+ 0x7956 /* offset 4579 */ ,
+ 0x798d /* offset 4580 */ ,
+ 0x798e /* offset 4581 */ ,
+ 0x7a40 /* offset 4582 */ ,
+ 0x7a81 /* offset 4583 */ ,
+ 0x7bc0 /* offset 4584 */ ,
+ 0x7e09 /* offset 4585 */ ,
+ 0x7e41 /* offset 4586 */ ,
+ 0x7f72 /* offset 4587 */ ,
+ 0x8005 /* offset 4588 */ ,
+ 0x81ed /* offset 4589 */ ,
+ 0x8279 /* offset 4590 */ ,
+ 0x8457 /* offset 4591 */ ,
+ 0x8910 /* offset 4592 */ ,
+ 0x8996 /* offset 4593 */ ,
+ 0x8b01 /* offset 4594 */ ,
+ 0x8b39 /* offset 4595 */ ,
+ 0x8cd3 /* offset 4596 */ ,
+ 0x8d08 /* offset 4597 */ ,
+ 0x8fb6 /* offset 4598 */ ,
+ 0x96e3 /* offset 4599 */ ,
+ 0x97ff /* offset 4600 */ ,
+ 0x983b /* offset 4601 */ ,
+ 0x66, 0x66 /* offset 4602 */ ,
+ 0x66, 0x69 /* offset 4604 */ ,
+ 0x66, 0x6c /* offset 4606 */ ,
+ 0x66, 0x66, 0x69 /* offset 4608 */ ,
+ 0x66, 0x66, 0x6c /* offset 4611 */ ,
+ 0x73, 0x74 /* offset 4614 */ ,
+ 0x574, 0x576 /* offset 4616 */ ,
+ 0x574, 0x565 /* offset 4618 */ ,
+ 0x574, 0x56b /* offset 4620 */ ,
+ 0x57e, 0x576 /* offset 4622 */ ,
+ 0x574, 0x56d /* offset 4624 */ ,
+ 0x5d9, 0x5b4 /* offset 4626 */ ,
+ 0x5f2, 0x5b7 /* offset 4628 */ ,
+ 0x5e2 /* offset 4630 */ ,
+ 0x5d4 /* offset 4631 */ ,
+ 0x5db /* offset 4632 */ ,
+ 0x5dc /* offset 4633 */ ,
+ 0x5dd /* offset 4634 */ ,
+ 0x5e8 /* offset 4635 */ ,
+ 0x5ea /* offset 4636 */ ,
+ 0x5e9, 0x5c1 /* offset 4637 */ ,
+ 0x5e9, 0x5c2 /* offset 4639 */ ,
+ 0x5e9, 0x5bc, 0x5c1 /* offset 4641 */ ,
+ 0x5e9, 0x5bc, 0x5c2 /* offset 4644 */ ,
+ 0x5d0, 0x5b7 /* offset 4647 */ ,
+ 0x5d0, 0x5b8 /* offset 4649 */ ,
+ 0x5d0, 0x5bc /* offset 4651 */ ,
+ 0x5d1, 0x5bc /* offset 4653 */ ,
+ 0x5d2, 0x5bc /* offset 4655 */ ,
+ 0x5d3, 0x5bc /* offset 4657 */ ,
+ 0x5d4, 0x5bc /* offset 4659 */ ,
+ 0x5d5, 0x5bc /* offset 4661 */ ,
+ 0x5d6, 0x5bc /* offset 4663 */ ,
+ 0x5d8, 0x5bc /* offset 4665 */ ,
+ 0x5d9, 0x5bc /* offset 4667 */ ,
+ 0x5da, 0x5bc /* offset 4669 */ ,
+ 0x5db, 0x5bc /* offset 4671 */ ,
+ 0x5dc, 0x5bc /* offset 4673 */ ,
+ 0x5de, 0x5bc /* offset 4675 */ ,
+ 0x5e0, 0x5bc /* offset 4677 */ ,
+ 0x5e1, 0x5bc /* offset 4679 */ ,
+ 0x5e3, 0x5bc /* offset 4681 */ ,
+ 0x5e4, 0x5bc /* offset 4683 */ ,
+ 0x5e6, 0x5bc /* offset 4685 */ ,
+ 0x5e7, 0x5bc /* offset 4687 */ ,
+ 0x5e8, 0x5bc /* offset 4689 */ ,
+ 0x5e9, 0x5bc /* offset 4691 */ ,
+ 0x5ea, 0x5bc /* offset 4693 */ ,
+ 0x5d5, 0x5b9 /* offset 4695 */ ,
+ 0x5d1, 0x5bf /* offset 4697 */ ,
+ 0x5db, 0x5bf /* offset 4699 */ ,
+ 0x5e4, 0x5bf /* offset 4701 */ ,
+ 0x5d0, 0x5dc /* offset 4703 */ ,
+ 0x671 /* offset 4705 */ ,
+ 0x67b /* offset 4706 */ ,
+ 0x67e /* offset 4707 */ ,
+ 0x680 /* offset 4708 */ ,
+ 0x67a /* offset 4709 */ ,
+ 0x67f /* offset 4710 */ ,
+ 0x679 /* offset 4711 */ ,
+ 0x6a4 /* offset 4712 */ ,
+ 0x6a6 /* offset 4713 */ ,
+ 0x684 /* offset 4714 */ ,
+ 0x683 /* offset 4715 */ ,
+ 0x686 /* offset 4716 */ ,
+ 0x687 /* offset 4717 */ ,
+ 0x68d /* offset 4718 */ ,
+ 0x68c /* offset 4719 */ ,
+ 0x68e /* offset 4720 */ ,
+ 0x688 /* offset 4721 */ ,
+ 0x698 /* offset 4722 */ ,
+ 0x691 /* offset 4723 */ ,
+ 0x6a9 /* offset 4724 */ ,
+ 0x6af /* offset 4725 */ ,
+ 0x6b3 /* offset 4726 */ ,
+ 0x6b1 /* offset 4727 */ ,
+ 0x6ba /* offset 4728 */ ,
+ 0x6bb /* offset 4729 */ ,
+ 0x6c1 /* offset 4730 */ ,
+ 0x6be /* offset 4731 */ ,
+ 0x6d2 /* offset 4732 */ ,
+ 0x6ad /* offset 4733 */ ,
+ 0x6c7 /* offset 4734 */ ,
+ 0x6c6 /* offset 4735 */ ,
+ 0x6c8 /* offset 4736 */ ,
+ 0x6cb /* offset 4737 */ ,
+ 0x6c5 /* offset 4738 */ ,
+ 0x6c9 /* offset 4739 */ ,
+ 0x6d0 /* offset 4740 */ ,
+ 0x649 /* offset 4741 */ ,
+ 0x64a, 0x654, 0x627 /* offset 4742 */ ,
+ 0x64a, 0x654, 0x6d5 /* offset 4745 */ ,
+ 0x64a, 0x654, 0x648 /* offset 4748 */ ,
+ 0x64a, 0x654, 0x6c7 /* offset 4751 */ ,
+ 0x64a, 0x654, 0x6c6 /* offset 4754 */ ,
+ 0x64a, 0x654, 0x6c8 /* offset 4757 */ ,
+ 0x64a, 0x654, 0x6d0 /* offset 4760 */ ,
+ 0x64a, 0x654, 0x649 /* offset 4763 */ ,
+ 0x6cc /* offset 4766 */ ,
+ 0x64a, 0x654, 0x62c /* offset 4767 */ ,
+ 0x64a, 0x654, 0x62d /* offset 4770 */ ,
+ 0x64a, 0x654, 0x645 /* offset 4773 */ ,
+ 0x64a, 0x654, 0x64a /* offset 4776 */ ,
+ 0x628, 0x62c /* offset 4779 */ ,
+ 0x628, 0x62d /* offset 4781 */ ,
+ 0x628, 0x62e /* offset 4783 */ ,
+ 0x628, 0x645 /* offset 4785 */ ,
+ 0x628, 0x649 /* offset 4787 */ ,
+ 0x628, 0x64a /* offset 4789 */ ,
+ 0x62a, 0x62c /* offset 4791 */ ,
+ 0x62a, 0x62d /* offset 4793 */ ,
+ 0x62a, 0x62e /* offset 4795 */ ,
+ 0x62a, 0x645 /* offset 4797 */ ,
+ 0x62a, 0x649 /* offset 4799 */ ,
+ 0x62a, 0x64a /* offset 4801 */ ,
+ 0x62b, 0x62c /* offset 4803 */ ,
+ 0x62b, 0x645 /* offset 4805 */ ,
+ 0x62b, 0x649 /* offset 4807 */ ,
+ 0x62b, 0x64a /* offset 4809 */ ,
+ 0x62c, 0x62d /* offset 4811 */ ,
+ 0x62c, 0x645 /* offset 4813 */ ,
+ 0x62d, 0x62c /* offset 4815 */ ,
+ 0x62d, 0x645 /* offset 4817 */ ,
+ 0x62e, 0x62c /* offset 4819 */ ,
+ 0x62e, 0x62d /* offset 4821 */ ,
+ 0x62e, 0x645 /* offset 4823 */ ,
+ 0x633, 0x62c /* offset 4825 */ ,
+ 0x633, 0x62d /* offset 4827 */ ,
+ 0x633, 0x62e /* offset 4829 */ ,
+ 0x633, 0x645 /* offset 4831 */ ,
+ 0x635, 0x62d /* offset 4833 */ ,
+ 0x635, 0x645 /* offset 4835 */ ,
+ 0x636, 0x62c /* offset 4837 */ ,
+ 0x636, 0x62d /* offset 4839 */ ,
+ 0x636, 0x62e /* offset 4841 */ ,
+ 0x636, 0x645 /* offset 4843 */ ,
+ 0x637, 0x62d /* offset 4845 */ ,
+ 0x637, 0x645 /* offset 4847 */ ,
+ 0x638, 0x645 /* offset 4849 */ ,
+ 0x639, 0x62c /* offset 4851 */ ,
+ 0x639, 0x645 /* offset 4853 */ ,
+ 0x63a, 0x62c /* offset 4855 */ ,
+ 0x63a, 0x645 /* offset 4857 */ ,
+ 0x641, 0x62c /* offset 4859 */ ,
+ 0x641, 0x62d /* offset 4861 */ ,
+ 0x641, 0x62e /* offset 4863 */ ,
+ 0x641, 0x645 /* offset 4865 */ ,
+ 0x641, 0x649 /* offset 4867 */ ,
+ 0x641, 0x64a /* offset 4869 */ ,
+ 0x642, 0x62d /* offset 4871 */ ,
+ 0x642, 0x645 /* offset 4873 */ ,
+ 0x642, 0x649 /* offset 4875 */ ,
+ 0x642, 0x64a /* offset 4877 */ ,
+ 0x643, 0x627 /* offset 4879 */ ,
+ 0x643, 0x62c /* offset 4881 */ ,
+ 0x643, 0x62d /* offset 4883 */ ,
+ 0x643, 0x62e /* offset 4885 */ ,
+ 0x643, 0x644 /* offset 4887 */ ,
+ 0x643, 0x645 /* offset 4889 */ ,
+ 0x643, 0x649 /* offset 4891 */ ,
+ 0x643, 0x64a /* offset 4893 */ ,
+ 0x644, 0x62c /* offset 4895 */ ,
+ 0x644, 0x62d /* offset 4897 */ ,
+ 0x644, 0x62e /* offset 4899 */ ,
+ 0x644, 0x645 /* offset 4901 */ ,
+ 0x644, 0x649 /* offset 4903 */ ,
+ 0x644, 0x64a /* offset 4905 */ ,
+ 0x645, 0x62c /* offset 4907 */ ,
+ 0x645, 0x62d /* offset 4909 */ ,
+ 0x645, 0x62e /* offset 4911 */ ,
+ 0x645, 0x645 /* offset 4913 */ ,
+ 0x645, 0x649 /* offset 4915 */ ,
+ 0x645, 0x64a /* offset 4917 */ ,
+ 0x646, 0x62c /* offset 4919 */ ,
+ 0x646, 0x62d /* offset 4921 */ ,
+ 0x646, 0x62e /* offset 4923 */ ,
+ 0x646, 0x645 /* offset 4925 */ ,
+ 0x646, 0x649 /* offset 4927 */ ,
+ 0x646, 0x64a /* offset 4929 */ ,
+ 0x647, 0x62c /* offset 4931 */ ,
+ 0x647, 0x645 /* offset 4933 */ ,
+ 0x647, 0x649 /* offset 4935 */ ,
+ 0x647, 0x64a /* offset 4937 */ ,
+ 0x64a, 0x62c /* offset 4939 */ ,
+ 0x64a, 0x62d /* offset 4941 */ ,
+ 0x64a, 0x62e /* offset 4943 */ ,
+ 0x64a, 0x645 /* offset 4945 */ ,
+ 0x64a, 0x649 /* offset 4947 */ ,
+ 0x64a, 0x64a /* offset 4949 */ ,
+ 0x630, 0x670 /* offset 4951 */ ,
+ 0x631, 0x670 /* offset 4953 */ ,
+ 0x649, 0x670 /* offset 4955 */ ,
+ 0x20, 0x64c, 0x651 /* offset 4957 */ ,
+ 0x20, 0x64d, 0x651 /* offset 4960 */ ,
+ 0x20, 0x64e, 0x651 /* offset 4963 */ ,
+ 0x20, 0x64f, 0x651 /* offset 4966 */ ,
+ 0x20, 0x650, 0x651 /* offset 4969 */ ,
+ 0x20, 0x651, 0x670 /* offset 4972 */ ,
+ 0x64a, 0x654, 0x631 /* offset 4975 */ ,
+ 0x64a, 0x654, 0x632 /* offset 4978 */ ,
+ 0x64a, 0x654, 0x646 /* offset 4981 */ ,
+ 0x628, 0x631 /* offset 4984 */ ,
+ 0x628, 0x632 /* offset 4986 */ ,
+ 0x628, 0x646 /* offset 4988 */ ,
+ 0x62a, 0x631 /* offset 4990 */ ,
+ 0x62a, 0x632 /* offset 4992 */ ,
+ 0x62a, 0x646 /* offset 4994 */ ,
+ 0x62b, 0x631 /* offset 4996 */ ,
+ 0x62b, 0x632 /* offset 4998 */ ,
+ 0x62b, 0x646 /* offset 5000 */ ,
+ 0x645, 0x627 /* offset 5002 */ ,
+ 0x646, 0x631 /* offset 5004 */ ,
+ 0x646, 0x632 /* offset 5006 */ ,
+ 0x646, 0x646 /* offset 5008 */ ,
+ 0x64a, 0x631 /* offset 5010 */ ,
+ 0x64a, 0x632 /* offset 5012 */ ,
+ 0x64a, 0x646 /* offset 5014 */ ,
+ 0x64a, 0x654, 0x62e /* offset 5016 */ ,
+ 0x64a, 0x654, 0x647 /* offset 5019 */ ,
+ 0x628, 0x647 /* offset 5022 */ ,
+ 0x62a, 0x647 /* offset 5024 */ ,
+ 0x635, 0x62e /* offset 5026 */ ,
+ 0x644, 0x647 /* offset 5028 */ ,
+ 0x646, 0x647 /* offset 5030 */ ,
+ 0x647, 0x670 /* offset 5032 */ ,
+ 0x64a, 0x647 /* offset 5034 */ ,
+ 0x62b, 0x647 /* offset 5036 */ ,
+ 0x633, 0x647 /* offset 5038 */ ,
+ 0x634, 0x645 /* offset 5040 */ ,
+ 0x634, 0x647 /* offset 5042 */ ,
+ 0x640, 0x64e, 0x651 /* offset 5044 */ ,
+ 0x640, 0x64f, 0x651 /* offset 5047 */ ,
+ 0x640, 0x650, 0x651 /* offset 5050 */ ,
+ 0x637, 0x649 /* offset 5053 */ ,
+ 0x637, 0x64a /* offset 5055 */ ,
+ 0x639, 0x649 /* offset 5057 */ ,
+ 0x639, 0x64a /* offset 5059 */ ,
+ 0x63a, 0x649 /* offset 5061 */ ,
+ 0x63a, 0x64a /* offset 5063 */ ,
+ 0x633, 0x649 /* offset 5065 */ ,
+ 0x633, 0x64a /* offset 5067 */ ,
+ 0x634, 0x649 /* offset 5069 */ ,
+ 0x634, 0x64a /* offset 5071 */ ,
+ 0x62d, 0x649 /* offset 5073 */ ,
+ 0x62d, 0x64a /* offset 5075 */ ,
+ 0x62c, 0x649 /* offset 5077 */ ,
+ 0x62c, 0x64a /* offset 5079 */ ,
+ 0x62e, 0x649 /* offset 5081 */ ,
+ 0x62e, 0x64a /* offset 5083 */ ,
+ 0x635, 0x649 /* offset 5085 */ ,
+ 0x635, 0x64a /* offset 5087 */ ,
+ 0x636, 0x649 /* offset 5089 */ ,
+ 0x636, 0x64a /* offset 5091 */ ,
+ 0x634, 0x62c /* offset 5093 */ ,
+ 0x634, 0x62d /* offset 5095 */ ,
+ 0x634, 0x62e /* offset 5097 */ ,
+ 0x634, 0x631 /* offset 5099 */ ,
+ 0x633, 0x631 /* offset 5101 */ ,
+ 0x635, 0x631 /* offset 5103 */ ,
+ 0x636, 0x631 /* offset 5105 */ ,
+ 0x627, 0x64b /* offset 5107 */ ,
+ 0x62a, 0x62c, 0x645 /* offset 5109 */ ,
+ 0x62a, 0x62d, 0x62c /* offset 5112 */ ,
+ 0x62a, 0x62d, 0x645 /* offset 5115 */ ,
+ 0x62a, 0x62e, 0x645 /* offset 5118 */ ,
+ 0x62a, 0x645, 0x62c /* offset 5121 */ ,
+ 0x62a, 0x645, 0x62d /* offset 5124 */ ,
+ 0x62a, 0x645, 0x62e /* offset 5127 */ ,
+ 0x62c, 0x645, 0x62d /* offset 5130 */ ,
+ 0x62d, 0x645, 0x64a /* offset 5133 */ ,
+ 0x62d, 0x645, 0x649 /* offset 5136 */ ,
+ 0x633, 0x62d, 0x62c /* offset 5139 */ ,
+ 0x633, 0x62c, 0x62d /* offset 5142 */ ,
+ 0x633, 0x62c, 0x649 /* offset 5145 */ ,
+ 0x633, 0x645, 0x62d /* offset 5148 */ ,
+ 0x633, 0x645, 0x62c /* offset 5151 */ ,
+ 0x633, 0x645, 0x645 /* offset 5154 */ ,
+ 0x635, 0x62d, 0x62d /* offset 5157 */ ,
+ 0x635, 0x645, 0x645 /* offset 5160 */ ,
+ 0x634, 0x62d, 0x645 /* offset 5163 */ ,
+ 0x634, 0x62c, 0x64a /* offset 5166 */ ,
+ 0x634, 0x645, 0x62e /* offset 5169 */ ,
+ 0x634, 0x645, 0x645 /* offset 5172 */ ,
+ 0x636, 0x62d, 0x649 /* offset 5175 */ ,
+ 0x636, 0x62e, 0x645 /* offset 5178 */ ,
+ 0x637, 0x645, 0x62d /* offset 5181 */ ,
+ 0x637, 0x645, 0x645 /* offset 5184 */ ,
+ 0x637, 0x645, 0x64a /* offset 5187 */ ,
+ 0x639, 0x62c, 0x645 /* offset 5190 */ ,
+ 0x639, 0x645, 0x645 /* offset 5193 */ ,
+ 0x639, 0x645, 0x649 /* offset 5196 */ ,
+ 0x63a, 0x645, 0x645 /* offset 5199 */ ,
+ 0x63a, 0x645, 0x64a /* offset 5202 */ ,
+ 0x63a, 0x645, 0x649 /* offset 5205 */ ,
+ 0x641, 0x62e, 0x645 /* offset 5208 */ ,
+ 0x642, 0x645, 0x62d /* offset 5211 */ ,
+ 0x642, 0x645, 0x645 /* offset 5214 */ ,
+ 0x644, 0x62d, 0x645 /* offset 5217 */ ,
+ 0x644, 0x62d, 0x64a /* offset 5220 */ ,
+ 0x644, 0x62d, 0x649 /* offset 5223 */ ,
+ 0x644, 0x62c, 0x62c /* offset 5226 */ ,
+ 0x644, 0x62e, 0x645 /* offset 5229 */ ,
+ 0x644, 0x645, 0x62d /* offset 5232 */ ,
+ 0x645, 0x62d, 0x62c /* offset 5235 */ ,
+ 0x645, 0x62d, 0x645 /* offset 5238 */ ,
+ 0x645, 0x62d, 0x64a /* offset 5241 */ ,
+ 0x645, 0x62c, 0x62d /* offset 5244 */ ,
+ 0x645, 0x62c, 0x645 /* offset 5247 */ ,
+ 0x645, 0x62e, 0x62c /* offset 5250 */ ,
+ 0x645, 0x62e, 0x645 /* offset 5253 */ ,
+ 0x645, 0x62c, 0x62e /* offset 5256 */ ,
+ 0x647, 0x645, 0x62c /* offset 5259 */ ,
+ 0x647, 0x645, 0x645 /* offset 5262 */ ,
+ 0x646, 0x62d, 0x645 /* offset 5265 */ ,
+ 0x646, 0x62d, 0x649 /* offset 5268 */ ,
+ 0x646, 0x62c, 0x645 /* offset 5271 */ ,
+ 0x646, 0x62c, 0x649 /* offset 5274 */ ,
+ 0x646, 0x645, 0x64a /* offset 5277 */ ,
+ 0x646, 0x645, 0x649 /* offset 5280 */ ,
+ 0x64a, 0x645, 0x645 /* offset 5283 */ ,
+ 0x628, 0x62e, 0x64a /* offset 5286 */ ,
+ 0x62a, 0x62c, 0x64a /* offset 5289 */ ,
+ 0x62a, 0x62c, 0x649 /* offset 5292 */ ,
+ 0x62a, 0x62e, 0x64a /* offset 5295 */ ,
+ 0x62a, 0x62e, 0x649 /* offset 5298 */ ,
+ 0x62a, 0x645, 0x64a /* offset 5301 */ ,
+ 0x62a, 0x645, 0x649 /* offset 5304 */ ,
+ 0x62c, 0x645, 0x64a /* offset 5307 */ ,
+ 0x62c, 0x62d, 0x649 /* offset 5310 */ ,
+ 0x62c, 0x645, 0x649 /* offset 5313 */ ,
+ 0x633, 0x62e, 0x649 /* offset 5316 */ ,
+ 0x635, 0x62d, 0x64a /* offset 5319 */ ,
+ 0x634, 0x62d, 0x64a /* offset 5322 */ ,
+ 0x636, 0x62d, 0x64a /* offset 5325 */ ,
+ 0x644, 0x62c, 0x64a /* offset 5328 */ ,
+ 0x644, 0x645, 0x64a /* offset 5331 */ ,
+ 0x64a, 0x62d, 0x64a /* offset 5334 */ ,
+ 0x64a, 0x62c, 0x64a /* offset 5337 */ ,
+ 0x64a, 0x645, 0x64a /* offset 5340 */ ,
+ 0x645, 0x645, 0x64a /* offset 5343 */ ,
+ 0x642, 0x645, 0x64a /* offset 5346 */ ,
+ 0x646, 0x62d, 0x64a /* offset 5349 */ ,
+ 0x639, 0x645, 0x64a /* offset 5352 */ ,
+ 0x643, 0x645, 0x64a /* offset 5355 */ ,
+ 0x646, 0x62c, 0x62d /* offset 5358 */ ,
+ 0x645, 0x62e, 0x64a /* offset 5361 */ ,
+ 0x644, 0x62c, 0x645 /* offset 5364 */ ,
+ 0x643, 0x645, 0x645 /* offset 5367 */ ,
+ 0x62c, 0x62d, 0x64a /* offset 5370 */ ,
+ 0x62d, 0x62c, 0x64a /* offset 5373 */ ,
+ 0x645, 0x62c, 0x64a /* offset 5376 */ ,
+ 0x641, 0x645, 0x64a /* offset 5379 */ ,
+ 0x628, 0x62d, 0x64a /* offset 5382 */ ,
+ 0x633, 0x62e, 0x64a /* offset 5385 */ ,
+ 0x646, 0x62c, 0x64a /* offset 5388 */ ,
+ 0x635, 0x644, 0x6d2 /* offset 5391 */ ,
+ 0x642, 0x644, 0x6d2 /* offset 5394 */ ,
+ 0x627, 0x644, 0x644, 0x647 /* offset 5397 */ ,
+ 0x627, 0x643, 0x628, 0x631 /* offset 5401 */ ,
+ 0x645, 0x62d, 0x645, 0x62f /* offset 5405 */ ,
+ 0x635, 0x644, 0x639, 0x645 /* offset 5409 */ ,
+ 0x631, 0x633, 0x648, 0x644 /* offset 5413 */ ,
+ 0x639, 0x644, 0x64a, 0x647 /* offset 5417 */ ,
+ 0x648, 0x633, 0x644, 0x645 /* offset 5421 */ ,
+ 0x635, 0x644, 0x649 /* offset 5425 */ ,
+ 0x635, 0x644, 0x649, 0x20, 0x627, 0x644, 0x644, 0x647, 0x20, 0x639, 0x644, 0x64a, 0x647, 0x20, 0x648, 0x633, 0x644, 0x645 /* offset 5428 */ ,
+ 0x62c, 0x644, 0x20, 0x62c, 0x644, 0x627, 0x644, 0x647 /* offset 5446 */ ,
+ 0x631, 0x6cc, 0x627, 0x644 /* offset 5454 */ ,
+ 0x2014 /* offset 5458 */ ,
+ 0x2013 /* offset 5459 */ ,
+ 0x5f /* offset 5460 */ ,
+ 0x7b /* offset 5461 */ ,
+ 0x7d /* offset 5462 */ ,
+ 0x3014 /* offset 5463 */ ,
+ 0x3015 /* offset 5464 */ ,
+ 0x3010 /* offset 5465 */ ,
+ 0x3011 /* offset 5466 */ ,
+ 0x300a /* offset 5467 */ ,
+ 0x300b /* offset 5468 */ ,
+ 0x300c /* offset 5469 */ ,
+ 0x300d /* offset 5470 */ ,
+ 0x300e /* offset 5471 */ ,
+ 0x300f /* offset 5472 */ ,
+ 0x2c /* offset 5473 */ ,
+ 0x3001 /* offset 5474 */ ,
+ 0x3a /* offset 5475 */ ,
+ 0x3f /* offset 5476 */ ,
+ 0x21 /* offset 5477 */ ,
+ 0x23 /* offset 5478 */ ,
+ 0x26 /* offset 5479 */ ,
+ 0x2a /* offset 5480 */ ,
+ 0x2d /* offset 5481 */ ,
+ 0x3c /* offset 5482 */ ,
+ 0x3e /* offset 5483 */ ,
+ 0x5c /* offset 5484 */ ,
+ 0x24 /* offset 5485 */ ,
+ 0x25 /* offset 5486 */ ,
+ 0x40 /* offset 5487 */ ,
+ 0x20, 0x64b /* offset 5488 */ ,
+ 0x640, 0x64b /* offset 5490 */ ,
+ 0x20, 0x64c /* offset 5492 */ ,
+ 0x20, 0x64d /* offset 5494 */ ,
+ 0x20, 0x64e /* offset 5496 */ ,
+ 0x640, 0x64e /* offset 5498 */ ,
+ 0x20, 0x64f /* offset 5500 */ ,
+ 0x640, 0x64f /* offset 5502 */ ,
+ 0x20, 0x650 /* offset 5504 */ ,
+ 0x640, 0x650 /* offset 5506 */ ,
+ 0x20, 0x651 /* offset 5508 */ ,
+ 0x640, 0x651 /* offset 5510 */ ,
+ 0x20, 0x652 /* offset 5512 */ ,
+ 0x640, 0x652 /* offset 5514 */ ,
+ 0x621 /* offset 5516 */ ,
+ 0x627 /* offset 5517 */ ,
+ 0x628 /* offset 5518 */ ,
+ 0x629 /* offset 5519 */ ,
+ 0x62a /* offset 5520 */ ,
+ 0x62b /* offset 5521 */ ,
+ 0x62c /* offset 5522 */ ,
+ 0x62d /* offset 5523 */ ,
+ 0x62e /* offset 5524 */ ,
+ 0x62f /* offset 5525 */ ,
+ 0x630 /* offset 5526 */ ,
+ 0x631 /* offset 5527 */ ,
+ 0x632 /* offset 5528 */ ,
+ 0x633 /* offset 5529 */ ,
+ 0x634 /* offset 5530 */ ,
+ 0x635 /* offset 5531 */ ,
+ 0x636 /* offset 5532 */ ,
+ 0x637 /* offset 5533 */ ,
+ 0x638 /* offset 5534 */ ,
+ 0x639 /* offset 5535 */ ,
+ 0x63a /* offset 5536 */ ,
+ 0x641 /* offset 5537 */ ,
+ 0x642 /* offset 5538 */ ,
+ 0x643 /* offset 5539 */ ,
+ 0x644 /* offset 5540 */ ,
+ 0x645 /* offset 5541 */ ,
+ 0x646 /* offset 5542 */ ,
+ 0x647 /* offset 5543 */ ,
+ 0x648 /* offset 5544 */ ,
+ 0x64a /* offset 5545 */ ,
+ 0x644, 0x627, 0x653 /* offset 5546 */ ,
+ 0x644, 0x627, 0x654 /* offset 5549 */ ,
+ 0x644, 0x627, 0x655 /* offset 5552 */ ,
+ 0x644, 0x627 /* offset 5555 */ ,
+ 0x22 /* offset 5557 */ ,
+ 0x27 /* offset 5558 */ ,
+ 0x2f /* offset 5559 */ ,
+ 0x5b /* offset 5560 */ ,
+ 0x5d /* offset 5561 */ ,
+ 0x5e /* offset 5562 */ ,
+ 0x7c /* offset 5563 */ ,
+ 0x7e /* offset 5564 */ ,
+ 0x2985 /* offset 5565 */ ,
+ 0x2986 /* offset 5566 */ ,
+ 0x3002 /* offset 5567 */ ,
+ 0x30fb /* offset 5568 */ ,
+ 0x30a1 /* offset 5569 */ ,
+ 0x30a3 /* offset 5570 */ ,
+ 0x30a5 /* offset 5571 */ ,
+ 0x30a7 /* offset 5572 */ ,
+ 0x30a9 /* offset 5573 */ ,
+ 0x30e3 /* offset 5574 */ ,
+ 0x30e5 /* offset 5575 */ ,
+ 0x30e7 /* offset 5576 */ ,
+ 0x30c3 /* offset 5577 */ ,
+ 0x30fc /* offset 5578 */ ,
+ 0x30f3 /* offset 5579 */ ,
+ 0x3099 /* offset 5580 */ ,
+ 0x309a /* offset 5581 */ ,
+ 0xa2 /* offset 5582 */ ,
+ 0xa3 /* offset 5583 */ ,
+ 0xac /* offset 5584 */ ,
+ 0xa6 /* offset 5585 */ ,
+ 0xa5 /* offset 5586 */ ,
+ 0x20a9 /* offset 5587 */ ,
+ 0x2502 /* offset 5588 */ ,
+ 0x2190 /* offset 5589 */ ,
+ 0x2191 /* offset 5590 */ ,
+ 0x2192 /* offset 5591 */ ,
+ 0x2193 /* offset 5592 */ ,
+ 0x25a0 /* offset 5593 */ ,
+ 0x25cb /* offset 5594 */ ,
+ 0x1d157, 0x1d165 /* offset 5595 */ ,
+ 0x1d158, 0x1d165 /* offset 5597 */ ,
+ 0x1d158, 0x1d165, 0x1d16e /* offset 5599 */ ,
+ 0x1d158, 0x1d165, 0x1d16f /* offset 5602 */ ,
+ 0x1d158, 0x1d165, 0x1d170 /* offset 5605 */ ,
+ 0x1d158, 0x1d165, 0x1d171 /* offset 5608 */ ,
+ 0x1d158, 0x1d165, 0x1d172 /* offset 5611 */ ,
+ 0x1d1b9, 0x1d165 /* offset 5614 */ ,
+ 0x1d1ba, 0x1d165 /* offset 5616 */ ,
+ 0x1d1b9, 0x1d165, 0x1d16e /* offset 5618 */ ,
+ 0x1d1ba, 0x1d165, 0x1d16e /* offset 5621 */ ,
+ 0x1d1b9, 0x1d165, 0x1d16f /* offset 5624 */ ,
+ 0x1d1ba, 0x1d165, 0x1d16f /* offset 5627 */ ,
+ 0x391 /* offset 5630 */ ,
+ 0x392 /* offset 5631 */ ,
+ 0x394 /* offset 5632 */ ,
+ 0x395 /* offset 5633 */ ,
+ 0x396 /* offset 5634 */ ,
+ 0x397 /* offset 5635 */ ,
+ 0x399 /* offset 5636 */ ,
+ 0x39a /* offset 5637 */ ,
+ 0x39b /* offset 5638 */ ,
+ 0x39c /* offset 5639 */ ,
+ 0x39d /* offset 5640 */ ,
+ 0x39e /* offset 5641 */ ,
+ 0x39f /* offset 5642 */ ,
+ 0x3a1 /* offset 5643 */ ,
+ 0x3a3 /* offset 5644 */ ,
+ 0x3a4 /* offset 5645 */ ,
+ 0x3a6 /* offset 5646 */ ,
+ 0x3a7 /* offset 5647 */ ,
+ 0x3a8 /* offset 5648 */ ,
+ 0x2207 /* offset 5649 */ ,
+ 0x3b1 /* offset 5650 */ ,
+ 0x3b4 /* offset 5651 */ ,
+ 0x3b6 /* offset 5652 */ ,
+ 0x3b7 /* offset 5653 */ ,
+ 0x3bb /* offset 5654 */ ,
+ 0x3bd /* offset 5655 */ ,
+ 0x3be /* offset 5656 */ ,
+ 0x3bf /* offset 5657 */ ,
+ 0x3c3 /* offset 5658 */ ,
+ 0x3c4 /* offset 5659 */ ,
+ 0x3c5 /* offset 5660 */ ,
+ 0x3c7 /* offset 5661 */ ,
+ 0x3c8 /* offset 5662 */ ,
+ 0x3c9 /* offset 5663 */ ,
+ 0x2202 /* offset 5664 */ ,
+ 0x4e3d /* offset 5665 */ ,
+ 0x4e38 /* offset 5666 */ ,
+ 0x4e41 /* offset 5667 */ ,
+ 0x20122 /* offset 5668 */ ,
+ 0x4f60 /* offset 5669 */ ,
+ 0x4fbb /* offset 5670 */ ,
+ 0x5002 /* offset 5671 */ ,
+ 0x507a /* offset 5672 */ ,
+ 0x5099 /* offset 5673 */ ,
+ 0x50cf /* offset 5674 */ ,
+ 0x349e /* offset 5675 */ ,
+ 0x2063a /* offset 5676 */ ,
+ 0x5154 /* offset 5677 */ ,
+ 0x5164 /* offset 5678 */ ,
+ 0x5177 /* offset 5679 */ ,
+ 0x2051c /* offset 5680 */ ,
+ 0x34b9 /* offset 5681 */ ,
+ 0x5167 /* offset 5682 */ ,
+ 0x518d /* offset 5683 */ ,
+ 0x2054b /* offset 5684 */ ,
+ 0x5197 /* offset 5685 */ ,
+ 0x51a4 /* offset 5686 */ ,
+ 0x4ecc /* offset 5687 */ ,
+ 0x51ac /* offset 5688 */ ,
+ 0x51b5 /* offset 5689 */ ,
+ 0x291df /* offset 5690 */ ,
+ 0x5203 /* offset 5691 */ ,
+ 0x34df /* offset 5692 */ ,
+ 0x523b /* offset 5693 */ ,
+ 0x5246 /* offset 5694 */ ,
+ 0x5272 /* offset 5695 */ ,
+ 0x5277 /* offset 5696 */ ,
+ 0x3515 /* offset 5697 */ ,
+ 0x52c7 /* offset 5698 */ ,
+ 0x52fa /* offset 5699 */ ,
+ 0x5305 /* offset 5700 */ ,
+ 0x5306 /* offset 5701 */ ,
+ 0x5349 /* offset 5702 */ ,
+ 0x535a /* offset 5703 */ ,
+ 0x5373 /* offset 5704 */ ,
+ 0x537d /* offset 5705 */ ,
+ 0x537f /* offset 5706 */ ,
+ 0x20a2c /* offset 5707 */ ,
+ 0x7070 /* offset 5708 */ ,
+ 0x53ca /* offset 5709 */ ,
+ 0x53df /* offset 5710 */ ,
+ 0x20b63 /* offset 5711 */ ,
+ 0x53eb /* offset 5712 */ ,
+ 0x53f1 /* offset 5713 */ ,
+ 0x5406 /* offset 5714 */ ,
+ 0x549e /* offset 5715 */ ,
+ 0x5438 /* offset 5716 */ ,
+ 0x5448 /* offset 5717 */ ,
+ 0x5468 /* offset 5718 */ ,
+ 0x54a2 /* offset 5719 */ ,
+ 0x54f6 /* offset 5720 */ ,
+ 0x5510 /* offset 5721 */ ,
+ 0x5553 /* offset 5722 */ ,
+ 0x5563 /* offset 5723 */ ,
+ 0x5584 /* offset 5724 */ ,
+ 0x5599 /* offset 5725 */ ,
+ 0x55ab /* offset 5726 */ ,
+ 0x55b3 /* offset 5727 */ ,
+ 0x55c2 /* offset 5728 */ ,
+ 0x5716 /* offset 5729 */ ,
+ 0x5717 /* offset 5730 */ ,
+ 0x5651 /* offset 5731 */ ,
+ 0x5674 /* offset 5732 */ ,
+ 0x58ee /* offset 5733 */ ,
+ 0x57ce /* offset 5734 */ ,
+ 0x57f4 /* offset 5735 */ ,
+ 0x580d /* offset 5736 */ ,
+ 0x578b /* offset 5737 */ ,
+ 0x5832 /* offset 5738 */ ,
+ 0x5831 /* offset 5739 */ ,
+ 0x58ac /* offset 5740 */ ,
+ 0x214e4 /* offset 5741 */ ,
+ 0x58f2 /* offset 5742 */ ,
+ 0x58f7 /* offset 5743 */ ,
+ 0x5906 /* offset 5744 */ ,
+ 0x591a /* offset 5745 */ ,
+ 0x5922 /* offset 5746 */ ,
+ 0x5962 /* offset 5747 */ ,
+ 0x216a8 /* offset 5748 */ ,
+ 0x216ea /* offset 5749 */ ,
+ 0x59ec /* offset 5750 */ ,
+ 0x5a1b /* offset 5751 */ ,
+ 0x5a27 /* offset 5752 */ ,
+ 0x59d8 /* offset 5753 */ ,
+ 0x5a66 /* offset 5754 */ ,
+ 0x36ee /* offset 5755 */ ,
+ 0x2136a /* offset 5756 */ ,
+ 0x5b08 /* offset 5757 */ ,
+ 0x5b3e /* offset 5758 */ ,
+ 0x219c8 /* offset 5759 */ ,
+ 0x5bc3 /* offset 5760 */ ,
+ 0x5bd8 /* offset 5761 */ ,
+ 0x5bf3 /* offset 5762 */ ,
+ 0x21b18 /* offset 5763 */ ,
+ 0x5bff /* offset 5764 */ ,
+ 0x5c06 /* offset 5765 */ ,
+ 0x5f33 /* offset 5766 */ ,
+ 0x3781 /* offset 5767 */ ,
+ 0x5c60 /* offset 5768 */ ,
+ 0x5cc0 /* offset 5769 */ ,
+ 0x5c8d /* offset 5770 */ ,
+ 0x21de4 /* offset 5771 */ ,
+ 0x5d43 /* offset 5772 */ ,
+ 0x21de6 /* offset 5773 */ ,
+ 0x5d6e /* offset 5774 */ ,
+ 0x5d6b /* offset 5775 */ ,
+ 0x5d7c /* offset 5776 */ ,
+ 0x5de1 /* offset 5777 */ ,
+ 0x5de2 /* offset 5778 */ ,
+ 0x382f /* offset 5779 */ ,
+ 0x5dfd /* offset 5780 */ ,
+ 0x5e28 /* offset 5781 */ ,
+ 0x5e3d /* offset 5782 */ ,
+ 0x5e69 /* offset 5783 */ ,
+ 0x3862 /* offset 5784 */ ,
+ 0x22183 /* offset 5785 */ ,
+ 0x387c /* offset 5786 */ ,
+ 0x5eb0 /* offset 5787 */ ,
+ 0x5eb3 /* offset 5788 */ ,
+ 0x5eb6 /* offset 5789 */ ,
+ 0x2a392 /* offset 5790 */ ,
+ 0x22331 /* offset 5791 */ ,
+ 0x8201 /* offset 5792 */ ,
+ 0x5f22 /* offset 5793 */ ,
+ 0x38c7 /* offset 5794 */ ,
+ 0x232b8 /* offset 5795 */ ,
+ 0x261da /* offset 5796 */ ,
+ 0x5f62 /* offset 5797 */ ,
+ 0x5f6b /* offset 5798 */ ,
+ 0x38e3 /* offset 5799 */ ,
+ 0x5f9a /* offset 5800 */ ,
+ 0x5fcd /* offset 5801 */ ,
+ 0x5fd7 /* offset 5802 */ ,
+ 0x5ff9 /* offset 5803 */ ,
+ 0x6081 /* offset 5804 */ ,
+ 0x393a /* offset 5805 */ ,
+ 0x391c /* offset 5806 */ ,
+ 0x226d4 /* offset 5807 */ ,
+ 0x60c7 /* offset 5808 */ ,
+ 0x6148 /* offset 5809 */ ,
+ 0x614c /* offset 5810 */ ,
+ 0x614e /* offset 5811 */ ,
+ 0x617a /* offset 5812 */ ,
+ 0x61b2 /* offset 5813 */ ,
+ 0x61a4 /* offset 5814 */ ,
+ 0x61af /* offset 5815 */ ,
+ 0x61de /* offset 5816 */ ,
+ 0x6210 /* offset 5817 */ ,
+ 0x621b /* offset 5818 */ ,
+ 0x625d /* offset 5819 */ ,
+ 0x62b1 /* offset 5820 */ ,
+ 0x62d4 /* offset 5821 */ ,
+ 0x6350 /* offset 5822 */ ,
+ 0x22b0c /* offset 5823 */ ,
+ 0x633d /* offset 5824 */ ,
+ 0x62fc /* offset 5825 */ ,
+ 0x6368 /* offset 5826 */ ,
+ 0x6383 /* offset 5827 */ ,
+ 0x63e4 /* offset 5828 */ ,
+ 0x22bf1 /* offset 5829 */ ,
+ 0x6422 /* offset 5830 */ ,
+ 0x63c5 /* offset 5831 */ ,
+ 0x63a9 /* offset 5832 */ ,
+ 0x3a2e /* offset 5833 */ ,
+ 0x6469 /* offset 5834 */ ,
+ 0x647e /* offset 5835 */ ,
+ 0x649d /* offset 5836 */ ,
+ 0x6477 /* offset 5837 */ ,
+ 0x3a6c /* offset 5838 */ ,
+ 0x656c /* offset 5839 */ ,
+ 0x2300a /* offset 5840 */ ,
+ 0x65e3 /* offset 5841 */ ,
+ 0x66f8 /* offset 5842 */ ,
+ 0x6649 /* offset 5843 */ ,
+ 0x3b19 /* offset 5844 */ ,
+ 0x3b08 /* offset 5845 */ ,
+ 0x3ae4 /* offset 5846 */ ,
+ 0x5192 /* offset 5847 */ ,
+ 0x5195 /* offset 5848 */ ,
+ 0x6700 /* offset 5849 */ ,
+ 0x669c /* offset 5850 */ ,
+ 0x80ad /* offset 5851 */ ,
+ 0x43d9 /* offset 5852 */ ,
+ 0x671b /* offset 5853 */ ,
+ 0x6721 /* offset 5854 */ ,
+ 0x675e /* offset 5855 */ ,
+ 0x6753 /* offset 5856 */ ,
+ 0x233c3 /* offset 5857 */ ,
+ 0x3b49 /* offset 5858 */ ,
+ 0x67fa /* offset 5859 */ ,
+ 0x6785 /* offset 5860 */ ,
+ 0x6852 /* offset 5861 */ ,
+ 0x2346d /* offset 5862 */ ,
+ 0x688e /* offset 5863 */ ,
+ 0x681f /* offset 5864 */ ,
+ 0x6914 /* offset 5865 */ ,
+ 0x3b9d /* offset 5866 */ ,
+ 0x6942 /* offset 5867 */ ,
+ 0x69a3 /* offset 5868 */ ,
+ 0x69ea /* offset 5869 */ ,
+ 0x6aa8 /* offset 5870 */ ,
+ 0x236a3 /* offset 5871 */ ,
+ 0x6adb /* offset 5872 */ ,
+ 0x3c18 /* offset 5873 */ ,
+ 0x6b21 /* offset 5874 */ ,
+ 0x238a7 /* offset 5875 */ ,
+ 0x6b54 /* offset 5876 */ ,
+ 0x3c4e /* offset 5877 */ ,
+ 0x6b72 /* offset 5878 */ ,
+ 0x6b9f /* offset 5879 */ ,
+ 0x6bbb /* offset 5880 */ ,
+ 0x23a8d /* offset 5881 */ ,
+ 0x21d0b /* offset 5882 */ ,
+ 0x23afa /* offset 5883 */ ,
+ 0x6c4e /* offset 5884 */ ,
+ 0x23cbc /* offset 5885 */ ,
+ 0x6cbf /* offset 5886 */ ,
+ 0x6ccd /* offset 5887 */ ,
+ 0x6c67 /* offset 5888 */ ,
+ 0x6d16 /* offset 5889 */ ,
+ 0x6d3e /* offset 5890 */ ,
+ 0x6d69 /* offset 5891 */ ,
+ 0x6d78 /* offset 5892 */ ,
+ 0x6d85 /* offset 5893 */ ,
+ 0x23d1e /* offset 5894 */ ,
+ 0x6d34 /* offset 5895 */ ,
+ 0x6e2f /* offset 5896 */ ,
+ 0x6e6e /* offset 5897 */ ,
+ 0x3d33 /* offset 5898 */ ,
+ 0x6ecb /* offset 5899 */ ,
+ 0x6ec7 /* offset 5900 */ ,
+ 0x23ed1 /* offset 5901 */ ,
+ 0x6df9 /* offset 5902 */ ,
+ 0x6f6e /* offset 5903 */ ,
+ 0x23f5e /* offset 5904 */ ,
+ 0x23f8e /* offset 5905 */ ,
+ 0x6fc6 /* offset 5906 */ ,
+ 0x7039 /* offset 5907 */ ,
+ 0x701e /* offset 5908 */ ,
+ 0x701b /* offset 5909 */ ,
+ 0x3d96 /* offset 5910 */ ,
+ 0x704a /* offset 5911 */ ,
+ 0x707d /* offset 5912 */ ,
+ 0x7077 /* offset 5913 */ ,
+ 0x70ad /* offset 5914 */ ,
+ 0x20525 /* offset 5915 */ ,
+ 0x7145 /* offset 5916 */ ,
+ 0x24263 /* offset 5917 */ ,
+ 0x719c /* offset 5918 */ ,
+ 0x43ab /* offset 5919 */ ,
+ 0x7228 /* offset 5920 */ ,
+ 0x7235 /* offset 5921 */ ,
+ 0x7250 /* offset 5922 */ ,
+ 0x24608 /* offset 5923 */ ,
+ 0x7280 /* offset 5924 */ ,
+ 0x7295 /* offset 5925 */ ,
+ 0x24735 /* offset 5926 */ ,
+ 0x24814 /* offset 5927 */ ,
+ 0x737a /* offset 5928 */ ,
+ 0x738b /* offset 5929 */ ,
+ 0x3eac /* offset 5930 */ ,
+ 0x73a5 /* offset 5931 */ ,
+ 0x3eb8 /* offset 5932 */ ,
+ 0x7447 /* offset 5933 */ ,
+ 0x745c /* offset 5934 */ ,
+ 0x7471 /* offset 5935 */ ,
+ 0x7485 /* offset 5936 */ ,
+ 0x74ca /* offset 5937 */ ,
+ 0x3f1b /* offset 5938 */ ,
+ 0x7524 /* offset 5939 */ ,
+ 0x24c36 /* offset 5940 */ ,
+ 0x753e /* offset 5941 */ ,
+ 0x24c92 /* offset 5942 */ ,
+ 0x2219f /* offset 5943 */ ,
+ 0x7610 /* offset 5944 */ ,
+ 0x24fa1 /* offset 5945 */ ,
+ 0x24fb8 /* offset 5946 */ ,
+ 0x25044 /* offset 5947 */ ,
+ 0x3ffc /* offset 5948 */ ,
+ 0x4008 /* offset 5949 */ ,
+ 0x76f4 /* offset 5950 */ ,
+ 0x250f3 /* offset 5951 */ ,
+ 0x250f2 /* offset 5952 */ ,
+ 0x25119 /* offset 5953 */ ,
+ 0x25133 /* offset 5954 */ ,
+ 0x771e /* offset 5955 */ ,
+ 0x771f /* offset 5956 */ ,
+ 0x774a /* offset 5957 */ ,
+ 0x4039 /* offset 5958 */ ,
+ 0x778b /* offset 5959 */ ,
+ 0x4046 /* offset 5960 */ ,
+ 0x4096 /* offset 5961 */ ,
+ 0x2541d /* offset 5962 */ ,
+ 0x784e /* offset 5963 */ ,
+ 0x78cc /* offset 5964 */ ,
+ 0x40e3 /* offset 5965 */ ,
+ 0x25626 /* offset 5966 */ ,
+ 0x2569a /* offset 5967 */ ,
+ 0x256c5 /* offset 5968 */ ,
+ 0x79eb /* offset 5969 */ ,
+ 0x412f /* offset 5970 */ ,
+ 0x7a4a /* offset 5971 */ ,
+ 0x7a4f /* offset 5972 */ ,
+ 0x2597c /* offset 5973 */ ,
+ 0x25aa7 /* offset 5974 */ ,
+ 0x7aae /* offset 5975 */ ,
+ 0x4202 /* offset 5976 */ ,
+ 0x25bab /* offset 5977 */ ,
+ 0x7bc6 /* offset 5978 */ ,
+ 0x7bc9 /* offset 5979 */ ,
+ 0x4227 /* offset 5980 */ ,
+ 0x25c80 /* offset 5981 */ ,
+ 0x7cd2 /* offset 5982 */ ,
+ 0x42a0 /* offset 5983 */ ,
+ 0x7ce8 /* offset 5984 */ ,
+ 0x7ce3 /* offset 5985 */ ,
+ 0x7d00 /* offset 5986 */ ,
+ 0x25f86 /* offset 5987 */ ,
+ 0x7d63 /* offset 5988 */ ,
+ 0x4301 /* offset 5989 */ ,
+ 0x7dc7 /* offset 5990 */ ,
+ 0x7e02 /* offset 5991 */ ,
+ 0x7e45 /* offset 5992 */ ,
+ 0x4334 /* offset 5993 */ ,
+ 0x26228 /* offset 5994 */ ,
+ 0x26247 /* offset 5995 */ ,
+ 0x4359 /* offset 5996 */ ,
+ 0x262d9 /* offset 5997 */ ,
+ 0x7f7a /* offset 5998 */ ,
+ 0x2633e /* offset 5999 */ ,
+ 0x7f95 /* offset 6000 */ ,
+ 0x7ffa /* offset 6001 */ ,
+ 0x264da /* offset 6002 */ ,
+ 0x26523 /* offset 6003 */ ,
+ 0x8060 /* offset 6004 */ ,
+ 0x265a8 /* offset 6005 */ ,
+ 0x8070 /* offset 6006 */ ,
+ 0x2335f /* offset 6007 */ ,
+ 0x43d5 /* offset 6008 */ ,
+ 0x80b2 /* offset 6009 */ ,
+ 0x8103 /* offset 6010 */ ,
+ 0x440b /* offset 6011 */ ,
+ 0x813e /* offset 6012 */ ,
+ 0x5ab5 /* offset 6013 */ ,
+ 0x267a7 /* offset 6014 */ ,
+ 0x267b5 /* offset 6015 */ ,
+ 0x23393 /* offset 6016 */ ,
+ 0x2339c /* offset 6017 */ ,
+ 0x8204 /* offset 6018 */ ,
+ 0x8f9e /* offset 6019 */ ,
+ 0x446b /* offset 6020 */ ,
+ 0x8291 /* offset 6021 */ ,
+ 0x828b /* offset 6022 */ ,
+ 0x829d /* offset 6023 */ ,
+ 0x52b3 /* offset 6024 */ ,
+ 0x82b1 /* offset 6025 */ ,
+ 0x82b3 /* offset 6026 */ ,
+ 0x82bd /* offset 6027 */ ,
+ 0x82e6 /* offset 6028 */ ,
+ 0x26b3c /* offset 6029 */ ,
+ 0x831d /* offset 6030 */ ,
+ 0x8363 /* offset 6031 */ ,
+ 0x83ad /* offset 6032 */ ,
+ 0x8323 /* offset 6033 */ ,
+ 0x83bd /* offset 6034 */ ,
+ 0x83e7 /* offset 6035 */ ,
+ 0x8353 /* offset 6036 */ ,
+ 0x83ca /* offset 6037 */ ,
+ 0x83cc /* offset 6038 */ ,
+ 0x83dc /* offset 6039 */ ,
+ 0x26c36 /* offset 6040 */ ,
+ 0x26d6b /* offset 6041 */ ,
+ 0x26cd5 /* offset 6042 */ ,
+ 0x452b /* offset 6043 */ ,
+ 0x84f1 /* offset 6044 */ ,
+ 0x84f3 /* offset 6045 */ ,
+ 0x8516 /* offset 6046 */ ,
+ 0x273ca /* offset 6047 */ ,
+ 0x8564 /* offset 6048 */ ,
+ 0x26f2c /* offset 6049 */ ,
+ 0x455d /* offset 6050 */ ,
+ 0x4561 /* offset 6051 */ ,
+ 0x26fb1 /* offset 6052 */ ,
+ 0x270d2 /* offset 6053 */ ,
+ 0x456b /* offset 6054 */ ,
+ 0x8650 /* offset 6055 */ ,
+ 0x8667 /* offset 6056 */ ,
+ 0x8669 /* offset 6057 */ ,
+ 0x86a9 /* offset 6058 */ ,
+ 0x8688 /* offset 6059 */ ,
+ 0x870e /* offset 6060 */ ,
+ 0x86e2 /* offset 6061 */ ,
+ 0x8779 /* offset 6062 */ ,
+ 0x8728 /* offset 6063 */ ,
+ 0x876b /* offset 6064 */ ,
+ 0x8786 /* offset 6065 */ ,
+ 0x4d57 /* offset 6066 */ ,
+ 0x87e1 /* offset 6067 */ ,
+ 0x8801 /* offset 6068 */ ,
+ 0x45f9 /* offset 6069 */ ,
+ 0x8860 /* offset 6070 */ ,
+ 0x27667 /* offset 6071 */ ,
+ 0x88d7 /* offset 6072 */ ,
+ 0x88de /* offset 6073 */ ,
+ 0x4635 /* offset 6074 */ ,
+ 0x88fa /* offset 6075 */ ,
+ 0x34bb /* offset 6076 */ ,
+ 0x278ae /* offset 6077 */ ,
+ 0x27966 /* offset 6078 */ ,
+ 0x46be /* offset 6079 */ ,
+ 0x46c7 /* offset 6080 */ ,
+ 0x8aa0 /* offset 6081 */ ,
+ 0x8aed /* offset 6082 */ ,
+ 0x8b8a /* offset 6083 */ ,
+ 0x27ca8 /* offset 6084 */ ,
+ 0x8cab /* offset 6085 */ ,
+ 0x8cc1 /* offset 6086 */ ,
+ 0x8d1b /* offset 6087 */ ,
+ 0x8d77 /* offset 6088 */ ,
+ 0x27f2f /* offset 6089 */ ,
+ 0x20804 /* offset 6090 */ ,
+ 0x8dcb /* offset 6091 */ ,
+ 0x8dbc /* offset 6092 */ ,
+ 0x8df0 /* offset 6093 */ ,
+ 0x208de /* offset 6094 */ ,
+ 0x8ed4 /* offset 6095 */ ,
+ 0x8f38 /* offset 6096 */ ,
+ 0x285d2 /* offset 6097 */ ,
+ 0x285ed /* offset 6098 */ ,
+ 0x9094 /* offset 6099 */ ,
+ 0x90f1 /* offset 6100 */ ,
+ 0x9111 /* offset 6101 */ ,
+ 0x2872e /* offset 6102 */ ,
+ 0x911b /* offset 6103 */ ,
+ 0x9238 /* offset 6104 */ ,
+ 0x92d7 /* offset 6105 */ ,
+ 0x92d8 /* offset 6106 */ ,
+ 0x927c /* offset 6107 */ ,
+ 0x93f9 /* offset 6108 */ ,
+ 0x9415 /* offset 6109 */ ,
+ 0x28bfa /* offset 6110 */ ,
+ 0x958b /* offset 6111 */ ,
+ 0x4995 /* offset 6112 */ ,
+ 0x95b7 /* offset 6113 */ ,
+ 0x28d77 /* offset 6114 */ ,
+ 0x49e6 /* offset 6115 */ ,
+ 0x96c3 /* offset 6116 */ ,
+ 0x5db2 /* offset 6117 */ ,
+ 0x9723 /* offset 6118 */ ,
+ 0x29145 /* offset 6119 */ ,
+ 0x2921a /* offset 6120 */ ,
+ 0x4a6e /* offset 6121 */ ,
+ 0x4a76 /* offset 6122 */ ,
+ 0x97e0 /* offset 6123 */ ,
+ 0x2940a /* offset 6124 */ ,
+ 0x4ab2 /* offset 6125 */ ,
+ 0x29496 /* offset 6126 */ ,
+ 0x980b /* offset 6127 */ ,
+ 0x9829 /* offset 6128 */ ,
+ 0x295b6 /* offset 6129 */ ,
+ 0x98e2 /* offset 6130 */ ,
+ 0x4b33 /* offset 6131 */ ,
+ 0x9929 /* offset 6132 */ ,
+ 0x99a7 /* offset 6133 */ ,
+ 0x99c2 /* offset 6134 */ ,
+ 0x99fe /* offset 6135 */ ,
+ 0x4bce /* offset 6136 */ ,
+ 0x29b30 /* offset 6137 */ ,
+ 0x9b12 /* offset 6138 */ ,
+ 0x9c40 /* offset 6139 */ ,
+ 0x9cfd /* offset 6140 */ ,
+ 0x4cce /* offset 6141 */ ,
+ 0x4ced /* offset 6142 */ ,
+ 0x9d67 /* offset 6143 */ ,
+ 0x2a0ce /* offset 6144 */ ,
+ 0x4cf8 /* offset 6145 */ ,
+ 0x2a105 /* offset 6146 */ ,
+ 0x2a20e /* offset 6147 */ ,
+ 0x2a291 /* offset 6148 */ ,
+ 0x4d56 /* offset 6149 */ ,
+ 0x9efe /* offset 6150 */ ,
+ 0x9f05 /* offset 6151 */ ,
+ 0x9f0f /* offset 6152 */ ,
+ 0x9f16 /* offset 6153 */ ,
+ 0x2a600 /* offset 6154 */
+};
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMap.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMap.cc
new file mode 100644
index 00000000000..1319666779b
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMap.cc
@@ -0,0 +1,311 @@
+//========================================================================
+//
+// UnicodeMap.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "goo/gfile.h"
+#include "goo/GooString.h"
+#include "goo/GooList.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "UnicodeMap.h"
+
+//------------------------------------------------------------------------
+
+#define maxExtCode 16
+
+struct UnicodeMapExt {
+ Unicode u; // Unicode char
+ char code[maxExtCode];
+ Guint nBytes;
+};
+
+//------------------------------------------------------------------------
+
+UnicodeMap *UnicodeMap::parse(GooString *encodingNameA) {
+ FILE *f;
+ UnicodeMap *map;
+ UnicodeMapRange *range;
+ UnicodeMapExt *eMap;
+ int size, eMapsSize;
+ char buf[256];
+ int line, nBytes, i, x;
+ char *tok1, *tok2, *tok3;
+ char *tokptr;
+
+ if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) {
+ error(errSyntaxError, -1,
+ "Couldn't find unicodeMap file for the '{0:t}' encoding",
+ encodingNameA);
+ return NULL;
+ }
+
+ map = new UnicodeMap(encodingNameA->copy());
+
+ size = 8;
+ map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange));
+ eMapsSize = 0;
+
+ line = 1;
+ while (getLine(buf, sizeof(buf), f)) {
+ if ((tok1 = strtok_r(buf, " \t\r\n", &tokptr)) &&
+ (tok2 = strtok_r(NULL, " \t\r\n", &tokptr))) {
+ if (!(tok3 = strtok_r(NULL, " \t\r\n", &tokptr))) {
+ tok3 = tok2;
+ tok2 = tok1;
+ }
+ nBytes = strlen(tok3) / 2;
+ if (nBytes <= 4) {
+ if (map->len == size) {
+ size *= 2;
+ map->ranges = (UnicodeMapRange *)
+ greallocn(map->ranges, size, sizeof(UnicodeMapRange));
+ }
+ range = &map->ranges[map->len];
+ sscanf(tok1, "%x", &range->start);
+ sscanf(tok2, "%x", &range->end);
+ sscanf(tok3, "%x", &range->code);
+ range->nBytes = nBytes;
+ ++map->len;
+ } else if (tok2 == tok1) {
+ if (map->eMapsLen == eMapsSize) {
+ eMapsSize += 16;
+ map->eMaps = (UnicodeMapExt *)
+ greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt));
+ }
+ eMap = &map->eMaps[map->eMapsLen];
+ sscanf(tok1, "%x", &eMap->u);
+ for (i = 0; i < nBytes; ++i) {
+ sscanf(tok3 + i*2, "%2x", &x);
+ eMap->code[i] = (char)x;
+ }
+ eMap->nBytes = nBytes;
+ ++map->eMapsLen;
+ } else {
+ error(errSyntaxError, -1,
+ "Bad line ({0:d}) in unicodeMap file for the '{1:t}' encoding",
+ line, encodingNameA);
+ }
+ } else {
+ error(errSyntaxError, -1,
+ "Bad line ({0:d}) in unicodeMap file for the '{1:t}' encoding",
+ line, encodingNameA);
+ }
+ ++line;
+ }
+
+ fclose(f);
+
+ return map;
+}
+
+UnicodeMap::UnicodeMap(GooString *encodingNameA) {
+ encodingName = encodingNameA;
+ unicodeOut = gFalse;
+ kind = unicodeMapUser;
+ ranges = NULL;
+ len = 0;
+ eMaps = NULL;
+ eMapsLen = 0;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA,
+ UnicodeMapRange *rangesA, int lenA) {
+ encodingName = new GooString(encodingNameA);
+ unicodeOut = unicodeOutA;
+ kind = unicodeMapResident;
+ ranges = rangesA;
+ len = lenA;
+ eMaps = NULL;
+ eMapsLen = 0;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA,
+ UnicodeMapFunc funcA) {
+ encodingName = new GooString(encodingNameA);
+ unicodeOut = unicodeOutA;
+ kind = unicodeMapFunc;
+ func = funcA;
+ eMaps = NULL;
+ eMapsLen = 0;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+UnicodeMap::~UnicodeMap() {
+ delete encodingName;
+ if (kind == unicodeMapUser && ranges) {
+ gfree(ranges);
+ }
+ if (eMaps) {
+ gfree(eMaps);
+ }
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+void UnicodeMap::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ ++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+}
+
+void UnicodeMap::decRefCnt() {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
+ delete this;
+ }
+}
+
+GBool UnicodeMap::match(GooString *encodingNameA) {
+ return !encodingName->cmp(encodingNameA);
+}
+
+int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) {
+ int a, b, m, n, i, j;
+ Guint code;
+
+ if (kind == unicodeMapFunc) {
+ return (*func)(u, buf, bufSize);
+ }
+
+ a = 0;
+ b = len;
+ if (u >= ranges[a].start) {
+ // invariant: ranges[a].start <= u < ranges[b].start
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (u >= ranges[m].start) {
+ a = m;
+ } else if (u < ranges[m].start) {
+ b = m;
+ }
+ }
+ if (u <= ranges[a].end) {
+ n = ranges[a].nBytes;
+ if (n > bufSize) {
+ return 0;
+ }
+ code = ranges[a].code + (u - ranges[a].start);
+ for (i = n - 1; i >= 0; --i) {
+ buf[i] = (char)(code & 0xff);
+ code >>= 8;
+ }
+ return n;
+ }
+ }
+
+ for (i = 0; i < eMapsLen; ++i) {
+ if (eMaps[i].u == u) {
+ n = eMaps[i].nBytes;
+ for (j = 0; j < n; ++j) {
+ buf[j] = eMaps[i].code[j];
+ }
+ return n;
+ }
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------
+
+UnicodeMapCache::UnicodeMapCache() {
+ int i;
+
+ for (i = 0; i < unicodeMapCacheSize; ++i) {
+ cache[i] = NULL;
+ }
+}
+
+UnicodeMapCache::~UnicodeMapCache() {
+ int i;
+
+ for (i = 0; i < unicodeMapCacheSize; ++i) {
+ if (cache[i]) {
+ cache[i]->decRefCnt();
+ }
+ }
+}
+
+UnicodeMap *UnicodeMapCache::getUnicodeMap(GooString *encodingName) {
+ UnicodeMap *map;
+ int i, j;
+
+ if (cache[0] && cache[0]->match(encodingName)) {
+ cache[0]->incRefCnt();
+ return cache[0];
+ }
+ for (i = 1; i < unicodeMapCacheSize; ++i) {
+ if (cache[i] && cache[i]->match(encodingName)) {
+ map = cache[i];
+ for (j = i; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = map;
+ map->incRefCnt();
+ return map;
+ }
+ }
+ if ((map = UnicodeMap::parse(encodingName))) {
+ if (cache[unicodeMapCacheSize - 1]) {
+ cache[unicodeMapCacheSize - 1]->decRefCnt();
+ }
+ for (j = unicodeMapCacheSize - 1; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = map;
+ map->incRefCnt();
+ return map;
+ }
+ return NULL;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMap.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMap.h
new file mode 100644
index 00000000000..ba7df2cfb99
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMap.h
@@ -0,0 +1,122 @@
+//========================================================================
+//
+// UnicodeMap.h
+//
+// Mapping from Unicode to an encoding.
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef UNICODEMAP_H
+#define UNICODEMAP_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "goo/gtypes.h"
+#include "CharTypes.h"
+
+#if MULTITHREADED
+#include "goo/GooMutex.h"
+#endif
+
+class GooString;
+
+//------------------------------------------------------------------------
+
+enum UnicodeMapKind {
+ unicodeMapUser, // read from a file
+ unicodeMapResident, // static list of ranges
+ unicodeMapFunc // function pointer
+};
+
+typedef int (*UnicodeMapFunc)(Unicode u, char *buf, int bufSize);
+
+struct UnicodeMapRange {
+ Unicode start, end; // range of Unicode chars
+ Guint code, nBytes; // first output code
+};
+
+struct UnicodeMapExt;
+
+//------------------------------------------------------------------------
+
+class UnicodeMap {
+public:
+
+ // Create the UnicodeMap specified by <encodingName>. Sets the
+ // initial reference count to 1. Returns NULL on failure.
+ static UnicodeMap *parse(GooString *encodingNameA);
+
+ // Create a resident UnicodeMap.
+ UnicodeMap(const char *encodingNameA, GBool unicodeOutA,
+ UnicodeMapRange *rangesA, int lenA);
+
+ // Create a resident UnicodeMap that uses a function instead of a
+ // list of ranges.
+ UnicodeMap(const char *encodingNameA, GBool unicodeOutA,
+ UnicodeMapFunc funcA);
+
+ ~UnicodeMap();
+
+ void incRefCnt();
+ void decRefCnt();
+
+ GooString *getEncodingName() { return encodingName; }
+
+ GBool isUnicode() { return unicodeOut; }
+
+ // Return true if this UnicodeMap matches the specified
+ // <encodingNameA>.
+ GBool match(GooString *encodingNameA);
+
+ // Map Unicode to the target encoding. Fills in <buf> with the
+ // output and returns the number of bytes used. Output will be
+ // truncated at <bufSize> bytes. No string terminator is written.
+ // Returns 0 if no mapping is found.
+ int mapUnicode(Unicode u, char *buf, int bufSize);
+
+private:
+
+ UnicodeMap(GooString *encodingNameA);
+
+ GooString *encodingName;
+ UnicodeMapKind kind;
+ GBool unicodeOut;
+ union {
+ UnicodeMapRange *ranges; // (user, resident)
+ UnicodeMapFunc func; // (func)
+ };
+ int len; // (user, resident)
+ UnicodeMapExt *eMaps; // (user)
+ int eMapsLen; // (user)
+ int refCnt;
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+};
+
+//------------------------------------------------------------------------
+
+#define unicodeMapCacheSize 4
+
+class UnicodeMapCache {
+public:
+
+ UnicodeMapCache();
+ ~UnicodeMapCache();
+
+ // Get the UnicodeMap for <encodingName>. Increments its reference
+ // count; there will be one reference for the cache plus one for the
+ // caller of this function. Returns NULL on failure.
+ UnicodeMap *getUnicodeMap(GooString *encodingName);
+
+private:
+
+ UnicodeMap *cache[unicodeMapCacheSize];
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMapTables.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMapTables.h
new file mode 100644
index 00000000000..073e474e6be
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeMapTables.h
@@ -0,0 +1,365 @@
+//========================================================================
+//
+// UnicodeMapTables.h
+//
+// Copyright 2001-2009 Glyph & Cog, LLC
+//
+//========================================================================
+
+static UnicodeMapRange latin1UnicodeMapRanges[] = {
+ { 0x000a, 0x000a, 0x0a, 1 },
+ { 0x000c, 0x000d, 0x0c, 1 },
+ { 0x0020, 0x007e, 0x20, 1 },
+ { 0x00a0, 0x00a0, 0x20, 1 },
+ { 0x00a1, 0x00ac, 0xa1, 1 },
+ { 0x00ae, 0x00ff, 0xae, 1 },
+ { 0x010c, 0x010c, 0x43, 1 },
+ { 0x010d, 0x010d, 0x63, 1 },
+ { 0x0131, 0x0131, 0x69, 1 },
+ { 0x0141, 0x0141, 0x4c, 1 },
+ { 0x0142, 0x0142, 0x6c, 1 },
+ { 0x0152, 0x0152, 0x4f45, 2 },
+ { 0x0153, 0x0153, 0x6f65, 2 },
+ { 0x0160, 0x0160, 0x53, 1 },
+ { 0x0161, 0x0161, 0x73, 1 },
+ { 0x0178, 0x0178, 0x59, 1 },
+ { 0x017d, 0x017d, 0x5a, 1 },
+ { 0x017e, 0x017e, 0x7a, 1 },
+ { 0x02c6, 0x02c6, 0x5e, 1 },
+ { 0x02da, 0x02da, 0xb0, 1 },
+ { 0x02dc, 0x02dc, 0x7e, 1 },
+ { 0x2013, 0x2013, 0xad, 1 },
+ { 0x2014, 0x2014, 0x2d2d, 2 },
+ { 0x2018, 0x2018, 0x60, 1 },
+ { 0x2019, 0x2019, 0x27, 1 },
+ { 0x201a, 0x201a, 0x2c, 1 },
+ { 0x201c, 0x201c, 0x22, 1 },
+ { 0x201d, 0x201d, 0x22, 1 },
+ { 0x201e, 0x201e, 0x2c2c, 2 },
+ { 0x2022, 0x2022, 0xb7, 1 },
+ { 0x2026, 0x2026, 0x2e2e2e, 3 },
+ { 0x2039, 0x2039, 0x3c, 1 },
+ { 0x203a, 0x203a, 0x3e, 1 },
+ { 0x2044, 0x2044, 0x2f, 1 },
+ { 0x2122, 0x2122, 0x544d, 2 },
+ { 0x2212, 0x2212, 0x2d, 1 },
+ { 0xf6f9, 0xf6f9, 0x4c, 1 },
+ { 0xf6fa, 0xf6fa, 0x4f45, 2 },
+ { 0xf6fc, 0xf6fc, 0xb0, 1 },
+ { 0xf6fd, 0xf6fd, 0x53, 1 },
+ { 0xf6fe, 0xf6fe, 0x7e, 1 },
+ { 0xf6ff, 0xf6ff, 0x5a, 1 },
+ { 0xf721, 0xf721, 0x21, 1 },
+ { 0xf724, 0xf724, 0x24, 1 },
+ { 0xf726, 0xf726, 0x26, 1 },
+ { 0xf730, 0xf739, 0x30, 1 },
+ { 0xf73f, 0xf73f, 0x3f, 1 },
+ { 0xf761, 0xf77a, 0x41, 1 },
+ { 0xf7a1, 0xf7a2, 0xa1, 1 },
+ { 0xf7bf, 0xf7bf, 0xbf, 1 },
+ { 0xf7e0, 0xf7f6, 0xc0, 1 },
+ { 0xf7f8, 0xf7fe, 0xd8, 1 },
+ { 0xf7ff, 0xf7ff, 0x59, 1 },
+ { 0xfb00, 0xfb00, 0x6666, 2 },
+ { 0xfb01, 0xfb01, 0x6669, 2 },
+ { 0xfb02, 0xfb02, 0x666c, 2 },
+ { 0xfb03, 0xfb03, 0x666669, 3 },
+ { 0xfb04, 0xfb04, 0x66666c, 3 },
+ { 0xfb05, 0xfb05, 0x7374, 2 },
+ { 0xfb06, 0xfb06, 0x7374, 2 }
+};
+#define latin1UnicodeMapLen (sizeof(latin1UnicodeMapRanges) / sizeof(UnicodeMapRange))
+
+static UnicodeMapRange ascii7UnicodeMapRanges[] = {
+ { 0x000a, 0x000a, 0x0a, 1 },
+ { 0x000c, 0x000d, 0x0c, 1 },
+ { 0x0020, 0x005f, 0x20, 1 },
+ { 0x0061, 0x007e, 0x61, 1 },
+ { 0x00a6, 0x00a6, 0x7c, 1 },
+ { 0x00a9, 0x00a9, 0x286329, 3 },
+ { 0x00ae, 0x00ae, 0x285229, 3 },
+ { 0x00b7, 0x00b7, 0x2a, 1 },
+ { 0x00bc, 0x00bc, 0x312f34, 3 },
+ { 0x00bd, 0x00bd, 0x312f32, 3 },
+ { 0x00be, 0x00be, 0x332f34, 3 },
+ { 0x00c0, 0x00c0, 0x41, 1 },
+ { 0x00c1, 0x00c1, 0x41, 1 },
+ { 0x00c2, 0x00c2, 0x41, 1 },
+ { 0x00c3, 0x00c3, 0x41, 1 },
+ { 0x00c4, 0x00c4, 0x41, 1 },
+ { 0x00c5, 0x00c5, 0x41, 1 },
+ { 0x00c6, 0x00c6, 0x4145, 2 },
+ { 0x00c7, 0x00c7, 0x43, 1 },
+ { 0x00c8, 0x00c8, 0x45, 1 },
+ { 0x00c9, 0x00c9, 0x45, 1 },
+ { 0x00ca, 0x00ca, 0x45, 1 },
+ { 0x00cb, 0x00cb, 0x45, 1 },
+ { 0x00cc, 0x00cc, 0x49, 1 },
+ { 0x00cd, 0x00cd, 0x49, 1 },
+ { 0x00ce, 0x00ce, 0x49, 1 },
+ { 0x00cf, 0x00cf, 0x49, 1 },
+ { 0x00d1, 0x00d2, 0x4e, 1 },
+ { 0x00d3, 0x00d3, 0x4f, 1 },
+ { 0x00d4, 0x00d4, 0x4f, 1 },
+ { 0x00d5, 0x00d5, 0x4f, 1 },
+ { 0x00d6, 0x00d6, 0x4f, 1 },
+ { 0x00d7, 0x00d7, 0x78, 1 },
+ { 0x00d8, 0x00d8, 0x4f, 1 },
+ { 0x00d9, 0x00d9, 0x55, 1 },
+ { 0x00da, 0x00da, 0x55, 1 },
+ { 0x00db, 0x00db, 0x55, 1 },
+ { 0x00dc, 0x00dc, 0x55, 1 },
+ { 0x00dd, 0x00dd, 0x59, 1 },
+ { 0x00e0, 0x00e0, 0x61, 1 },
+ { 0x00e1, 0x00e1, 0x61, 1 },
+ { 0x00e2, 0x00e2, 0x61, 1 },
+ { 0x00e3, 0x00e3, 0x61, 1 },
+ { 0x00e4, 0x00e4, 0x61, 1 },
+ { 0x00e5, 0x00e5, 0x61, 1 },
+ { 0x00e6, 0x00e6, 0x6165, 2 },
+ { 0x00e7, 0x00e7, 0x63, 1 },
+ { 0x00e8, 0x00e8, 0x65, 1 },
+ { 0x00e9, 0x00e9, 0x65, 1 },
+ { 0x00ea, 0x00ea, 0x65, 1 },
+ { 0x00eb, 0x00eb, 0x65, 1 },
+ { 0x00ec, 0x00ec, 0x69, 1 },
+ { 0x00ed, 0x00ed, 0x69, 1 },
+ { 0x00ee, 0x00ee, 0x69, 1 },
+ { 0x00ef, 0x00ef, 0x69, 1 },
+ { 0x00f1, 0x00f2, 0x6e, 1 },
+ { 0x00f3, 0x00f3, 0x6f, 1 },
+ { 0x00f4, 0x00f4, 0x6f, 1 },
+ { 0x00f5, 0x00f5, 0x6f, 1 },
+ { 0x00f6, 0x00f6, 0x6f, 1 },
+ { 0x00f7, 0x00f7, 0x2f, 1 },
+ { 0x00f8, 0x00f8, 0x6f, 1 },
+ { 0x00f9, 0x00f9, 0x75, 1 },
+ { 0x00fa, 0x00fa, 0x75, 1 },
+ { 0x00fb, 0x00fb, 0x75, 1 },
+ { 0x00fc, 0x00fc, 0x75, 1 },
+ { 0x00fd, 0x00fd, 0x79, 1 },
+ { 0x00ff, 0x00ff, 0x79, 1 },
+ { 0x0131, 0x0131, 0x69, 1 },
+ { 0x0141, 0x0141, 0x4c, 1 },
+ { 0x0152, 0x0152, 0x4f45, 2 },
+ { 0x0153, 0x0153, 0x6f65, 2 },
+ { 0x0160, 0x0160, 0x53, 1 },
+ { 0x0178, 0x0178, 0x59, 1 },
+ { 0x017d, 0x017d, 0x5a, 1 },
+ { 0x2013, 0x2013, 0x2d, 1 },
+ { 0x2014, 0x2014, 0x2d2d, 2 },
+ { 0x2018, 0x2018, 0x60, 1 },
+ { 0x2019, 0x2019, 0x27, 1 },
+ { 0x201c, 0x201c, 0x22, 1 },
+ { 0x201d, 0x201d, 0x22, 1 },
+ { 0x2022, 0x2022, 0x2a, 1 },
+ { 0x2026, 0x2026, 0x2e2e2e, 3 },
+ { 0x2122, 0x2122, 0x544d, 2 },
+ { 0x2212, 0x2212, 0x2d, 1 },
+ { 0xf6f9, 0xf6f9, 0x4c, 1 },
+ { 0xf6fa, 0xf6fa, 0x4f45, 2 },
+ { 0xf6fd, 0xf6fd, 0x53, 1 },
+ { 0xf6fe, 0xf6fe, 0x7e, 1 },
+ { 0xf6ff, 0xf6ff, 0x5a, 1 },
+ { 0xf721, 0xf721, 0x21, 1 },
+ { 0xf724, 0xf724, 0x24, 1 },
+ { 0xf726, 0xf726, 0x26, 1 },
+ { 0xf730, 0xf739, 0x30, 1 },
+ { 0xf73f, 0xf73f, 0x3f, 1 },
+ { 0xf761, 0xf77a, 0x41, 1 },
+ { 0xf7e0, 0xf7e0, 0x41, 1 },
+ { 0xf7e1, 0xf7e1, 0x41, 1 },
+ { 0xf7e2, 0xf7e2, 0x41, 1 },
+ { 0xf7e3, 0xf7e3, 0x41, 1 },
+ { 0xf7e4, 0xf7e4, 0x41, 1 },
+ { 0xf7e5, 0xf7e5, 0x41, 1 },
+ { 0xf7e6, 0xf7e6, 0x4145, 2 },
+ { 0xf7e7, 0xf7e7, 0x43, 1 },
+ { 0xf7e8, 0xf7e8, 0x45, 1 },
+ { 0xf7e9, 0xf7e9, 0x45, 1 },
+ { 0xf7ea, 0xf7ea, 0x45, 1 },
+ { 0xf7eb, 0xf7eb, 0x45, 1 },
+ { 0xf7ec, 0xf7ec, 0x49, 1 },
+ { 0xf7ed, 0xf7ed, 0x49, 1 },
+ { 0xf7ee, 0xf7ee, 0x49, 1 },
+ { 0xf7ef, 0xf7ef, 0x49, 1 },
+ { 0xf7f1, 0xf7f2, 0x4e, 1 },
+ { 0xf7f3, 0xf7f3, 0x4f, 1 },
+ { 0xf7f4, 0xf7f4, 0x4f, 1 },
+ { 0xf7f5, 0xf7f5, 0x4f, 1 },
+ { 0xf7f6, 0xf7f6, 0x4f, 1 },
+ { 0xf7f8, 0xf7f8, 0x4f, 1 },
+ { 0xf7f9, 0xf7f9, 0x55, 1 },
+ { 0xf7fa, 0xf7fa, 0x55, 1 },
+ { 0xf7fb, 0xf7fb, 0x55, 1 },
+ { 0xf7fc, 0xf7fc, 0x55, 1 },
+ { 0xf7fd, 0xf7fd, 0x59, 1 },
+ { 0xf7ff, 0xf7ff, 0x59, 1 },
+ { 0xfb00, 0xfb00, 0x6666, 2 },
+ { 0xfb01, 0xfb01, 0x6669, 2 },
+ { 0xfb02, 0xfb02, 0x666c, 2 },
+ { 0xfb03, 0xfb03, 0x666669, 3 },
+ { 0xfb04, 0xfb04, 0x66666c, 3 },
+ { 0xfb05, 0xfb05, 0x7374, 2 },
+ { 0xfb06, 0xfb06, 0x7374, 2 }
+};
+#define ascii7UnicodeMapLen (sizeof(ascii7UnicodeMapRanges) / sizeof(UnicodeMapRange))
+
+static UnicodeMapRange symbolUnicodeMapRanges[] = {
+ { 0x0020, 0x0021, 0x20, 1 },
+ { 0x0023, 0x0023, 0x23, 1 },
+ { 0x0025, 0x0026, 0x25, 1 },
+ { 0x0028, 0x0029, 0x28, 1 },
+ { 0x002b, 0x002c, 0x2b, 1 },
+ { 0x002e, 0x003f, 0x2e, 1 },
+ { 0x005b, 0x005b, 0x5b, 1 },
+ { 0x005d, 0x005d, 0x5d, 1 },
+ { 0x005f, 0x005f, 0x5f, 1 },
+ { 0x007b, 0x007d, 0x7b, 1 },
+ { 0x00ac, 0x00ac, 0xd8, 1 },
+ { 0x00b0, 0x00b1, 0xb0, 1 },
+ { 0x00b5, 0x00b5, 0x6d, 1 },
+ { 0x00d7, 0x00d7, 0xb4, 1 },
+ { 0x00f7, 0x00f7, 0xb8, 1 },
+ { 0x0192, 0x0192, 0xa6, 1 },
+ { 0x0391, 0x0392, 0x41, 1 },
+ { 0x0393, 0x0393, 0x47, 1 },
+ { 0x0395, 0x0395, 0x45, 1 },
+ { 0x0396, 0x0396, 0x5a, 1 },
+ { 0x0397, 0x0397, 0x48, 1 },
+ { 0x0398, 0x0398, 0x51, 1 },
+ { 0x0399, 0x0399, 0x49, 1 },
+ { 0x039a, 0x039d, 0x4b, 1 },
+ { 0x039e, 0x039e, 0x58, 1 },
+ { 0x039f, 0x03a0, 0x4f, 1 },
+ { 0x03a1, 0x03a1, 0x52, 1 },
+ { 0x03a3, 0x03a5, 0x53, 1 },
+ { 0x03a6, 0x03a6, 0x46, 1 },
+ { 0x03a7, 0x03a7, 0x43, 1 },
+ { 0x03a8, 0x03a8, 0x59, 1 },
+ { 0x03b1, 0x03b2, 0x61, 1 },
+ { 0x03b3, 0x03b3, 0x67, 1 },
+ { 0x03b4, 0x03b5, 0x64, 1 },
+ { 0x03b6, 0x03b6, 0x7a, 1 },
+ { 0x03b7, 0x03b7, 0x68, 1 },
+ { 0x03b8, 0x03b8, 0x71, 1 },
+ { 0x03b9, 0x03b9, 0x69, 1 },
+ { 0x03ba, 0x03bb, 0x6b, 1 },
+ { 0x03bd, 0x03bd, 0x6e, 1 },
+ { 0x03be, 0x03be, 0x78, 1 },
+ { 0x03bf, 0x03c0, 0x6f, 1 },
+ { 0x03c1, 0x03c1, 0x72, 1 },
+ { 0x03c2, 0x03c2, 0x56, 1 },
+ { 0x03c3, 0x03c5, 0x73, 1 },
+ { 0x03c6, 0x03c6, 0x66, 1 },
+ { 0x03c7, 0x03c7, 0x63, 1 },
+ { 0x03c8, 0x03c8, 0x79, 1 },
+ { 0x03c9, 0x03c9, 0x77, 1 },
+ { 0x03d1, 0x03d1, 0x4a, 1 },
+ { 0x03d2, 0x03d2, 0xa1, 1 },
+ { 0x03d5, 0x03d5, 0x6a, 1 },
+ { 0x03d6, 0x03d6, 0x76, 1 },
+ { 0x2022, 0x2022, 0xb7, 1 },
+ { 0x2026, 0x2026, 0xbc, 1 },
+ { 0x2032, 0x2032, 0xa2, 1 },
+ { 0x2033, 0x2033, 0xb2, 1 },
+ { 0x2044, 0x2044, 0xa4, 1 },
+ { 0x2111, 0x2111, 0xc1, 1 },
+ { 0x2118, 0x2118, 0xc3, 1 },
+ { 0x211c, 0x211c, 0xc2, 1 },
+ { 0x2126, 0x2126, 0x57, 1 },
+ { 0x2135, 0x2135, 0xc0, 1 },
+ { 0x2190, 0x2193, 0xac, 1 },
+ { 0x2194, 0x2194, 0xab, 1 },
+ { 0x21b5, 0x21b5, 0xbf, 1 },
+ { 0x21d0, 0x21d3, 0xdc, 1 },
+ { 0x21d4, 0x21d4, 0xdb, 1 },
+ { 0x2200, 0x2200, 0x22, 1 },
+ { 0x2202, 0x2202, 0xb6, 1 },
+ { 0x2203, 0x2203, 0x24, 1 },
+ { 0x2205, 0x2205, 0xc6, 1 },
+ { 0x2206, 0x2206, 0x44, 1 },
+ { 0x2207, 0x2207, 0xd1, 1 },
+ { 0x2208, 0x2209, 0xce, 1 },
+ { 0x220b, 0x220b, 0x27, 1 },
+ { 0x220f, 0x220f, 0xd5, 1 },
+ { 0x2211, 0x2211, 0xe5, 1 },
+ { 0x2212, 0x2212, 0x2d, 1 },
+ { 0x2217, 0x2217, 0x2a, 1 },
+ { 0x221a, 0x221a, 0xd6, 1 },
+ { 0x221d, 0x221d, 0xb5, 1 },
+ { 0x221e, 0x221e, 0xa5, 1 },
+ { 0x2220, 0x2220, 0xd0, 1 },
+ { 0x2227, 0x2228, 0xd9, 1 },
+ { 0x2229, 0x222a, 0xc7, 1 },
+ { 0x222b, 0x222b, 0xf2, 1 },
+ { 0x2234, 0x2234, 0x5c, 1 },
+ { 0x223c, 0x223c, 0x7e, 1 },
+ { 0x2245, 0x2245, 0x40, 1 },
+ { 0x2248, 0x2248, 0xbb, 1 },
+ { 0x2260, 0x2261, 0xb9, 1 },
+ { 0x2264, 0x2264, 0xa3, 1 },
+ { 0x2265, 0x2265, 0xb3, 1 },
+ { 0x2282, 0x2282, 0xcc, 1 },
+ { 0x2283, 0x2283, 0xc9, 1 },
+ { 0x2284, 0x2284, 0xcb, 1 },
+ { 0x2286, 0x2286, 0xcd, 1 },
+ { 0x2287, 0x2287, 0xca, 1 },
+ { 0x2295, 0x2295, 0xc5, 1 },
+ { 0x2297, 0x2297, 0xc4, 1 },
+ { 0x22a5, 0x22a5, 0x5e, 1 },
+ { 0x22c5, 0x22c5, 0xd7, 1 },
+ { 0x2320, 0x2320, 0xf3, 1 },
+ { 0x2321, 0x2321, 0xf5, 1 },
+ { 0x2329, 0x2329, 0xe1, 1 },
+ { 0x232a, 0x232a, 0xf1, 1 },
+ { 0x25ca, 0x25ca, 0xe0, 1 },
+ { 0x2660, 0x2660, 0xaa, 1 },
+ { 0x2663, 0x2663, 0xa7, 1 },
+ { 0x2665, 0x2665, 0xa9, 1 },
+ { 0x2666, 0x2666, 0xa8, 1 },
+ { 0xf6d9, 0xf6d9, 0xd3, 1 },
+ { 0xf6da, 0xf6da, 0xd2, 1 },
+ { 0xf6db, 0xf6db, 0xd4, 1 },
+ { 0xf8e5, 0xf8e5, 0x60, 1 },
+ { 0xf8e6, 0xf8e7, 0xbd, 1 },
+ { 0xf8e8, 0xf8ea, 0xe2, 1 },
+ { 0xf8eb, 0xf8f4, 0xe6, 1 },
+ { 0xf8f5, 0xf8f5, 0xf4, 1 },
+ { 0xf8f6, 0xf8fe, 0xf6, 1 }
+};
+#define symbolUnicodeMapLen (sizeof(symbolUnicodeMapRanges) / sizeof(UnicodeMapRange))
+
+static UnicodeMapRange zapfDingbatsUnicodeMapRanges[] = {
+ { 0x0020, 0x0020, 0x20, 1 },
+ { 0x2192, 0x2192, 0xd5, 1 },
+ { 0x2194, 0x2195, 0xd6, 1 },
+ { 0x2460, 0x2469, 0xac, 1 },
+ { 0x25a0, 0x25a0, 0x6e, 1 },
+ { 0x25b2, 0x25b2, 0x73, 1 },
+ { 0x25bc, 0x25bc, 0x74, 1 },
+ { 0x25c6, 0x25c6, 0x75, 1 },
+ { 0x25cf, 0x25cf, 0x6c, 1 },
+ { 0x25d7, 0x25d7, 0x77, 1 },
+ { 0x2605, 0x2605, 0x48, 1 },
+ { 0x260e, 0x260e, 0x25, 1 },
+ { 0x261b, 0x261b, 0x2a, 1 },
+ { 0x261e, 0x261e, 0x2b, 1 },
+ { 0x2660, 0x2660, 0xab, 1 },
+ { 0x2663, 0x2663, 0xa8, 1 },
+ { 0x2665, 0x2665, 0xaa, 1 },
+ { 0x2666, 0x2666, 0xa9, 1 },
+ { 0x2701, 0x2704, 0x21, 1 },
+ { 0x2706, 0x2709, 0x26, 1 },
+ { 0x270c, 0x2727, 0x2c, 1 },
+ { 0x2729, 0x274b, 0x49, 1 },
+ { 0x274d, 0x274d, 0x6d, 1 },
+ { 0x274f, 0x2752, 0x6f, 1 },
+ { 0x2756, 0x2756, 0x76, 1 },
+ { 0x2758, 0x275e, 0x78, 1 },
+ { 0x2761, 0x2767, 0xa1, 1 },
+ { 0x2776, 0x2794, 0xb6, 1 },
+ { 0x2798, 0x27af, 0xd8, 1 },
+ { 0x27b1, 0x27be, 0xf1, 1 }
+};
+#define zapfDingbatsUnicodeMapLen (sizeof(zapfDingbatsUnicodeMapRanges) / sizeof(UnicodeMapRange))
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeTypeTable.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeTypeTable.cc
new file mode 100644
index 00000000000..721af9db6e5
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeTypeTable.cc
@@ -0,0 +1,1223 @@
+//========================================================================
+//
+// UnicodeTypeTable.cc
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2007 Ed Catmur <ed@catmur.co.uk>
+// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
+// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <stdlib.h>
+#include "CharTypes.h"
+#include "UnicodeTypeTable.h"
+#include "goo/gmem.h"
+
+struct UnicodeMapTableEntry {
+ const char *vector;
+ const char type;
+};
+
+struct UnicodeCaseTableVector {
+ Unicode codes[256];
+};
+
+static const UnicodeMapTableEntry typeTable[256] = {
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN###NNNNN################NNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN#N####NNNNLNNNNN####NLNNN#LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL", 'X' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLNNNNNNNNNNNNNNLLNNNNNNNNNNNNNNLLLLLNNNNNNNNNLNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLNNNNNNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' },
+ { "RRRR#########RNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNN####################RRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNRNNNNNNNRRNNNNNNNRR##########RRRRRR", 'X' },
+ { "RRRRRRRRRRRRRRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'N' },
+ { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLNNNNLLLLLLLLLLLLLNNLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNLLLLLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLL##LLLLLLLNNNNN", 'X' },
+ { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLL##NNNNNNNNNNNNNN", 'X' },
+ { "NNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLNLNNNLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNN#NLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNN#####LLLLLLLNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNLNNNNNLNNLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLNLLNNNNNNNNNNNLLLLLLL#LNLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLNNNNNLLLLLLNLLLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNNNLLLLLLLLLLLNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLNNNLLLLLLLLLLLLLNNN", 'X' },
+ { "NNNNNNNNNNNNNNLRNNNNNNNNNNNNNNNNNNNNNNNNNNLRNLRN#####NNNNNNNNNNNNNNN#NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN#L##########NNNL############NNN###################################NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNLNNNNLNNLLLLLLLLLLNLNNNLLLLLNNNNNNLNLNLNLLLL#LLLNLLLLLLLNNLLLLNNNNNLLLLLNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNN##NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN####################LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'L' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { "NNNNNLLLNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNNNNNNNLLLLLNNLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLL", 'X' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLRRRRRRNRRRRRRRRRR#RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' },
+ { NULL, 'R' },
+ { "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN#N#NN#NNNNNNNNN#NN##NNNNN##NRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' },
+ { "NNN###NNNNN################NNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#####NNN##NNNNNNNNNNNNNNNNNNNNNNNLL", 'X' }
+};
+
+static const UnicodeCaseTableVector caseTable00 = {{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+}};
+static const UnicodeCaseTableVector caseTable01 = {{
+ 0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107,
+ 0x0109, 0x0109, 0x010b, 0x010b, 0x010d, 0x010d, 0x010f, 0x010f,
+ 0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117,
+ 0x0119, 0x0119, 0x011b, 0x011b, 0x011d, 0x011d, 0x011f, 0x011f,
+ 0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127,
+ 0x0129, 0x0129, 0x012b, 0x012b, 0x012d, 0x012d, 0x012f, 0x012f,
+ 0x0130, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137,
+ 0x0138, 0x013a, 0x013a, 0x013c, 0x013c, 0x013e, 0x013e, 0x0140,
+ 0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148,
+ 0x0148, 0x0149, 0x014b, 0x014b, 0x014d, 0x014d, 0x014f, 0x014f,
+ 0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157,
+ 0x0159, 0x0159, 0x015b, 0x015b, 0x015d, 0x015d, 0x015f, 0x015f,
+ 0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167,
+ 0x0169, 0x0169, 0x016b, 0x016b, 0x016d, 0x016d, 0x016f, 0x016f,
+ 0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177,
+ 0x00ff, 0x017a, 0x017a, 0x017c, 0x017c, 0x017e, 0x017e, 0x0073,
+ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
+ 0x0188, 0x0256, 0x0257, 0x018c, 0x018c, 0x018d, 0x01dd, 0x0259,
+ 0x025b, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
+ 0x0199, 0x0199, 0x019a, 0x019b, 0x026f, 0x0272, 0x019e, 0x0275,
+ 0x01a1, 0x01a1, 0x01a3, 0x01a3, 0x01a5, 0x01a5, 0x0280, 0x01a8,
+ 0x01a8, 0x0283, 0x01aa, 0x01ab, 0x01ad, 0x01ad, 0x0288, 0x01b0,
+ 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b4, 0x01b6, 0x01b6, 0x0292,
+ 0x01b9, 0x01b9, 0x01ba, 0x01bb, 0x01bd, 0x01bd, 0x01be, 0x01bf,
+ 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c6, 0x01c6, 0x01c6, 0x01c9,
+ 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01cc, 0x01ce, 0x01ce, 0x01d0,
+ 0x01d0, 0x01d2, 0x01d2, 0x01d4, 0x01d4, 0x01d6, 0x01d6, 0x01d8,
+ 0x01d8, 0x01da, 0x01da, 0x01dc, 0x01dc, 0x01dd, 0x01df, 0x01df,
+ 0x01e1, 0x01e1, 0x01e3, 0x01e3, 0x01e5, 0x01e5, 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9, 0x01eb, 0x01eb, 0x01ed, 0x01ed, 0x01ef, 0x01ef,
+ 0x01f0, 0x01f3, 0x01f3, 0x01f3, 0x01f5, 0x01f5, 0x0195, 0x01bf,
+ 0x01f9, 0x01f9, 0x01fb, 0x01fb, 0x01fd, 0x01fd, 0x01ff, 0x01ff
+}};
+static const UnicodeCaseTableVector caseTable02 = {{
+ 0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207,
+ 0x0209, 0x0209, 0x020b, 0x020b, 0x020d, 0x020d, 0x020f, 0x020f,
+ 0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217,
+ 0x0219, 0x0219, 0x021b, 0x021b, 0x021d, 0x021d, 0x021f, 0x021f,
+ 0x019e, 0x0221, 0x0223, 0x0223, 0x0225, 0x0225, 0x0227, 0x0227,
+ 0x0229, 0x0229, 0x022b, 0x022b, 0x022d, 0x022d, 0x022f, 0x022f,
+ 0x0231, 0x0231, 0x0233, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237,
+ 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f,
+ 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247,
+ 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f,
+ 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257,
+ 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f,
+ 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267,
+ 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f,
+ 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277,
+ 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f,
+ 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287,
+ 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f,
+ 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297,
+ 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f,
+ 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7,
+ 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af,
+ 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7,
+ 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf,
+ 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7,
+ 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf,
+ 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7,
+ 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df,
+ 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7,
+ 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef,
+ 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7,
+ 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff
+}};
+static const UnicodeCaseTableVector caseTable03 = {{
+ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
+ 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f,
+ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
+ 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f,
+ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
+ 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f,
+ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
+ 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f,
+ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x03b9, 0x0346, 0x0347,
+ 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f,
+ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
+ 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f,
+ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
+ 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f,
+ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
+ 0x0378, 0x0379, 0x037a, 0x037b, 0x037c, 0x037d, 0x037e, 0x037f,
+ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x03ac, 0x0387,
+ 0x03ad, 0x03ae, 0x03af, 0x038b, 0x03cc, 0x038d, 0x03cd, 0x03ce,
+ 0x0390, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+ 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+ 0x03c0, 0x03c1, 0x03a2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+ 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03ac, 0x03ad, 0x03ae, 0x03af,
+ 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+ 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+ 0x03c0, 0x03c1, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+ 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf,
+ 0x03b2, 0x03b8, 0x03d2, 0x03d3, 0x03d4, 0x03c6, 0x03c0, 0x03d7,
+ 0x03d9, 0x03d9, 0x03db, 0x03db, 0x03dd, 0x03dd, 0x03df, 0x03df,
+ 0x03e1, 0x03e1, 0x03e3, 0x03e3, 0x03e5, 0x03e5, 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9, 0x03eb, 0x03eb, 0x03ed, 0x03ed, 0x03ef, 0x03ef,
+ 0x03ba, 0x03c1, 0x03f2, 0x03f3, 0x03b8, 0x03b5, 0x03f6, 0x03f8,
+ 0x03f8, 0x03f2, 0x03fb, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff
+}};
+static const UnicodeCaseTableVector caseTable04 = {{
+ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f,
+ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,
+ 0x0469, 0x0469, 0x046b, 0x046b, 0x046d, 0x046d, 0x046f, 0x046f,
+ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477,
+ 0x0479, 0x0479, 0x047b, 0x047b, 0x047d, 0x047d, 0x047f, 0x047f,
+ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
+ 0x0488, 0x0489, 0x048b, 0x048b, 0x048d, 0x048d, 0x048f, 0x048f,
+ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,
+ 0x0499, 0x0499, 0x049b, 0x049b, 0x049d, 0x049d, 0x049f, 0x049f,
+ 0x04a1, 0x04a1, 0x04a3, 0x04a3, 0x04a5, 0x04a5, 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9, 0x04ab, 0x04ab, 0x04ad, 0x04ad, 0x04af, 0x04af,
+ 0x04b1, 0x04b1, 0x04b3, 0x04b3, 0x04b5, 0x04b5, 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9, 0x04bb, 0x04bb, 0x04bd, 0x04bd, 0x04bf, 0x04bf,
+ 0x04c0, 0x04c2, 0x04c2, 0x04c4, 0x04c4, 0x04c6, 0x04c6, 0x04c8,
+ 0x04c8, 0x04ca, 0x04ca, 0x04cc, 0x04cc, 0x04ce, 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1, 0x04d3, 0x04d3, 0x04d5, 0x04d5, 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9, 0x04db, 0x04db, 0x04dd, 0x04dd, 0x04df, 0x04df,
+ 0x04e1, 0x04e1, 0x04e3, 0x04e3, 0x04e5, 0x04e5, 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9, 0x04eb, 0x04eb, 0x04ed, 0x04ed, 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1, 0x04f3, 0x04f3, 0x04f5, 0x04f5, 0x04f6, 0x04f7,
+ 0x04f9, 0x04f9, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff
+}};
+static const UnicodeCaseTableVector caseTable05 = {{
+ 0x0501, 0x0501, 0x0503, 0x0503, 0x0505, 0x0505, 0x0507, 0x0507,
+ 0x0509, 0x0509, 0x050b, 0x050b, 0x050d, 0x050d, 0x050f, 0x050f,
+ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,
+ 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f,
+ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
+ 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f,
+ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+ 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f,
+ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+ 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f,
+ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,
+ 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f,
+ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+ 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f,
+ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+ 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f,
+ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587,
+ 0x0588, 0x0589, 0x058a, 0x058b, 0x058c, 0x058d, 0x058e, 0x058f,
+ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,
+ 0x0598, 0x0599, 0x059a, 0x059b, 0x059c, 0x059d, 0x059e, 0x059f,
+ 0x05a0, 0x05a1, 0x05a2, 0x05a3, 0x05a4, 0x05a5, 0x05a6, 0x05a7,
+ 0x05a8, 0x05a9, 0x05aa, 0x05ab, 0x05ac, 0x05ad, 0x05ae, 0x05af,
+ 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7,
+ 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf,
+ 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7,
+ 0x05c8, 0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf,
+ 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+ 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+ 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+ 0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed, 0x05ee, 0x05ef,
+ 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x05f5, 0x05f6, 0x05f7,
+ 0x05f8, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x05ff
+}};
+static const UnicodeCaseTableVector caseTable1e = {{
+ 0x1e01, 0x1e01, 0x1e03, 0x1e03, 0x1e05, 0x1e05, 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09, 0x1e0b, 0x1e0b, 0x1e0d, 0x1e0d, 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11, 0x1e13, 0x1e13, 0x1e15, 0x1e15, 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19, 0x1e1b, 0x1e1b, 0x1e1d, 0x1e1d, 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21, 0x1e23, 0x1e23, 0x1e25, 0x1e25, 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29, 0x1e2b, 0x1e2b, 0x1e2d, 0x1e2d, 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31, 0x1e33, 0x1e33, 0x1e35, 0x1e35, 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39, 0x1e3b, 0x1e3b, 0x1e3d, 0x1e3d, 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41, 0x1e43, 0x1e43, 0x1e45, 0x1e45, 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49, 0x1e4b, 0x1e4b, 0x1e4d, 0x1e4d, 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51, 0x1e53, 0x1e53, 0x1e55, 0x1e55, 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59, 0x1e5b, 0x1e5b, 0x1e5d, 0x1e5d, 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61, 0x1e63, 0x1e63, 0x1e65, 0x1e65, 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69, 0x1e6b, 0x1e6b, 0x1e6d, 0x1e6d, 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71, 0x1e73, 0x1e73, 0x1e75, 0x1e75, 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79, 0x1e7b, 0x1e7b, 0x1e7d, 0x1e7d, 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81, 0x1e83, 0x1e83, 0x1e85, 0x1e85, 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89, 0x1e8b, 0x1e8b, 0x1e8d, 0x1e8d, 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91, 0x1e93, 0x1e93, 0x1e95, 0x1e95, 0x1e96, 0x1e97,
+ 0x1e98, 0x1e99, 0x1e9a, 0x1e61, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f,
+ 0x1ea1, 0x1ea1, 0x1ea3, 0x1ea3, 0x1ea5, 0x1ea5, 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9, 0x1eab, 0x1eab, 0x1ead, 0x1ead, 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1, 0x1eb3, 0x1eb3, 0x1eb5, 0x1eb5, 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9, 0x1ebb, 0x1ebb, 0x1ebd, 0x1ebd, 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1, 0x1ec3, 0x1ec3, 0x1ec5, 0x1ec5, 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9, 0x1ecb, 0x1ecb, 0x1ecd, 0x1ecd, 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1, 0x1ed3, 0x1ed3, 0x1ed5, 0x1ed5, 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9, 0x1edb, 0x1edb, 0x1edd, 0x1edd, 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1, 0x1ee3, 0x1ee3, 0x1ee5, 0x1ee5, 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9, 0x1eeb, 0x1eeb, 0x1eed, 0x1eed, 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1, 0x1ef3, 0x1ef3, 0x1ef5, 0x1ef5, 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff
+}};
+static const UnicodeCaseTableVector caseTable1f = {{
+ 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07,
+ 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07,
+ 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f16, 0x1f17,
+ 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f1e, 0x1f1f,
+ 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27,
+ 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27,
+ 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37,
+ 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37,
+ 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f46, 0x1f47,
+ 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f4e, 0x1f4f,
+ 0x1f50, 0x1f51, 0x1f52, 0x1f53, 0x1f54, 0x1f55, 0x1f56, 0x1f57,
+ 0x1f58, 0x1f51, 0x1f5a, 0x1f53, 0x1f5c, 0x1f55, 0x1f5e, 0x1f57,
+ 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67,
+ 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67,
+ 0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77,
+ 0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f7e, 0x1f7f,
+ 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87,
+ 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87,
+ 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97,
+ 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97,
+ 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7,
+ 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7,
+ 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7,
+ 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1fbd, 0x03b9, 0x1fbf,
+ 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7,
+ 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf,
+ 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7,
+ 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf,
+ 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, 0x1fe6, 0x1fe7,
+ 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1fed, 0x1fee, 0x1fef,
+ 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7,
+ 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff
+}};
+static const UnicodeCaseTableVector caseTable21 = {{
+ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107,
+ 0x2108, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f,
+ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117,
+ 0x2118, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x211e, 0x211f,
+ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x03c9, 0x2127,
+ 0x2128, 0x2129, 0x006b, 0x00e5, 0x212c, 0x212d, 0x212e, 0x212f,
+ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137,
+ 0x2138, 0x2139, 0x213a, 0x213b, 0x213c, 0x213d, 0x213e, 0x213f,
+ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,
+ 0x2148, 0x2149, 0x214a, 0x214b, 0x214c, 0x214d, 0x214e, 0x214f,
+ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,
+ 0x2158, 0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x215f,
+ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+ 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f,
+ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+ 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f,
+ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187,
+ 0x2188, 0x2189, 0x218a, 0x218b, 0x218c, 0x218d, 0x218e, 0x218f,
+ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197,
+ 0x2198, 0x2199, 0x219a, 0x219b, 0x219c, 0x219d, 0x219e, 0x219f,
+ 0x21a0, 0x21a1, 0x21a2, 0x21a3, 0x21a4, 0x21a5, 0x21a6, 0x21a7,
+ 0x21a8, 0x21a9, 0x21aa, 0x21ab, 0x21ac, 0x21ad, 0x21ae, 0x21af,
+ 0x21b0, 0x21b1, 0x21b2, 0x21b3, 0x21b4, 0x21b5, 0x21b6, 0x21b7,
+ 0x21b8, 0x21b9, 0x21ba, 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf,
+ 0x21c0, 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7,
+ 0x21c8, 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf,
+ 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x21d5, 0x21d6, 0x21d7,
+ 0x21d8, 0x21d9, 0x21da, 0x21db, 0x21dc, 0x21dd, 0x21de, 0x21df,
+ 0x21e0, 0x21e1, 0x21e2, 0x21e3, 0x21e4, 0x21e5, 0x21e6, 0x21e7,
+ 0x21e8, 0x21e9, 0x21ea, 0x21eb, 0x21ec, 0x21ed, 0x21ee, 0x21ef,
+ 0x21f0, 0x21f1, 0x21f2, 0x21f3, 0x21f4, 0x21f5, 0x21f6, 0x21f7,
+ 0x21f8, 0x21f9, 0x21fa, 0x21fb, 0x21fc, 0x21fd, 0x21fe, 0x21ff
+}};
+static const UnicodeCaseTableVector caseTable24 = {{
+ 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407,
+ 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f,
+ 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417,
+ 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f,
+ 0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427,
+ 0x2428, 0x2429, 0x242a, 0x242b, 0x242c, 0x242d, 0x242e, 0x242f,
+ 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437,
+ 0x2438, 0x2439, 0x243a, 0x243b, 0x243c, 0x243d, 0x243e, 0x243f,
+ 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447,
+ 0x2448, 0x2449, 0x244a, 0x244b, 0x244c, 0x244d, 0x244e, 0x244f,
+ 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457,
+ 0x2458, 0x2459, 0x245a, 0x245b, 0x245c, 0x245d, 0x245e, 0x245f,
+ 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467,
+ 0x2468, 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f,
+ 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477,
+ 0x2478, 0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f,
+ 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487,
+ 0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e, 0x248f,
+ 0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497,
+ 0x2498, 0x2499, 0x249a, 0x249b, 0x249c, 0x249d, 0x249e, 0x249f,
+ 0x24a0, 0x24a1, 0x24a2, 0x24a3, 0x24a4, 0x24a5, 0x24a6, 0x24a7,
+ 0x24a8, 0x24a9, 0x24aa, 0x24ab, 0x24ac, 0x24ad, 0x24ae, 0x24af,
+ 0x24b0, 0x24b1, 0x24b2, 0x24b3, 0x24b4, 0x24b5, 0x24d0, 0x24d1,
+ 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9,
+ 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1,
+ 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9,
+ 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7,
+ 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df,
+ 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7,
+ 0x24e8, 0x24e9, 0x24ea, 0x24eb, 0x24ec, 0x24ed, 0x24ee, 0x24ef,
+ 0x24f0, 0x24f1, 0x24f2, 0x24f3, 0x24f4, 0x24f5, 0x24f6, 0x24f7,
+ 0x24f8, 0x24f9, 0x24fa, 0x24fb, 0x24fc, 0x24fd, 0x24fe, 0x24ff
+}};
+static const UnicodeCaseTableVector caseTableff = {{
+ 0xff00, 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07,
+ 0xff08, 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f,
+ 0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17,
+ 0xff18, 0xff19, 0xff1a, 0xff1b, 0xff1c, 0xff1d, 0xff1e, 0xff1f,
+ 0xff20, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47,
+ 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f,
+ 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57,
+ 0xff58, 0xff59, 0xff5a, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff3f,
+ 0xff40, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47,
+ 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f,
+ 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57,
+ 0xff58, 0xff59, 0xff5a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f,
+ 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67,
+ 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
+ 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77,
+ 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f,
+ 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87,
+ 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f,
+ 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97,
+ 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f,
+ 0xffa0, 0xffa1, 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7,
+ 0xffa8, 0xffa9, 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf,
+ 0xffb0, 0xffb1, 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7,
+ 0xffb8, 0xffb9, 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf,
+ 0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7,
+ 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf,
+ 0xffd0, 0xffd1, 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7,
+ 0xffd8, 0xffd9, 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf,
+ 0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7,
+ 0xffe8, 0xffe9, 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef,
+ 0xfff0, 0xfff1, 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7,
+ 0xfff8, 0xfff9, 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff
+}};
+static const UnicodeCaseTableVector *caseTable[256] = {
+ &caseTable00,
+ &caseTable01,
+ &caseTable02,
+ &caseTable03,
+ &caseTable04,
+ &caseTable05,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &caseTable1e,
+ &caseTable1f,
+ NULL,
+ &caseTable21,
+ NULL,
+ NULL,
+ &caseTable24,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &caseTableff
+};
+
+static inline char getType(Unicode c) {
+ int i;
+ char type;
+
+ if (c > 0xffff) {
+ type = 'X';
+ } else {
+ i = (c >> 8) & 0xff;
+ if ((type = typeTable[i].type) == 'X') {
+ type = typeTable[i].vector[c & 0xff];
+ }
+ }
+ return type;
+}
+
+GBool unicodeTypeL(Unicode c) {
+ return getType(c) == 'L';
+}
+
+GBool unicodeTypeR(Unicode c) {
+ return getType(c) == 'R';
+}
+
+GBool unicodeTypeNum(Unicode c) {
+ return getType(c) == '#';
+}
+
+GBool unicodeTypeAlphaNum(Unicode c) {
+ char t;
+
+ t = getType(c);
+ return t == 'L' || t == 'R' || t == '#';
+}
+
+#define UNICODE_ALPHABETIC_PRESENTATION_BLOCK_BEGIN 0xFB00
+#define UNICODE_ALPHABETIC_PRESENTATION_BLOCK_END 0xFB4F
+
+GBool unicodeIsAlphabeticPresentationForm(Unicode c) {
+ return c >= UNICODE_ALPHABETIC_PRESENTATION_BLOCK_BEGIN
+ && c <= UNICODE_ALPHABETIC_PRESENTATION_BLOCK_END;
+}
+
+Unicode unicodeToUpper(Unicode c) {
+ int i;
+
+ if (c > 0xffff) {
+ return c;
+ }
+ i = (c >> 8) & 0xff;
+ if (caseTable[i]) {
+ return caseTable[i]->codes[c & 0xff];
+ }
+ return c;
+}
+
+#define UNICODE_LAST_CHAR 0x10FFFF
+#define UNICODE_MAX_TABLE_INDEX (UNICODE_LAST_CHAR / 256 + 1)
+// large empty block between U+2FA1D and U+E0001
+#define UNICODE_LAST_CHAR_PART1 0x2FAFF
+#define UNICODE_LAST_PAGE_PART1 (UNICODE_LAST_CHAR_PART1 / 256)
+#define UNICODE_PART2_START 0xE0000
+
+#include "UnicodeCClassTables.h"
+#include "UnicodeCompTables.h"
+#include "UnicodeDecompTables.h"
+
+#define CC_PART1(Page, Char) \
+ ((combining_class_table_part1[Page] >= UNICODE_MAX_TABLE_INDEX) \
+ ? (combining_class_table_part1[Page] - UNICODE_MAX_TABLE_INDEX) \
+ : (cclass_data[combining_class_table_part1[Page]][Char]))
+
+#define CC_PART2(Page, Char) \
+ ((combining_class_table_part2[Page] >= UNICODE_MAX_TABLE_INDEX) \
+ ? (combining_class_table_part2[Page] - UNICODE_MAX_TABLE_INDEX) \
+ : (cclass_data[combining_class_table_part2[Page]][Char]))
+
+#define COMBINING_CLASS(u) (((u) <= UNICODE_LAST_CHAR_PART1) \
+ ? CC_PART1((u) / 256, (u) % 256) \
+ : (((u) >= UNICODE_PART2_START && (u) <= UNICODE_LAST_CHAR) \
+ ? CC_PART2(((u) - UNICODE_PART2_START) / 256, (u) % 256) \
+ : 0))
+
+// Write the compatibility decomposition of @u into @buf, returning the number
+// of characters written. @buf may be NULL, in which case the length of the
+// decomposition is returned but nothing is written. If @u is its own
+// decomposition, write @u into @buf and return 1.
+static int decomp_compat(Unicode u, Unicode *buf) {
+ // decomposition tables stored as lists {character, decomp_length, offset}
+ // so we do a binary search
+ int start = 0, end = DECOMP_TABLE_LENGTH;
+ if (u >= decomp_table[start].character
+ && u <= decomp_table[end - 1].character)
+ while (gTrue) {
+ int midpoint = (start + end) / 2;
+ if (u == decomp_table[midpoint].character) {
+ int offset = decomp_table[midpoint].offset;
+ if (offset == -1)
+ break;
+ else {
+ int length = decomp_table[midpoint].length, i;
+ if (buf)
+ for (i = 0; i < length; ++i)
+ buf[i] = decomp_expansion[offset + i];
+ return length;
+ }
+ } else if (midpoint == start)
+ break;
+ else if (u > decomp_table[midpoint].character)
+ start = midpoint;
+ else
+ end = midpoint;
+ }
+ if (buf)
+ *buf = u;
+ return 1;
+}
+
+#define CI(Page, Char) \
+ ((compose_table[Page] >= UNICODE_MAX_TABLE_INDEX) \
+ ? (compose_table[Page] - UNICODE_MAX_TABLE_INDEX) \
+ : (compose_data[compose_table[Page]][Char]))
+
+#define COMPOSE_INDEX(u) \
+ ((((u) / 256) > (COMPOSE_TABLE_LAST)) ? 0 : CI((u) / 256, (u) % 256))
+
+// If @add combines with @base, write the combination to @out and return
+// gTrue. Otherwise return gFalse.
+static GBool combine(Unicode base, Unicode add, Unicode *out) {
+ unsigned short idx_base, idx_add;
+
+ idx_base = COMPOSE_INDEX(base);
+ if (idx_base >= COMPOSE_FIRST_SINGLE_START
+ && idx_base < COMPOSE_SECOND_START) {
+ if (compose_first_single[idx_base - COMPOSE_FIRST_SINGLE_START][0]
+ == add) {
+ *out = compose_first_single[idx_base - COMPOSE_FIRST_SINGLE_START][1];
+ return gTrue;
+ } else
+ return gFalse;
+ }
+
+ idx_add = COMPOSE_INDEX(add);
+ if (idx_add >= COMPOSE_SECOND_SINGLE_START) {
+ if (compose_second_single[idx_add - COMPOSE_SECOND_SINGLE_START][0]
+ == base) {
+ *out = compose_second_single[idx_add - COMPOSE_SECOND_SINGLE_START][1];
+ return gTrue;
+ } else
+ return gFalse;
+ }
+
+ if (idx_base >= COMPOSE_FIRST_START && idx_base < COMPOSE_FIRST_SINGLE_START
+ && idx_add >= COMPOSE_SECOND_START
+ && idx_add < COMPOSE_SECOND_SINGLE_START) {
+ Unicode o = compose_array[idx_base - COMPOSE_FIRST_START]
+ [idx_add - COMPOSE_SECOND_START];
+ if (o) {
+ *out = o;
+ return gTrue;
+ }
+ }
+
+ return gFalse;
+}
+
+#define HANGUL_S_BASE 0xAC00
+#define HANGUL_L_BASE 0x1100
+#define HANGUL_V_BASE 0x1161
+#define HANGUL_T_BASE 0x11A7
+#define HANGUL_L_COUNT 19
+#define HANGUL_V_COUNT 21
+#define HANGUL_T_COUNT 28
+#define HANGUL_S_COUNT (HANGUL_L_COUNT * HANGUL_V_COUNT * HANGUL_T_COUNT)
+#define HANGUL_N_COUNT (HANGUL_V_COUNT * HANGUL_T_COUNT)
+#define HANGUL_IS_L(u) (((u) >= HANGUL_L_BASE) \
+ && ((u) < HANGUL_L_BASE + HANGUL_L_COUNT))
+#define HANGUL_IS_V(u) (((u) >= HANGUL_V_BASE) \
+ && ((u) < HANGUL_V_BASE + HANGUL_V_COUNT))
+#define HANGUL_IS_T(u) (((u) >= HANGUL_T_BASE) \
+ && ((u) < HANGUL_T_BASE + HANGUL_T_COUNT))
+#define HANGUL_IS_SYLLABLE(u) (((u) >= HANGUL_S_BASE) \
+ && ((u) < HANGUL_S_BASE + HANGUL_S_COUNT))
+#define HANGUL_SYLLABLE_IS_LV(u) (((u) - HANGUL_S_BASE) % HANGUL_T_COUNT == 0)
+#define IS_HANGUL(u) (HANGUL_IS_L(u) || HANGUL_IS_V(u) || HANGUL_IS_T(u) \
+ || HANGUL_IS_SYLLABLE(u))
+#define HANGUL_COMPOSE_L_V(l, v) (HANGUL_S_BASE + (HANGUL_T_COUNT * \
+ (((v) - HANGUL_V_BASE) + (HANGUL_V_COUNT * ((l) - HANGUL_L_BASE)))))
+#define HANGUL_COMPOSE_LV_T(lv, t) ((lv) + ((t) - HANGUL_T_BASE))
+
+// Converts Unicode string @in of length @len to its normalization in form
+// NFKC (compatibility decomposition + canonical composition). The length of
+// the resulting Unicode string is returned in @out_len. If non-NULL, @indices
+// is assigned the location of a newly-allocated array of length @out_len + 1,
+// for each character in the normalized string giving the index in @in of the
+// corresponding unnormalized character. @indices is not guaranteed monotone or
+// onto.
+Unicode *unicodeNormalizeNFKC(Unicode *in, int len,
+ int *out_len, int **indices) {
+ Unicode *out;
+ int i, o, *classes, *idx = NULL;
+
+ for (i = 0, o = 0; i < len; ++i) {
+ if (HANGUL_IS_L(in[i]) || HANGUL_IS_SYLLABLE(in[i])) {
+ o += 1;
+ } else
+ o += decomp_compat(in[i], NULL);
+ }
+
+ out = (Unicode *) gmallocn(o, sizeof(Unicode));
+ classes = (int *) gmallocn(o, sizeof(int));
+ if (indices)
+ idx = (int *) gmallocn(o + 1, sizeof(int));
+
+ for (i = 0, o = 0; i < len; ) {
+ Unicode u = in[i];
+ if (IS_HANGUL(u)) {
+ if (HANGUL_IS_L(u)) {
+ Unicode l = u;
+ if (i+1 < len && HANGUL_IS_V(in[i+1])) {
+ Unicode lv = HANGUL_COMPOSE_L_V(l, in[++i]);
+ if (i+1 < len && HANGUL_IS_T(in[i+1]))
+ out[o] = HANGUL_COMPOSE_LV_T(lv, in[++i]);
+ else
+ out[o] = lv;
+ } else
+ out[o] = l;
+ } else if (HANGUL_SYLLABLE_IS_LV(u)) {
+ Unicode lv = u;
+ if (i+1 < len && HANGUL_IS_T(in[i+1]))
+ out[o] = HANGUL_COMPOSE_LV_T(lv, in[++i]);
+ else
+ out[o] = lv;
+ } else
+ out[o] = u;
+ if (indices)
+ idx[o] = i;
+ ++i; ++o;
+ } else {
+ int j, p, q, r, s, dlen;
+ // write compatibility decompositions into out (we have enough space)
+ // chomp in until a starter is reached
+ for (j = i, p = o; j < len; ++j) {
+ u = in[j];
+ if (j != i && COMBINING_CLASS(u) == 0)
+ break;
+ dlen = decomp_compat(u, out + p);
+ for (q = p; q < p + dlen; ++q) {
+ classes[q] = COMBINING_CLASS(out[q]);
+ if (indices)
+ idx[q] = j;
+ }
+ p += dlen;
+ }
+ // put out[o, p) in canonical ordering
+ for (q = o + 1; q < p; ++q)
+ for (r = q; r > o + 1; --r) { // FIXME worth using a better sort?
+ int swap;
+ if (classes[r] >= classes[r-1])
+ break;
+ u = out[r]; out[r] = out[r - 1]; out[r - 1] = u;
+ swap = classes[r]; classes[r] = classes[r - 1]; classes[r - 1] = swap;
+ if (indices) {
+ swap = idx[r];
+ idx[r] = idx[r - 1];
+ idx[r - 1] = swap;
+ }
+ }
+ // canonical compose out[o, p)
+ for (q = o + 1; q < p; ++q)
+ if (!combine(out[o], out[q], &out[o]))
+ break;
+ // move out[q, p) back to [o+1, ?)
+ if (q != o + 1)
+ for (r = q, s = o + 1; r < p; ++r, ++s) {
+ out[s] = out[r];
+ if (indices)
+ idx[s] = idx[r];
+ }
+ else
+ s = p;
+ i = j; o = s;
+ }
+ }
+
+ *out_len = o;
+ gfree(classes);
+ if (indices) {
+ idx[o] = len;
+ *indices = idx;
+ }
+ return out;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeTypeTable.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeTypeTable.h
new file mode 100644
index 00000000000..869aad9e6c6
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/UnicodeTypeTable.h
@@ -0,0 +1,44 @@
+//========================================================================
+//
+// UnicodeTypeTable.h
+//
+// Copyright 2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Ed Catmur <ed@catmur.co.uk>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef UNICODETYPETABLE_H
+#define UNICODETYPETABLE_H
+
+#include "goo/gtypes.h"
+
+extern GBool unicodeTypeL(Unicode c);
+
+extern GBool unicodeTypeR(Unicode c);
+
+extern GBool unicodeTypeNum(Unicode c);
+
+extern GBool unicodeTypeAlphaNum(Unicode c);
+
+extern GBool unicodeIsAlphabeticPresentationForm(Unicode c);
+
+extern Unicode unicodeToUpper(Unicode c);
+
+extern Unicode *unicodeNormalizeNFKC(Unicode *in, int len,
+ int *out_len, int **offsets);
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/ViewerPreferences.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/ViewerPreferences.cc
new file mode 100644
index 00000000000..cba8d0ac512
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/ViewerPreferences.cc
@@ -0,0 +1,117 @@
+//========================================================================
+//
+// ViewerPreferences.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2011 Pino Toscano <pino@kde.org>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "ViewerPreferences.h"
+
+#include "Object.h"
+#include "Dict.h"
+
+ViewerPreferences::ViewerPreferences(Dict *prefDict)
+{
+ init();
+
+ Object obj;
+
+ if (prefDict->lookup("HideToolbar", &obj)->isBool()) {
+ hideToolbar = obj.getBool();
+ }
+ obj.free();
+
+ if (prefDict->lookup("HideMenubar", &obj)->isBool()) {
+ hideMenubar = obj.getBool();
+ }
+ obj.free();
+
+ if (prefDict->lookup("HideWindowUI", &obj)->isBool()) {
+ hideWindowUI = obj.getBool();
+ }
+ obj.free();
+
+ if (prefDict->lookup("FitWindow", &obj)->isBool()) {
+ fitWindow = obj.getBool();
+ }
+ obj.free();
+
+ if (prefDict->lookup("CenterWindow", &obj)->isBool()) {
+ centerWindow = obj.getBool();
+ }
+ obj.free();
+
+ if (prefDict->lookup("DisplayDocTitle", &obj)->isBool()) {
+ displayDocTitle = obj.getBool();
+ }
+ obj.free();
+
+ if (prefDict->lookup("NonFullScreenPageMode", &obj)->isName()) {
+ const char *mode = obj.getName();
+ if (!strcmp(mode, "UseNone")) {
+ nonFullScreenPageMode = nfpmUseNone;
+ } else if (!strcmp(mode, "UseOutlines")) {
+ nonFullScreenPageMode = nfpmUseOutlines;
+ } else if (!strcmp(mode, "UseThumbs")) {
+ nonFullScreenPageMode = nfpmUseThumbs;
+ } else if (!strcmp(mode, "UseOC")) {
+ nonFullScreenPageMode = nfpmUseOC;
+ }
+ }
+ obj.free();
+
+ if (prefDict->lookup("Direction", &obj)->isName()) {
+ const char *dir = obj.getName();
+ if (!strcmp(dir, "L2R")) {
+ direction = directionL2R;
+ } else if (!strcmp(dir, "R2L")) {
+ direction = directionR2L;
+ }
+ }
+ obj.free();
+
+ if (prefDict->lookup("PrintScaling", &obj)->isName()) {
+ const char *ps = obj.getName();
+ if (!strcmp(ps, "None")) {
+ printScaling = printScalingNone;
+ } else if (!strcmp(ps, "AppDefault")) {
+ printScaling = printScalingAppDefault;
+ }
+ }
+ obj.free();
+
+ if (prefDict->lookup("Duplex", &obj)->isName()) {
+ const char *d = obj.getName();
+ if (!strcmp(d, "Simplex")) {
+ duplex = duplexSimplex;
+ } else if (!strcmp(d, "DuplexFlipShortEdge")) {
+ duplex = duplexDuplexFlipShortEdge;
+ } else if (!strcmp(d, "DuplexFlipLongEdge")) {
+ duplex = duplexDuplexFlipLongEdge;
+ }
+ }
+ obj.free();
+}
+
+ViewerPreferences::~ViewerPreferences()
+{
+}
+
+void ViewerPreferences::init()
+{
+ hideToolbar = gFalse;
+ hideMenubar = gFalse;
+ hideWindowUI = gFalse;
+ fitWindow = gFalse;
+ centerWindow = gFalse;
+ displayDocTitle = gFalse;
+ nonFullScreenPageMode = nfpmUseNone;
+ direction = directionL2R;
+ printScaling = printScalingAppDefault;
+ duplex = duplexNone;
+}
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/ViewerPreferences.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/ViewerPreferences.h
new file mode 100644
index 00000000000..8cdc4d40a73
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/ViewerPreferences.h
@@ -0,0 +1,76 @@
+//========================================================================
+//
+// ViewerPreferences.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2011 Pino Toscano <pino@kde.org>
+//
+//========================================================================
+
+#ifndef VIEWERPREFERENCES_H
+#define VIEWERPREFERENCES_H
+
+#include "goo/gtypes.h"
+
+class Dict;
+
+//------------------------------------------------------------------------
+// ViewerPreferences
+//------------------------------------------------------------------------
+
+class ViewerPreferences {
+public:
+
+ enum NonFullScreenPageMode {
+ nfpmUseNone,
+ nfpmUseOutlines,
+ nfpmUseThumbs,
+ nfpmUseOC
+ };
+ enum Direction {
+ directionL2R,
+ directionR2L
+ };
+ enum PrintScaling {
+ printScalingNone,
+ printScalingAppDefault
+ };
+ enum Duplex {
+ duplexNone,
+ duplexSimplex,
+ duplexDuplexFlipShortEdge,
+ duplexDuplexFlipLongEdge
+ };
+
+ ViewerPreferences(Dict *prefDict);
+ ~ViewerPreferences();
+
+ GBool getHideToolbar() const { return hideToolbar; }
+ GBool getHideMenubar() const { return hideMenubar; }
+ GBool getHideWindowUI() const { return hideWindowUI; }
+ GBool getFitWindow() const { return fitWindow; }
+ GBool getCenterWindow() const { return centerWindow; }
+ GBool getDisplayDocTitle() const { return displayDocTitle; }
+ NonFullScreenPageMode getNonFullScreenPageMode() const { return nonFullScreenPageMode; }
+ Direction getDirection() const { return direction; }
+ PrintScaling getPrintScaling() const { return printScaling; }
+ Duplex getDuplex() const { return duplex; }
+
+private:
+
+ void init();
+
+ GBool hideToolbar;
+ GBool hideMenubar;
+ GBool hideWindowUI;
+ GBool fitWindow;
+ GBool centerWindow;
+ GBool displayDocTitle;
+ NonFullScreenPageMode nonFullScreenPageMode;
+ Direction direction;
+ PrintScaling printScaling;
+ Duplex duplex;
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/XRef.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/XRef.cc
new file mode 100644
index 00000000000..1bbbdc51c25
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/XRef.cc
@@ -0,0 +1,1740 @@
+//========================================================================
+//
+// XRef.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Dan Sheridan <dan.sheridan@postman.org.uk>
+// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
+// Copyright (C) 2006, 2008, 2010, 2012-2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2009, 2010 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@kabelmail.de>
+// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013, 2014 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2013 Pino Toscano <pino@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <limits.h>
+#include <float.h>
+#include "goo/gfile.h"
+#include "goo/gmem.h"
+#include "Object.h"
+#include "Stream.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "Dict.h"
+#include "Error.h"
+#include "ErrorCodes.h"
+#include "XRef.h"
+#include "PopplerCache.h"
+
+//------------------------------------------------------------------------
+// Permission bits
+// Note that the PDF spec uses 1 base (eg bit 3 is 1<<2)
+//------------------------------------------------------------------------
+
+#define permPrint (1<<2) // bit 3
+#define permChange (1<<3) // bit 4
+#define permCopy (1<<4) // bit 5
+#define permNotes (1<<5) // bit 6
+#define permFillForm (1<<8) // bit 9
+#define permAccessibility (1<<9) // bit 10
+#define permAssemble (1<<10) // bit 11
+#define permHighResPrint (1<<11) // bit 12
+#define defPermFlags 0xfffc
+
+#if MULTITHREADED
+# define xrefLocker() MutexLocker locker(&mutex)
+# define xrefCondLocker(X) MutexLocker locker(&mutex, (X))
+#else
+# define xrefLocker()
+# define xrefCondLocker(X)
+#endif
+
+//------------------------------------------------------------------------
+// ObjectStream
+//------------------------------------------------------------------------
+
+class ObjectStream {
+public:
+
+ // Create an object stream, using object number <objStrNum>,
+ // generation 0.
+ ObjectStream(XRef *xref, int objStrNumA, int recursion = 0);
+
+ GBool isOk() { return ok; }
+
+ ~ObjectStream();
+
+ // Return the object number of this object stream.
+ int getObjStrNum() { return objStrNum; }
+
+ // Get the <objIdx>th object from this stream, which should be
+ // object number <objNum>, generation 0.
+ Object *getObject(int objIdx, int objNum, Object *obj);
+
+private:
+
+ int objStrNum; // object number of the object stream
+ int nObjects; // number of objects in the stream
+ Object *objs; // the objects (length = nObjects)
+ int *objNums; // the object numbers (length = nObjects)
+ GBool ok;
+};
+
+class ObjectStreamKey : public PopplerCacheKey
+{
+ public:
+ ObjectStreamKey(int num) : objStrNum(num)
+ {
+ }
+
+ bool operator==(const PopplerCacheKey &key) const
+ {
+ const ObjectStreamKey *k = static_cast<const ObjectStreamKey*>(&key);
+ return objStrNum == k->objStrNum;
+ }
+
+ const int objStrNum;
+};
+
+class ObjectStreamItem : public PopplerCacheItem
+{
+ public:
+ ObjectStreamItem(ObjectStream *objStr) : objStream(objStr)
+ {
+ }
+
+ ~ObjectStreamItem()
+ {
+ delete objStream;
+ }
+
+ ObjectStream *objStream;
+};
+
+ObjectStream::ObjectStream(XRef *xref, int objStrNumA, int recursion) {
+ Stream *str;
+ Parser *parser;
+ Goffset *offsets;
+ Object objStr, obj1, obj2;
+ Goffset first;
+ int i;
+
+ objStrNum = objStrNumA;
+ nObjects = 0;
+ objs = NULL;
+ objNums = NULL;
+ ok = gFalse;
+
+ if (!xref->fetch(objStrNum, 0, &objStr, recursion)->isStream()) {
+ goto err1;
+ }
+
+ if (!objStr.streamGetDict()->lookup("N", &obj1, recursion)->isInt()) {
+ obj1.free();
+ goto err1;
+ }
+ nObjects = obj1.getInt();
+ obj1.free();
+ if (nObjects <= 0) {
+ goto err1;
+ }
+
+ objStr.streamGetDict()->lookup("First", &obj1, recursion);
+ if (!obj1.isInt() && !obj1.isInt64()) {
+ obj1.free();
+ goto err1;
+ }
+ if (obj1.isInt())
+ first = obj1.getInt();
+ else
+ first = obj1.getInt64();
+ obj1.free();
+ if (first < 0) {
+ goto err1;
+ }
+
+ // this is an arbitrary limit to avoid integer overflow problems
+ // in the 'new Object[nObjects]' call (Acrobat apparently limits
+ // object streams to 100-200 objects)
+ if (nObjects > 1000000) {
+ error(errSyntaxError, -1, "Too many objects in an object stream");
+ goto err1;
+ }
+ objs = new Object[nObjects];
+ objNums = (int *)gmallocn(nObjects, sizeof(int));
+ offsets = (Goffset *)gmallocn(nObjects, sizeof(Goffset));
+
+ // parse the header: object numbers and offsets
+ objStr.streamReset();
+ obj1.initNull();
+ str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first);
+ parser = new Parser(xref, new Lexer(xref, str), gFalse);
+ for (i = 0; i < nObjects; ++i) {
+ parser->getObj(&obj1);
+ parser->getObj(&obj2);
+ if (!obj1.isInt() || !(obj2.isInt() || obj2.isInt64())) {
+ obj1.free();
+ obj2.free();
+ delete parser;
+ gfree(offsets);
+ goto err1;
+ }
+ objNums[i] = obj1.getInt();
+ if (obj2.isInt())
+ offsets[i] = obj2.getInt();
+ else
+ offsets[i] = obj2.getInt64();
+ obj1.free();
+ obj2.free();
+ if (objNums[i] < 0 || offsets[i] < 0 ||
+ (i > 0 && offsets[i] < offsets[i-1])) {
+ delete parser;
+ gfree(offsets);
+ goto err1;
+ }
+ }
+ while (str->getChar() != EOF) ;
+ delete parser;
+
+ // skip to the first object - this shouldn't be necessary because
+ // the First key is supposed to be equal to offsets[0], but just in
+ // case...
+ for (Goffset pos = first; pos < offsets[0]; ++pos) {
+ objStr.getStream()->getChar();
+ }
+
+ // parse the objects
+ for (i = 0; i < nObjects; ++i) {
+ obj1.initNull();
+ if (i == nObjects - 1) {
+ str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0);
+ } else {
+ str = new EmbedStream(objStr.getStream(), &obj1, gTrue,
+ offsets[i+1] - offsets[i]);
+ }
+ parser = new Parser(xref, new Lexer(xref, str), gFalse);
+ parser->getObj(&objs[i]);
+ while (str->getChar() != EOF) ;
+ delete parser;
+ }
+
+ gfree(offsets);
+ ok = gTrue;
+
+ err1:
+ objStr.free();
+}
+
+ObjectStream::~ObjectStream() {
+ int i;
+
+ if (objs) {
+ for (i = 0; i < nObjects; ++i) {
+ objs[i].free();
+ }
+ delete[] objs;
+ }
+ gfree(objNums);
+}
+
+Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
+ if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) {
+ return obj->initNull();
+ }
+ return objs[objIdx].copy(obj);
+}
+
+//------------------------------------------------------------------------
+// XRef
+//------------------------------------------------------------------------
+
+void XRef::init() {
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+ ok = gTrue;
+ errCode = errNone;
+ entries = NULL;
+ capacity = 0;
+ size = 0;
+ streamEnds = NULL;
+ streamEndsLen = 0;
+ objStrs = new PopplerCache(5);
+ mainXRefEntriesOffset = 0;
+ xRefStream = gFalse;
+ scannedSpecialFlags = gFalse;
+ encrypted = gFalse;
+ permFlags = defPermFlags;
+ ownerPasswordOk = gFalse;
+ rootNum = -1;
+ strOwner = gFalse;
+}
+
+XRef::XRef() {
+ init();
+}
+
+XRef::XRef(Object *trailerDictA) {
+ init();
+
+ if (trailerDictA->isDict())
+ trailerDict.initDict(trailerDictA->getDict());
+}
+
+XRef::XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA, GBool *wasReconstructed, GBool reconstruct) {
+ Object obj;
+
+ init();
+ mainXRefEntriesOffset = mainXRefEntriesOffsetA;
+
+ // read the trailer
+ str = strA;
+ start = str->getStart();
+ prevXRefOffset = mainXRefOffset = pos;
+
+ if (reconstruct && !(ok = constructXRef(wasReconstructed)))
+ {
+ errCode = errDamaged;
+ return;
+ }
+ else
+ {
+ // if there was a problem with the 'startxref' position, try to
+ // reconstruct the xref table
+ if (prevXRefOffset == 0) {
+ if (!(ok = constructXRef(wasReconstructed))) {
+ errCode = errDamaged;
+ return;
+ }
+
+ // read the xref table
+ } else {
+ std::vector<Goffset> followedXRefStm;
+ readXRef(&prevXRefOffset, &followedXRefStm, NULL);
+
+ // if there was a problem with the xref table,
+ // try to reconstruct it
+ if (!ok) {
+ if (!(ok = constructXRef(wasReconstructed))) {
+ errCode = errDamaged;
+ return;
+ }
+ }
+ }
+
+ // set size to (at least) the size specified in trailer dict
+ trailerDict.dictLookupNF("Size", &obj);
+ if (!obj.isInt()) {
+ error(errSyntaxWarning, -1, "No valid XRef size in trailer");
+ } else {
+ if (obj.getInt() > size) {
+ if (resize(obj.getInt()) != obj.getInt()) {
+ if (!(ok = constructXRef(wasReconstructed))) {
+ obj.free();
+ errCode = errDamaged;
+ return;
+ }
+ }
+ }
+ }
+ obj.free();
+
+ // get the root dictionary (catalog) object
+ trailerDict.dictLookupNF("Root", &obj);
+ if (obj.isRef()) {
+ rootNum = obj.getRefNum();
+ rootGen = obj.getRefGen();
+ obj.free();
+ } else {
+ obj.free();
+ if (!(ok = constructXRef(wasReconstructed))) {
+ errCode = errDamaged;
+ return;
+ }
+ }
+ }
+ // now set the trailer dictionary's xref pointer so we can fetch
+ // indirect objects from it
+ trailerDict.getDict()->setXRef(this);
+}
+
+XRef::~XRef() {
+ for(int i=0; i<size; i++) {
+ entries[i].obj.free ();
+ }
+ gfree(entries);
+
+ trailerDict.free();
+ if (streamEnds) {
+ gfree(streamEnds);
+ }
+ if (objStrs) {
+ delete objStrs;
+ }
+ if (strOwner) {
+ delete str;
+ }
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+XRef *XRef::copy() {
+ XRef *xref = new XRef();
+ xref->str = str->copy();
+ xref->strOwner = gTrue;
+ xref->encrypted = encrypted;
+ xref->permFlags = permFlags;
+ xref->ownerPasswordOk = ownerPasswordOk;
+ xref->rootGen = rootGen;
+ xref->rootNum = rootNum;
+
+ xref->start = start;
+ xref->prevXRefOffset = prevXRefOffset;
+ xref->mainXRefEntriesOffset = mainXRefEntriesOffset;
+ xref->xRefStream = xRefStream;
+ trailerDict.copy(&xref->trailerDict);
+ xref->encAlgorithm = encAlgorithm;
+ xref->encRevision = encRevision;
+ xref->encVersion = encVersion;
+ xref->permFlags = permFlags;
+ xref->keyLength = keyLength;
+ xref->permFlags = permFlags;
+ for (int i = 0; i < 32; i++) {
+ xref->fileKey[i] = fileKey[i];
+ }
+
+ if (xref->reserve(size) == 0) {
+ error(errSyntaxError, -1, "unable to allocate {0:d} entries", size);
+ delete xref;
+ return NULL;
+ }
+ xref->size = size;
+ for (int i = 0; i < size; ++i) {
+ xref->entries[i].offset = entries[i].offset;
+ xref->entries[i].type = entries[i].type;
+ xref->entries[i].obj.initNull ();
+ xref->entries[i].flags = entries[i].flags;
+ xref->entries[i].gen = entries[i].gen;
+ }
+ xref->streamEndsLen = streamEndsLen;
+ if (streamEndsLen != 0) {
+ xref->streamEnds = (Goffset *)gmalloc(streamEndsLen * sizeof(Goffset));
+ for (int i = 0; i < streamEndsLen; i++) {
+ xref->streamEnds[i] = streamEnds[i];
+ }
+ }
+ return xref;
+}
+
+int XRef::reserve(int newSize)
+{
+ if (newSize > capacity) {
+
+ int realNewSize;
+ for (realNewSize = capacity ? 2 * capacity : 1024;
+ newSize > realNewSize && realNewSize > 0;
+ realNewSize <<= 1) ;
+ if ((realNewSize < 0) ||
+ (realNewSize >= INT_MAX / (int)sizeof(XRefEntry))) {
+ return 0;
+ }
+
+ void *p = greallocn_checkoverflow(entries, realNewSize, sizeof(XRefEntry));
+ if (p == NULL) {
+ return 0;
+ }
+
+ entries = (XRefEntry *) p;
+ capacity = realNewSize;
+
+ }
+
+ return capacity;
+}
+
+int XRef::resize(int newSize)
+{
+ if (newSize > size) {
+
+ if (reserve(newSize) < newSize) return size;
+
+ for (int i = size; i < newSize; ++i) {
+ entries[i].offset = -1;
+ entries[i].type = xrefEntryNone;
+ entries[i].obj.initNull ();
+ entries[i].flags = 0;
+ entries[i].gen = 0;
+ }
+ } else {
+ for (int i = newSize; i < size; i++) {
+ entries[i].obj.free ();
+ }
+ }
+
+ size = newSize;
+
+ return size;
+}
+
+/* Read one xref table section. Also reads the associated trailer
+ * dictionary, and returns the prev pointer (if any).
+ * Arguments:
+ * pos Points to a Goffset containing the offset of the XRef
+ * section to be read. If a prev pointer is found, *pos is
+ * updated with its value
+ * followedXRefStm Used in case of nested readXRef calls to spot circular
+ * references in XRefStm pointers
+ * xrefStreamObjsNum If not NULL, every time a XRef stream is encountered,
+ * its object number is appended
+ * Return value:
+ * gTrue if a prev pointer is found, otherwise gFalse
+ */
+GBool XRef::readXRef(Goffset *pos, std::vector<Goffset> *followedXRefStm, std::vector<int> *xrefStreamObjsNum) {
+ Parser *parser;
+ Object obj;
+ GBool more;
+
+ // start up a parser, parse one token
+ obj.initNull();
+ parser = new Parser(NULL,
+ new Lexer(NULL,
+ str->makeSubStream(start + *pos, gFalse, 0, &obj)),
+ gTrue);
+ parser->getObj(&obj, gTrue);
+
+ // parse an old-style xref table
+ if (obj.isCmd("xref")) {
+ obj.free();
+ more = readXRefTable(parser, pos, followedXRefStm, xrefStreamObjsNum);
+
+ // parse an xref stream
+ } else if (obj.isInt()) {
+ const int objNum = obj.getInt();
+ obj.free();
+ if (!parser->getObj(&obj, gTrue)->isInt()) {
+ goto err1;
+ }
+ obj.free();
+ if (!parser->getObj(&obj, gTrue)->isCmd("obj")) {
+ goto err1;
+ }
+ obj.free();
+ if (!parser->getObj(&obj)->isStream()) {
+ goto err1;
+ }
+ if (trailerDict.isNone()) {
+ xRefStream = gTrue;
+ }
+ if (xrefStreamObjsNum) {
+ xrefStreamObjsNum->push_back(objNum);
+ }
+ more = readXRefStream(obj.getStream(), pos);
+ obj.free();
+
+ } else {
+ goto err1;
+ }
+
+ delete parser;
+ return more;
+
+ err1:
+ obj.free();
+ delete parser;
+ ok = gFalse;
+ return gFalse;
+}
+
+GBool XRef::readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *followedXRefStm, std::vector<int> *xrefStreamObjsNum) {
+ XRefEntry entry;
+ GBool more;
+ Object obj, obj2;
+ Goffset pos2;
+ int first, n, i;
+
+ while (1) {
+ parser->getObj(&obj, gTrue);
+ if (obj.isCmd("trailer")) {
+ obj.free();
+ break;
+ }
+ if (!obj.isInt()) {
+ goto err1;
+ }
+ first = obj.getInt();
+ obj.free();
+ if (!parser->getObj(&obj, gTrue)->isInt()) {
+ goto err1;
+ }
+ n = obj.getInt();
+ obj.free();
+ if (first < 0 || n < 0 || first + n < 0) {
+ goto err0;
+ }
+ if (first + n > size) {
+ if (resize(first + n) != first + n) {
+ error(errSyntaxError, -1, "Invalid 'obj' parameters'");
+ goto err0;
+ }
+ }
+ for (i = first; i < first + n; ++i) {
+ parser->getObj(&obj, gTrue);
+ if (obj.isInt()) {
+ entry.offset = obj.getInt();
+ } else if (obj.isInt64()) {
+ entry.offset = obj.getInt64();
+ } else {
+ goto err1;
+ }
+ obj.free();
+ if (!parser->getObj(&obj, gTrue)->isInt()) {
+ goto err1;
+ }
+ entry.gen = obj.getInt();
+ entry.obj.initNull ();
+ entry.flags = 0;
+ obj.free();
+ parser->getObj(&obj, gTrue);
+ if (obj.isCmd("n")) {
+ entry.type = xrefEntryUncompressed;
+ } else if (obj.isCmd("f")) {
+ entry.type = xrefEntryFree;
+ } else {
+ goto err1;
+ }
+ obj.free();
+ if (entries[i].offset == -1) {
+ entries[i] = entry;
+ // PDF files of patents from the IBM Intellectual Property
+ // Network have a bug: the xref table claims to start at 1
+ // instead of 0.
+ if (i == 1 && first == 1 &&
+ entries[1].offset == 0 && entries[1].gen == 65535 &&
+ entries[1].type == xrefEntryFree) {
+ i = first = 0;
+ entries[0] = entries[1];
+ entries[1].offset = -1;
+ }
+ }
+ }
+ }
+
+ // read the trailer dictionary
+ if (!parser->getObj(&obj)->isDict()) {
+ goto err1;
+ }
+
+ // get the 'Prev' pointer
+ obj.getDict()->lookupNF("Prev", &obj2);
+ if (obj2.isInt() || obj2.isInt64()) {
+ if (obj2.isInt())
+ pos2 = obj2.getInt();
+ else
+ pos2 = obj2.getInt64();
+ if (pos2 != *pos) {
+ *pos = pos2;
+ more = gTrue;
+ } else {
+ error(errSyntaxWarning, -1, "Infinite loop in xref table");
+ more = gFalse;
+ }
+ } else if (obj2.isRef()) {
+ // certain buggy PDF generators generate "/Prev NNN 0 R" instead
+ // of "/Prev NNN"
+ pos2 = (Guint)obj2.getRefNum();
+ if (pos2 != *pos) {
+ *pos = pos2;
+ more = gTrue;
+ } else {
+ error(errSyntaxWarning, -1, "Infinite loop in xref table");
+ more = gFalse;
+ }
+ } else {
+ more = gFalse;
+ }
+ obj2.free();
+
+ // save the first trailer dictionary
+ if (trailerDict.isNone()) {
+ obj.copy(&trailerDict);
+ }
+
+ // check for an 'XRefStm' key
+ obj.getDict()->lookup("XRefStm", &obj2);
+ if (obj2.isInt() || obj2.isInt64()) {
+ if (obj2.isInt())
+ pos2 = obj2.getInt();
+ else
+ pos2 = obj2.getInt64();
+ for (size_t i = 0; ok == gTrue && i < followedXRefStm->size(); ++i) {
+ if (followedXRefStm->at(i) == pos2) {
+ ok = gFalse;
+ }
+ }
+ if (ok) {
+ followedXRefStm->push_back(pos2);
+ readXRef(&pos2, followedXRefStm, xrefStreamObjsNum);
+ }
+ if (!ok) {
+ obj2.free();
+ goto err1;
+ }
+ }
+ obj2.free();
+
+ obj.free();
+ return more;
+
+ err1:
+ obj.free();
+ err0:
+ ok = gFalse;
+ return gFalse;
+}
+
+GBool XRef::readXRefStream(Stream *xrefStr, Goffset *pos) {
+ Dict *dict;
+ int w[3];
+ GBool more;
+ Object obj, obj2, idx;
+ int newSize, first, n, i;
+
+ dict = xrefStr->getDict();
+
+ if (!dict->lookupNF("Size", &obj)->isInt()) {
+ goto err1;
+ }
+ newSize = obj.getInt();
+ obj.free();
+ if (newSize < 0) {
+ goto err1;
+ }
+ if (newSize > size) {
+ if (resize(newSize) != newSize) {
+ error(errSyntaxError, -1, "Invalid 'size' parameter");
+ goto err0;
+ }
+ }
+
+ if (!dict->lookupNF("W", &obj)->isArray() ||
+ obj.arrayGetLength() < 3) {
+ goto err1;
+ }
+ for (i = 0; i < 3; ++i) {
+ if (!obj.arrayGet(i, &obj2)->isInt()) {
+ obj2.free();
+ goto err1;
+ }
+ w[i] = obj2.getInt();
+ obj2.free();
+ if (w[i] < 0) {
+ goto err1;
+ }
+ }
+ obj.free();
+ if (w[0] > (int)sizeof(int) || w[1] > (int)sizeof(long long) || w[2] > (int)sizeof(int)) {
+ goto err1;
+ }
+
+ xrefStr->reset();
+ dict->lookupNF("Index", &idx);
+ if (idx.isArray()) {
+ for (i = 0; i+1 < idx.arrayGetLength(); i += 2) {
+ if (!idx.arrayGet(i, &obj)->isInt()) {
+ idx.free();
+ goto err1;
+ }
+ first = obj.getInt();
+ obj.free();
+ if (!idx.arrayGet(i+1, &obj)->isInt()) {
+ idx.free();
+ goto err1;
+ }
+ n = obj.getInt();
+ obj.free();
+ if (first < 0 || n < 0 ||
+ !readXRefStreamSection(xrefStr, w, first, n)) {
+ idx.free();
+ goto err0;
+ }
+ }
+ } else {
+ if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
+ idx.free();
+ goto err0;
+ }
+ }
+ idx.free();
+
+ dict->lookupNF("Prev", &obj);
+ if (obj.isInt()) {
+ *pos = obj.getInt();
+ more = gTrue;
+ } else if (obj.isInt64()) {
+ *pos = obj.getInt64();
+ more = gTrue;
+ } else {
+ more = gFalse;
+ }
+ obj.free();
+ if (trailerDict.isNone()) {
+ trailerDict.initDict(dict);
+ }
+
+ return more;
+
+ err1:
+ obj.free();
+ err0:
+ ok = gFalse;
+ return gFalse;
+}
+
+GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
+ unsigned long long offset;
+ int type, gen, c, i, j;
+
+ if (first + n < 0) {
+ return gFalse;
+ }
+ if (first + n > size) {
+ if (resize(first + n) != size) {
+ error(errSyntaxError, -1, "Invalid 'size' inside xref table");
+ return gFalse;
+ }
+ if (first + n > size) {
+ error(errSyntaxError, -1, "Invalid 'first' or 'n' inside xref table");
+ return gFalse;
+ }
+ }
+ for (i = first; i < first + n; ++i) {
+ if (w[0] == 0) {
+ type = 1;
+ } else {
+ for (type = 0, j = 0; j < w[0]; ++j) {
+ if ((c = xrefStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ type = (type << 8) + c;
+ }
+ }
+ for (offset = 0, j = 0; j < w[1]; ++j) {
+ if ((c = xrefStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ offset = (offset << 8) + c;
+ }
+ if (offset > (unsigned long long)GoffsetMax()) {
+ error(errSyntaxError, -1, "Offset inside xref table too large for fseek");
+ return gFalse;
+ }
+ for (gen = 0, j = 0; j < w[2]; ++j) {
+ if ((c = xrefStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ gen = (gen << 8) + c;
+ }
+ if (entries[i].offset == -1) {
+ switch (type) {
+ case 0:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryFree;
+ break;
+ case 1:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryUncompressed;
+ break;
+ case 2:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryCompressed;
+ break;
+ default:
+ return gFalse;
+ }
+ }
+ }
+
+ return gTrue;
+}
+
+// Attempt to construct an xref table for a damaged file.
+GBool XRef::constructXRef(GBool *wasReconstructed, GBool needCatalogDict) {
+ Parser *parser;
+ Object newTrailerDict, obj;
+ char buf[256];
+ Goffset pos;
+ int num, gen;
+ int newSize;
+ int streamEndsSize;
+ char *p;
+ GBool gotRoot;
+ char* token = NULL;
+ bool oneCycle = true;
+ int offset = 0;
+
+ gfree(entries);
+ capacity = 0;
+ size = 0;
+ entries = NULL;
+
+ gotRoot = gFalse;
+ streamEndsLen = streamEndsSize = 0;
+
+ if (wasReconstructed)
+ {
+ *wasReconstructed = true;
+ }
+
+ str->reset();
+ while (1) {
+ pos = str->getPos();
+ if (!str->getLine(buf, 256)) {
+ break;
+ }
+ p = buf;
+
+ // skip whitespace
+ while (*p && Lexer::isSpace(*p & 0xff)) ++p;
+
+ oneCycle = true;
+ offset = 0;
+
+ while( ( token = strstr( p, "endobj" ) ) || oneCycle ) {
+ oneCycle = false;
+
+ if( token ) {
+ oneCycle = true;
+ token[0] = '\0';
+ offset = token - p;
+ }
+
+ // got trailer dictionary
+ if (!strncmp(p, "trailer", 7)) {
+ obj.initNull();
+ parser = new Parser(NULL,
+ new Lexer(NULL,
+ str->makeSubStream(pos + 7, gFalse, 0, &obj)),
+ gFalse);
+ parser->getObj(&newTrailerDict);
+ if (newTrailerDict.isDict()) {
+ newTrailerDict.dictLookupNF("Root", &obj);
+ if (obj.isRef() && (!gotRoot || !needCatalogDict) && rootNum != obj.getRefNum()) {
+ rootNum = obj.getRefNum();
+ rootGen = obj.getRefGen();
+ if (!trailerDict.isNone()) {
+ trailerDict.free();
+ }
+ newTrailerDict.copy(&trailerDict);
+ gotRoot = gTrue;
+ }
+ obj.free();
+ }
+ newTrailerDict.free();
+ delete parser;
+
+ // look for object
+ } else if (isdigit(*p & 0xff)) {
+ num = atoi(p);
+ if (num > 0) {
+ do {
+ ++p;
+ } while (*p && isdigit(*p & 0xff));
+ if (isspace(*p & 0xff)) {
+ do {
+ ++p;
+ } while (*p && isspace(*p & 0xff));
+ if (isdigit(*p & 0xff)) {
+ gen = atoi(p);
+ do {
+ ++p;
+ } while (*p && isdigit(*p & 0xff));
+ if (isspace(*p & 0xff)) {
+ do {
+ ++p;
+ } while (*p && isspace(*p & 0xff));
+ if (!strncmp(p, "obj", 3)) {
+ if (num >= size) {
+ newSize = (num + 1 + 255) & ~255;
+ if (newSize < 0) {
+ error(errSyntaxError, -1, "Bad object number");
+ return gFalse;
+ }
+ if (resize(newSize) != newSize) {
+ error(errSyntaxError, -1, "Invalid 'obj' parameters");
+ return gFalse;
+ }
+ }
+ if (entries[num].type == xrefEntryFree ||
+ gen >= entries[num].gen) {
+ entries[num].offset = pos - start;
+ entries[num].gen = gen;
+ entries[num].type = xrefEntryUncompressed;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ } else if (!strncmp(p, "endstream", 9)) {
+ if (streamEndsLen == streamEndsSize) {
+ streamEndsSize += 64;
+ if (streamEndsSize >= INT_MAX / (int)sizeof(int)) {
+ error(errSyntaxError, -1, "Invalid 'endstream' parameter.");
+ return gFalse;
+ }
+ streamEnds = (Goffset *)greallocn(streamEnds,
+ streamEndsSize, sizeof(Goffset));
+ }
+ streamEnds[streamEndsLen++] = pos;
+ }
+ if( token ) {
+ p = token + 6;// strlen( "endobj" ) = 6
+ pos += offset + 6;// strlen( "endobj" ) = 6
+ while (*p && Lexer::isSpace(*p & 0xff)) {
+ ++p;
+ ++pos;
+ }
+ }
+ }
+ }
+
+ if (gotRoot)
+ return gTrue;
+
+ error(errSyntaxError, -1, "Couldn't find trailer dictionary");
+ return gFalse;
+}
+
+void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
+ Guchar *fileKeyA, int keyLengthA,
+ int encVersionA, int encRevisionA,
+ CryptAlgorithm encAlgorithmA) {
+ int i;
+
+ encrypted = gTrue;
+ permFlags = permFlagsA;
+ ownerPasswordOk = ownerPasswordOkA;
+ if (keyLengthA <= 32) {
+ keyLength = keyLengthA;
+ } else {
+ keyLength = 32;
+ }
+ for (i = 0; i < keyLength; ++i) {
+ fileKey[i] = fileKeyA[i];
+ }
+ encVersion = encVersionA;
+ encRevision = encRevisionA;
+ encAlgorithm = encAlgorithmA;
+}
+
+void XRef::getEncryptionParameters(Guchar **fileKeyA, CryptAlgorithm *encAlgorithmA,
+ int *keyLengthA) {
+ if (encrypted) {
+ *fileKeyA = fileKey;
+ *encAlgorithmA = encAlgorithm;
+ *keyLengthA = keyLength;
+ } else {
+ // null encryption parameters
+ *fileKeyA = NULL;
+ *encAlgorithmA = cryptRC4;
+ *keyLengthA = 0;
+ }
+}
+
+GBool XRef::okToPrint(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
+}
+
+// we can print at high res if we are only doing security handler revision
+// 2 (and we are allowed to print at all), or with security handler rev
+// 3 and we are allowed to print, and bit 12 is set.
+GBool XRef::okToPrintHighRes(GBool ignoreOwnerPW) {
+ if (encrypted) {
+ if (2 == encRevision) {
+ return (okToPrint(ignoreOwnerPW));
+ } else if (encRevision >= 3) {
+ return (okToPrint(ignoreOwnerPW) && (permFlags & permHighResPrint));
+ } else {
+ // something weird - unknown security handler version
+ return gFalse;
+ }
+ } else {
+ return gTrue;
+ }
+}
+
+GBool XRef::okToChange(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange);
+}
+
+GBool XRef::okToCopy(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy);
+}
+
+GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes);
+}
+
+GBool XRef::okToFillForm(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permFillForm);
+}
+
+GBool XRef::okToAccessibility(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAccessibility);
+}
+
+GBool XRef::okToAssemble(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAssemble);
+}
+
+Object *XRef::getCatalog(Object *catalog) {
+ Object *obj = fetch(rootNum, rootGen, catalog);
+ if (obj->isDict()) {
+ return obj;
+ }
+ GBool wasReconstructed = false;
+ GBool ok = constructXRef(&wasReconstructed, gTrue);
+ return (ok) ? fetch(rootNum, rootGen, catalog) : obj;
+}
+
+Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
+ XRefEntry *e;
+ Parser *parser;
+ Object obj1, obj2, obj3;
+
+ xrefLocker();
+ // check for bogus ref - this can happen in corrupted PDF files
+ if (num < 0 || num >= size) {
+ goto err;
+ }
+
+ e = getEntry(num);
+ if(!e->obj.isNull ()) { //check for updated object
+ obj = e->obj.copy(obj);
+ return obj;
+ }
+
+ switch (e->type) {
+
+ case xrefEntryUncompressed:
+ if (e->gen != gen) {
+ goto err;
+ }
+ obj1.initNull();
+ parser = new Parser(this,
+ new Lexer(this,
+ str->makeSubStream(start + e->offset, gFalse, 0, &obj1)),
+ gTrue);
+ parser->getObj(&obj1, recursion);
+ parser->getObj(&obj2, recursion);
+ parser->getObj(&obj3, recursion);
+ if (!obj1.isInt() || obj1.getInt() != num ||
+ !obj2.isInt() || obj2.getInt() != gen ||
+ !obj3.isCmd("obj")) {
+ // some buggy pdf have obj1234 for ints that represent 1234
+ // try to recover here
+ if (obj1.isInt() && obj1.getInt() == num &&
+ obj2.isInt() && obj2.getInt() == gen &&
+ obj3.isCmd()) {
+ char *cmd = obj3.getCmd();
+ if (strlen(cmd) > 3 &&
+ cmd[0] == 'o' &&
+ cmd[1] == 'b' &&
+ cmd[2] == 'j') {
+ char *end_ptr;
+ long longNumber = strtol(cmd + 3, &end_ptr, 0);
+ if (longNumber <= INT_MAX && longNumber >= INT_MIN && *end_ptr == '\0') {
+ int number = longNumber;
+ error(errSyntaxWarning, -1, "Cmd was not obj but {0:s}, assuming the creator meant obj {1:d}", cmd, number);
+ obj->initInt(number);
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ delete parser;
+ break;
+ }
+ }
+ }
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ delete parser;
+ goto err;
+ }
+ parser->getObj(obj, gFalse, (encrypted && !e->getFlag(XRefEntry::Unencrypted)) ? fileKey : NULL,
+ encAlgorithm, keyLength, num, gen, recursion);
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ delete parser;
+ break;
+
+ case xrefEntryCompressed:
+ {
+#if 0 // Adobe apparently ignores the generation number on compressed objects
+ if (gen != 0) {
+ goto err;
+ }
+#endif
+ if (e->offset >= (Guint)size ||
+ entries[e->offset].type != xrefEntryUncompressed) {
+ error(errSyntaxError, -1, "Invalid object stream");
+ goto err;
+ }
+
+ ObjectStream *objStr = NULL;
+ ObjectStreamKey key(e->offset);
+ PopplerCacheItem *item = objStrs->lookup(key);
+ if (item) {
+ ObjectStreamItem *it = static_cast<ObjectStreamItem *>(item);
+ objStr = it->objStream;
+ }
+
+ if (!objStr) {
+ objStr = new ObjectStream(this, e->offset, recursion + 1);
+ if (!objStr->isOk()) {
+ delete objStr;
+ objStr = NULL;
+ goto err;
+ } else {
+ // XRef could be reconstructed in constructor of ObjectStream:
+ e = getEntry(num);
+ ObjectStreamKey *newkey = new ObjectStreamKey(e->offset);
+ ObjectStreamItem *newitem = new ObjectStreamItem(objStr);
+ objStrs->put(newkey, newitem);
+ }
+ }
+ objStr->getObject(e->gen, num, obj);
+ }
+ break;
+
+ default:
+ goto err;
+ }
+
+ return obj;
+
+ err:
+ return obj->initNull();
+}
+
+void XRef::lock() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+}
+
+void XRef::unlock() {
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+}
+
+Object *XRef::getDocInfo(Object *obj) {
+ return trailerDict.dictLookup("Info", obj);
+}
+
+// Added for the pdftex project.
+Object *XRef::getDocInfoNF(Object *obj) {
+ return trailerDict.dictLookupNF("Info", obj);
+}
+
+GBool XRef::getStreamEnd(Goffset streamStart, Goffset *streamEnd) {
+ int a, b, m;
+
+ if (streamEndsLen == 0 ||
+ streamStart > streamEnds[streamEndsLen - 1]) {
+ return gFalse;
+ }
+
+ a = -1;
+ b = streamEndsLen - 1;
+ // invariant: streamEnds[a] < streamStart <= streamEnds[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (streamStart <= streamEnds[m]) {
+ b = m;
+ } else {
+ a = m;
+ }
+ }
+ *streamEnd = streamEnds[b];
+ return gTrue;
+}
+
+int XRef::getNumEntry(Goffset offset)
+{
+ if (size > 0)
+ {
+ int res = 0;
+ Goffset resOffset = getEntry(0)->offset;
+ XRefEntry *e;
+ for (int i = 1; i < size; ++i)
+ {
+ e = getEntry(i, gFalse);
+ if (e->type != xrefEntryFree && e->offset < offset && e->offset >= resOffset)
+ {
+ res = i;
+ resOffset = e->offset;
+ }
+ }
+ return res;
+ }
+ else return -1;
+}
+
+void XRef::add(int num, int gen, Goffset offs, GBool used) {
+ xrefLocker();
+ if (num >= size) {
+ if (num >= capacity) {
+ entries = (XRefEntry *)greallocn(entries, num + 1, sizeof(XRefEntry));
+ capacity = num + 1;
+ }
+ for (int i = size; i < num + 1; ++i) {
+ entries[i].offset = -1;
+ entries[i].type = xrefEntryFree;
+ entries[i].obj.initNull ();
+ entries[i].flags = 0;
+ entries[i].gen = 0;
+ }
+ size = num + 1;
+ }
+ XRefEntry *e = getEntry(num);
+ e->gen = gen;
+ e->obj.initNull ();
+ e->flags = 0;
+ if (used) {
+ e->type = xrefEntryUncompressed;
+ e->offset = offs;
+ } else {
+ e->type = xrefEntryFree;
+ e->offset = 0;
+ }
+}
+
+void XRef::setModifiedObject (Object* o, Ref r) {
+ xrefLocker();
+ if (r.num < 0 || r.num >= size) {
+ error(errInternal, -1,"XRef::setModifiedObject on unknown ref: {0:d}, {1:d}\n", r.num, r.gen);
+ return;
+ }
+ XRefEntry *e = getEntry(r.num);
+ e->obj.free();
+ o->copy(&(e->obj));
+ e->setFlag(XRefEntry::Updated, gTrue);
+}
+
+Ref XRef::addIndirectObject (Object* o) {
+ int entryIndexToUse = -1;
+ for (int i = 1; entryIndexToUse == -1 && i < size; ++i) {
+ XRefEntry *e = getEntry(i, false /* complainIfMissing */);
+ if (e->type == xrefEntryFree && e->gen != 65535) {
+ entryIndexToUse = i;
+ }
+ }
+
+ XRefEntry *e;
+ if (entryIndexToUse == -1) {
+ entryIndexToUse = size;
+ add(entryIndexToUse, 0, 0, gFalse);
+ e = getEntry(entryIndexToUse);
+ } else {
+ //reuse a free entry
+ e = getEntry(entryIndexToUse);
+ //we don't touch gen number, because it should have been
+ //incremented when the object was deleted
+ }
+ e->type = xrefEntryUncompressed;
+ o->copy(&e->obj);
+ e->setFlag(XRefEntry::Updated, gTrue);
+
+ Ref r;
+ r.num = entryIndexToUse;
+ r.gen = e->gen;
+ return r;
+}
+
+void XRef::removeIndirectObject(Ref r) {
+ xrefLocker();
+ if (r.num < 0 || r.num >= size) {
+ error(errInternal, -1,"XRef::removeIndirectObject on unknown ref: {0:d}, {1:d}\n", r.num, r.gen);
+ return;
+ }
+ XRefEntry *e = getEntry(r.num);
+ if (e->type == xrefEntryFree) {
+ return;
+ }
+ e->obj.free();
+ e->type = xrefEntryFree;
+ e->gen++;
+ e->setFlag(XRefEntry::Updated, gTrue);
+}
+
+void XRef::writeXRef(XRef::XRefWriter *writer, GBool writeAllEntries) {
+ //create free entries linked-list
+ if (getEntry(0)->gen != 65535) {
+ error(errInternal, -1, "XRef::writeXRef, entry 0 of the XRef is invalid (gen != 65535)\n");
+ }
+ int lastFreeEntry = 0;
+ for (int i=0; i<size; i++) {
+ if (getEntry(i)->type == xrefEntryFree) {
+ getEntry(lastFreeEntry)->offset = i;
+ lastFreeEntry = i;
+ }
+ }
+ getEntry(lastFreeEntry)->offset = 0;
+
+ if (writeAllEntries) {
+ writer->startSection(0, size);
+ for (int i=0; i<size; i++) {
+ XRefEntry *e = getEntry(i);
+ if(e->gen > 65535) e->gen = 65535; //cap generation number to 65535 (required by PDFReference)
+ writer->writeEntry(e->offset, e->gen, e->type);
+ }
+ } else {
+ int i = 0;
+ while (i < size) {
+ int j;
+ for(j=i; j<size; j++) { //look for consecutive entries
+ if ((getEntry(j)->type == xrefEntryFree) && (getEntry(j)->gen == 0))
+ break;
+ }
+ if (j-i != 0)
+ {
+ writer->startSection(i, j-i);
+ for (int k=i; k<j; k++) {
+ XRefEntry *e = getEntry(k);
+ if(e->gen > 65535) e->gen = 65535; //cap generation number to 65535 (required by PDFReference)
+ writer->writeEntry(e->offset, e->gen, e->type);
+ }
+ i = j;
+ }
+ else ++i;
+ }
+ }
+}
+
+XRef::XRefTableWriter::XRefTableWriter(OutStream* outStrA) {
+ outStr = outStrA;
+}
+
+void XRef::XRefTableWriter::startSection(int first, int count) {
+ outStr->printf("%i %i\r\n", first, count);
+}
+
+void XRef::XRefTableWriter::writeEntry(Goffset offset, int gen, XRefEntryType type) {
+ outStr->printf("%010lli %05i %c\r\n", (long long)offset, gen, (type==xrefEntryFree)?'f':'n');
+}
+
+void XRef::writeTableToFile(OutStream* outStr, GBool writeAllEntries) {
+ XRefTableWriter writer(outStr);
+ outStr->printf("xref\r\n");
+ writeXRef(&writer, writeAllEntries);
+}
+
+XRef::XRefStreamWriter::XRefStreamWriter(Object *indexA, GooString *stmBufA, int offsetSizeA) {
+ index = indexA;
+ stmBuf = stmBufA;
+ offsetSize = offsetSizeA;
+}
+
+void XRef::XRefStreamWriter::startSection(int first, int count) {
+ Object obj;
+ index->arrayAdd( obj.initInt(first) );
+ index->arrayAdd( obj.initInt(count) );
+}
+
+void XRef::XRefStreamWriter::writeEntry(Goffset offset, int gen, XRefEntryType type) {
+ const int entryTotalSize = 1 + offsetSize + 2; /* type + offset + gen */
+ char data[16];
+ data[0] = (type==xrefEntryFree) ? 0 : 1;
+ for (int i = offsetSize; i > 0; i--) {
+ data[i] = offset & 0xff;
+ offset >>= 8;
+ }
+ data[offsetSize + 1] = (gen >> 8) & 0xff;
+ data[offsetSize + 2] = gen & 0xff;
+ stmBuf->append(data, entryTotalSize);
+}
+
+XRef::XRefPreScanWriter::XRefPreScanWriter() {
+ hasOffsetsBeyond4GB = gFalse;
+}
+
+void XRef::XRefPreScanWriter::startSection(int first, int count) {
+}
+
+void XRef::XRefPreScanWriter::writeEntry(Goffset offset, int gen, XRefEntryType type) {
+ if (offset >= 0x100000000ll)
+ hasOffsetsBeyond4GB = gTrue;
+}
+
+void XRef::writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref) {
+ Object index;
+ index.initArray(xref);
+ stmBuf->clear();
+
+ // First pass: determine whether all offsets fit in 4 bytes or not
+ XRefPreScanWriter prescan;
+ writeXRef(&prescan, gFalse);
+ const int offsetSize = prescan.hasOffsetsBeyond4GB ? sizeof(Goffset) : 4;
+
+ // Second pass: actually write the xref stream
+ XRefStreamWriter writer(&index, stmBuf, offsetSize);
+ writeXRef(&writer, gFalse);
+
+ Object obj1, obj2;
+ xrefDict->set("Type", obj1.initName("XRef"));
+ xrefDict->set("Index", &index);
+ obj2.initArray(xref);
+ obj2.arrayAdd( obj1.initInt(1) );
+ obj2.arrayAdd( obj1.initInt(offsetSize) );
+ obj2.arrayAdd( obj1.initInt(2) );
+ xrefDict->set("W", &obj2);
+}
+
+GBool XRef::parseEntry(Goffset offset, XRefEntry *entry)
+{
+ GBool r;
+
+ Object obj;
+ obj.initNull();
+ Parser parser = Parser(NULL, new Lexer(NULL,
+ str->makeSubStream(offset, gFalse, 20, &obj)), gTrue);
+
+ Object obj1, obj2, obj3;
+ if (((parser.getObj(&obj1)->isInt()) ||
+ parser.getObj(&obj1)->isInt64()) &&
+ (parser.getObj(&obj2)->isInt()) &&
+ (parser.getObj(&obj3)->isCmd("n") || obj3.isCmd("f"))) {
+ if (obj1.isInt64())
+ entry->offset = obj1.getInt64();
+ else
+ entry->offset = obj1.getInt();
+ entry->gen = obj2.getInt();
+ entry->type = obj3.isCmd("n") ? xrefEntryUncompressed : xrefEntryFree;
+ entry->obj.initNull ();
+ entry->flags = 0;
+ r = gTrue;
+ } else {
+ r = gFalse;
+ }
+ obj1.free();
+ obj2.free();
+ obj3.free();
+
+ return r;
+}
+
+/* Traverse all XRef tables and, if untilEntryNum != -1, stop as soon as
+ * untilEntryNum is found, or try to reconstruct the xref table if it's not
+ * present in any xref.
+ * If xrefStreamObjsNum is not NULL, it is filled with the list of the object
+ * numbers of the XRef streams that have been traversed */
+void XRef::readXRefUntil(int untilEntryNum, std::vector<int> *xrefStreamObjsNum)
+{
+ std::vector<Goffset> followedPrev;
+ while (prevXRefOffset && (untilEntryNum == -1 || (untilEntryNum < size && entries[untilEntryNum].type == xrefEntryNone))) {
+ bool followed = false;
+ for (size_t j = 0; j < followedPrev.size(); j++) {
+ if (followedPrev.at(j) == prevXRefOffset) {
+ followed = true;
+ break;
+ }
+ }
+ if (followed) {
+ error(errSyntaxError, -1, "Circular XRef");
+ if (!(ok = constructXRef(NULL))) {
+ errCode = errDamaged;
+ }
+ break;
+ }
+
+ followedPrev.push_back (prevXRefOffset);
+
+ std::vector<Goffset> followedXRefStm;
+ if (!readXRef(&prevXRefOffset, &followedXRefStm, xrefStreamObjsNum)) {
+ prevXRefOffset = 0;
+ }
+
+ // if there was a problem with the xref table, or we haven't found the entry
+ // we were looking for, try to reconstruct the xref
+ if (!ok || (!prevXRefOffset && untilEntryNum != -1 && entries[untilEntryNum].type == xrefEntryNone)) {
+ GBool wasReconstructed = false;
+ if (!(ok = constructXRef(&wasReconstructed))) {
+ errCode = errDamaged;
+ break;
+ }
+ break;
+ }
+ }
+}
+
+XRefEntry *XRef::getEntry(int i, GBool complainIfMissing)
+{
+ if (i >= size || entries[i].type == xrefEntryNone) {
+
+ if ((!xRefStream) && mainXRefEntriesOffset) {
+ if (!parseEntry(mainXRefEntriesOffset + 20*i, &entries[i])) {
+ error(errSyntaxError, -1, "Failed to parse XRef entry [{0:d}].", i);
+ }
+ } else {
+ // Read XRef tables until the entry we're looking for is found
+ readXRefUntil(i);
+
+ // We might have reconstructed the xref
+ // Check again i is in bounds
+ if (unlikely(i >= size)) {
+ static XRefEntry dummy;
+ dummy.offset = 0;
+ dummy.gen = -1;
+ dummy.type = xrefEntryNone;
+ dummy.flags = 0;
+ return &dummy;
+ }
+
+ if (entries[i].type == xrefEntryNone) {
+ if (complainIfMissing) {
+ error(errSyntaxError, -1, "Invalid XRef entry");
+ }
+ entries[i].type = xrefEntryFree;
+ }
+ }
+ }
+
+ return &entries[i];
+}
+
+// Recursively sets the Unencrypted flag in all referenced xref entries
+void XRef::markUnencrypted(Object *obj) {
+ Object obj1;
+
+ switch (obj->getType()) {
+ case objArray:
+ {
+ Array *array = obj->getArray();
+ for (int i = 0; i < array->getLength(); i++) {
+ markUnencrypted(array->getNF(i, &obj1));
+ obj1.free();
+ }
+ break;
+ }
+ case objStream:
+ case objDict:
+ {
+ Dict *dict;
+ if (obj->getType() == objStream) {
+ Stream *stream = obj->getStream();
+ dict = stream->getDict();
+ } else {
+ dict = obj->getDict();
+ }
+ for (int i = 0; i < dict->getLength(); i++) {
+ markUnencrypted(dict->getValNF(i, &obj1));
+ obj1.free();
+ }
+ break;
+ }
+ case objRef:
+ {
+ Ref ref = obj->getRef();
+ XRefEntry *e = getEntry(ref.num);
+ if (e->getFlag(XRefEntry::Unencrypted))
+ return; // We've already been here: prevent infinite recursion
+ e->setFlag(XRefEntry::Unencrypted, gTrue);
+ fetch(ref.num, ref.gen, &obj1);
+ markUnencrypted(&obj1);
+ obj1.free();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void XRef::scanSpecialFlags() {
+ if (scannedSpecialFlags) {
+ return;
+ }
+ scannedSpecialFlags = gTrue;
+
+ // "Rewind" the XRef linked list, so that readXRefUntil re-reads all XRef
+ // tables/streams, even those that had already been parsed
+ prevXRefOffset = mainXRefOffset;
+
+ std::vector<int> xrefStreamObjNums;
+ if (!streamEndsLen) { // don't do it for already reconstructed xref
+ readXRefUntil(-1 /* read all xref sections */, &xrefStreamObjNums);
+ }
+
+ // Mark object streams as DontRewrite, because we write each object
+ // individually in full rewrite mode.
+ for (int i = 0; i < size; ++i) {
+ if (entries[i].type == xrefEntryCompressed) {
+ const int objStmNum = entries[i].offset;
+ if (unlikely(objStmNum < 0 || objStmNum >= size)) {
+ error(errSyntaxError, -1, "Compressed object offset out of xref bounds");
+ } else {
+ getEntry(objStmNum)->setFlag(XRefEntry::DontRewrite, gTrue);
+ }
+ }
+ }
+
+ // Mark XRef streams objects as Unencrypted and DontRewrite
+ for (size_t i = 0; i < xrefStreamObjNums.size(); ++i) {
+ const int objNum = xrefStreamObjNums.at(i);
+ getEntry(objNum)->setFlag(XRefEntry::Unencrypted, gTrue);
+ getEntry(objNum)->setFlag(XRefEntry::DontRewrite, gTrue);
+ }
+
+ // Mark objects referred from the Encrypt dict as Unencrypted
+ Object obj;
+ markUnencrypted(trailerDict.dictLookupNF("Encrypt", &obj));
+ obj.free();
+}
+
+void XRef::markUnencrypted() {
+ // Mark objects referred from the Encrypt dict as Unencrypted
+ Object obj;
+ trailerDict.dictLookupNF("Encrypt", &obj);
+ if (obj.isRef()) {
+ XRefEntry *e = getEntry(obj.getRefNum());
+ e->setFlag(XRefEntry::Unencrypted, gTrue);
+ }
+ obj.free();
+}
+
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/XRef.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/XRef.h
new file mode 100644
index 00000000000..70065d8963e
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/XRef.h
@@ -0,0 +1,281 @@
+//========================================================================
+//
+// XRef.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
+// Copyright (C) 2006, 2008, 2010-2013 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
+// Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2010 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@kabelmail.de>
+// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef XREF_H
+#define XREF_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "poppler-config.h"
+#include "goo/gtypes.h"
+#include "goo/GooMutex.h"
+#include "Object.h"
+#include "Stream.h"
+
+#include <vector>
+
+class Dict;
+class Stream;
+class Parser;
+class PopplerCache;
+
+//------------------------------------------------------------------------
+// XRef
+//------------------------------------------------------------------------
+
+enum XRefEntryType {
+ xrefEntryFree,
+ xrefEntryUncompressed,
+ xrefEntryCompressed,
+ xrefEntryNone
+};
+
+struct XRefEntry {
+ Goffset offset;
+ int gen;
+ XRefEntryType type;
+ int flags;
+ Object obj; //if this entry was updated, obj will contains the updated object
+
+ enum Flag {
+ // Regular flags
+ Updated, // Entry was modified
+
+ // Special flags -- available only after xref->scanSpecialFlags() is run
+ Unencrypted, // Entry is stored in unencrypted form (meaningless in unencrypted documents)
+ DontRewrite // Entry must not be written back in case of full rewrite
+ };
+
+ inline GBool getFlag(Flag flag) {
+ const int mask = (1 << (int)flag);
+ return (flags & mask) != 0;
+ }
+
+ inline void setFlag(Flag flag, GBool value) {
+ const int mask = (1 << (int)flag);
+ if (value) {
+ flags |= mask;
+ } else {
+ flags &= ~mask;
+ }
+ }
+};
+
+class XRef {
+public:
+
+ // Constructor, create an empty XRef, used for PDF writing
+ XRef();
+ // Constructor, create an empty XRef but with info dict, used for PDF writing
+ XRef(Object *trailerDictA);
+ // Constructor. Read xref table from stream.
+ XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA = 0, GBool *wasReconstructed = NULL, GBool reconstruct = false);
+
+ // Destructor.
+ ~XRef();
+
+ // Copy xref but with new base stream!
+ XRef *copy();
+
+ // Is xref table valid?
+ GBool isOk() { return ok; }
+
+ // Is the last XRef section a stream or a table?
+ GBool isXRefStream() { return xRefStream; }
+
+ // Get the error code (if isOk() returns false).
+ int getErrorCode() { return errCode; }
+
+ // Set the encryption parameters.
+ void setEncryption(int permFlagsA, GBool ownerPasswordOkA,
+ Guchar *fileKeyA, int keyLengthA,
+ int encVersionA, int encRevisionA,
+ CryptAlgorithm encAlgorithmA);
+ // Mark Encrypt entry as Unencrypted
+ void markUnencrypted();
+
+ void getEncryptionParameters(Guchar **fileKeyA, CryptAlgorithm *encAlgorithmA, int *keyLengthA);
+
+ // Is the file encrypted?
+ GBool isEncrypted() { return encrypted; }
+
+ // Check various permissions.
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse);
+ GBool okToPrintHighRes(GBool ignoreOwnerPW = gFalse);
+ GBool okToChange(GBool ignoreOwnerPW = gFalse);
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse);
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse);
+ GBool okToFillForm(GBool ignoreOwnerPW = gFalse);
+ GBool okToAccessibility(GBool ignoreOwnerPW = gFalse);
+ GBool okToAssemble(GBool ignoreOwnerPW = gFalse);
+ int getPermFlags() { return permFlags; }
+
+ // Get catalog object.
+ Object *getCatalog(Object *obj);
+
+ // Fetch an indirect reference.
+ Object *fetch(int num, int gen, Object *obj, int recursion = 0);
+
+ // Return the document's Info dictionary (if any).
+ Object *getDocInfo(Object *obj);
+ Object *getDocInfoNF(Object *obj);
+
+ // Return the number of objects in the xref table.
+ int getNumObjects() { return size; }
+
+ // Return the catalog object reference.
+ int getRootNum() { return rootNum; }
+ int getRootGen() { return rootGen; }
+
+ // Get end position for a stream in a damaged file.
+ // Returns false if unknown or file is not damaged.
+ GBool getStreamEnd(Goffset streamStart, Goffset *streamEnd);
+
+ // Retuns the entry that belongs to the offset
+ int getNumEntry(Goffset offset);
+
+ // Scans the document and sets special flags in all xref entries. One of those
+ // flags is Unencrypted, which affects how the object is fetched. Therefore,
+ // this function must be called before fetching unencrypted objects (e.g.
+ // Encrypt dictionary, XRef streams). Note that the code that initializes
+ // decryption doesn't need to call this function, because it runs before
+ // decryption is enabled, and therefore the Unencrypted flag is ignored.
+ void scanSpecialFlags();
+
+ // Direct access.
+ XRefEntry *getEntry(int i, GBool complainIfMissing = gTrue);
+ Object *getTrailerDict() { return &trailerDict; }
+
+ // Write access
+ void setModifiedObject(Object* o, Ref r);
+ Ref addIndirectObject (Object* o);
+ void removeIndirectObject(Ref r);
+ void add(int num, int gen, Goffset offs, GBool used);
+
+ // Output XRef table to stream
+ void writeTableToFile(OutStream* outStr, GBool writeAllEntries);
+ // Output XRef stream contents to GooString and fill trailerDict fields accordingly
+ void writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref);
+
+ // to be thread safe during write where changes are not allowed
+ void lock();
+ void unlock();
+
+private:
+
+ BaseStream *str; // input stream
+ Goffset start; // offset in file (to allow for garbage
+ // at beginning of file)
+ XRefEntry *entries; // xref entries
+ int capacity; // size of <entries> array
+ int size; // number of entries
+ int rootNum, rootGen; // catalog dict
+ GBool ok; // true if xref table is valid
+ int errCode; // error code (if <ok> is false)
+ Object trailerDict; // trailer dictionary
+ Goffset *streamEnds; // 'endstream' positions - only used in
+ // damaged files
+ int streamEndsLen; // number of valid entries in streamEnds
+ PopplerCache *objStrs; // cached object streams
+ GBool encrypted; // true if file is encrypted
+ int encRevision;
+ int encVersion; // encryption algorithm
+ CryptAlgorithm encAlgorithm; // encryption algorithm
+ int keyLength; // length of key, in bytes
+ int permFlags; // permission bits
+ Guchar fileKey[32]; // file decryption key
+ GBool ownerPasswordOk; // true if owner password is correct
+ Goffset prevXRefOffset; // position of prev XRef section (= next to read)
+ Goffset mainXRefEntriesOffset; // offset of entries in main XRef table
+ GBool xRefStream; // true if last XRef section is a stream
+ Goffset mainXRefOffset; // position of the main XRef table/stream
+ GBool scannedSpecialFlags; // true if scanSpecialFlags has been called
+ GBool strOwner; // true if str is owned by the instance
+#if MULTITHREADED
+ GooMutex mutex;
+#endif
+
+ void init();
+ int reserve(int newSize);
+ int resize(int newSize);
+ GBool readXRef(Goffset *pos, std::vector<Goffset> *followedXRefStm, std::vector<int> *xrefStreamObjsNum);
+ GBool readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *followedXRefStm, std::vector<int> *xrefStreamObjsNum);
+ GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n);
+ GBool readXRefStream(Stream *xrefStr, Goffset *pos);
+ GBool constructXRef(GBool *wasReconstructed, GBool needCatalogDict = gFalse);
+ GBool parseEntry(Goffset offset, XRefEntry *entry);
+ void readXRefUntil(int untilEntryNum, std::vector<int> *xrefStreamObjsNum = NULL);
+ void markUnencrypted(Object *obj);
+
+ class XRefWriter {
+ public:
+ virtual void startSection(int first, int count) = 0;
+ virtual void writeEntry(Goffset offset, int gen, XRefEntryType type) = 0;
+ virtual ~XRefWriter() {};
+ };
+
+ // XRefWriter subclass that writes a XRef table
+ class XRefTableWriter: public XRefWriter {
+ public:
+ XRefTableWriter(OutStream* outStrA);
+ void startSection(int first, int count);
+ void writeEntry(Goffset offset, int gen, XRefEntryType type);
+ private:
+ OutStream* outStr;
+ };
+
+ // XRefWriter subclass that writes a XRef stream
+ class XRefStreamWriter: public XRefWriter {
+ public:
+ XRefStreamWriter(Object *index, GooString *stmBuf, int offsetSize);
+ void startSection(int first, int count);
+ void writeEntry(Goffset offset, int gen, XRefEntryType type);
+ private:
+ Object *index;
+ GooString *stmBuf;
+ int offsetSize;
+ };
+
+ // Dummy XRefWriter subclass that only checks if all offsets fit in 4 bytes
+ class XRefPreScanWriter: public XRefWriter {
+ public:
+ XRefPreScanWriter();
+ void startSection(int first, int count);
+ void writeEntry(Goffset offset, int gen, XRefEntryType type);
+
+ GBool hasOffsetsBeyond4GB;
+ };
+
+ void writeXRef(XRefWriter *writer, GBool writeAllEntries);
+};
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/XpdfPluginAPI.cc b/Build/source/libs/poppler/poppler-0.36.0/poppler/XpdfPluginAPI.cc
new file mode 100644
index 00000000000..834c681d991
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/XpdfPluginAPI.cc
@@ -0,0 +1,243 @@
+//========================================================================
+//
+// XpdfPluginAPI.cc
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include "config.h"
+
+#ifdef ENABLE_PLUGINS
+
+#include "gmem.h"
+#include "GlobalParams.h"
+#include "Object.h"
+#include "PDFDoc.h"
+#include "XpdfPluginAPI.h"
+
+//------------------------------------------------------------------------
+
+//~ This should use a pool of Objects; change xpdfFreeObj to match.
+static Object *allocObj() {
+ return (Object *)gmalloc(sizeof(Object));
+}
+
+//------------------------------------------------------------------------
+// Document access functions
+//------------------------------------------------------------------------
+
+XpdfObject _xpdfGetInfoDict(XpdfDoc doc) {
+ Object *obj;
+
+ obj = allocObj();
+ return (XpdfObject)((PDFDoc *)doc)->getDocInfo(obj);
+}
+
+XpdfObject _xpdfGetCatalog(XpdfDoc doc) {
+ Object *obj;
+
+ obj = allocObj();
+ return (XpdfObject)((PDFDoc *)doc)->getXRef()->getCatalog(obj);
+}
+
+//------------------------------------------------------------------------
+// Object access functions.
+//------------------------------------------------------------------------
+
+XpdfBool _xpdfObjIsBool(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isBool();
+}
+
+XpdfBool _xpdfObjIsInt(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isInt();
+}
+
+XpdfBool _xpdfObjIsReal(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isReal();
+}
+
+XpdfBool _xpdfObjIsNumber(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isNum();
+}
+
+XpdfBool _xpdfObjIsString(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isString();
+}
+
+XpdfBool _xpdfObjIsName(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isName();
+}
+
+XpdfBool _xpdfObjIsNull(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isNull();
+}
+
+XpdfBool _xpdfObjIsArray(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isArray();
+}
+
+XpdfBool _xpdfObjIsDict(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isDict();
+}
+
+XpdfBool _xpdfObjIsStream(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isStream();
+}
+
+XpdfBool _xpdfObjIsRef(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->isRef();
+}
+
+XpdfBool _xpdfBoolValue(XpdfObject obj) {
+ return (XpdfBool)((Object *)obj)->getBool();
+}
+
+int _xpdfIntValue(XpdfObject obj) {
+ if (!((Object *)obj)->isInt()) {
+ return 0;
+ }
+ return ((Object *)obj)->getInt();
+}
+
+double _xpdfRealValue(XpdfObject obj) {
+ if (!((Object *)obj)->isReal()) {
+ return 0;
+ }
+ return ((Object *)obj)->getReal();
+}
+
+double _xpdfNumberValue(XpdfObject obj) {
+ if (!((Object *)obj)->isNum()) {
+ return 0;
+ }
+ return ((Object *)obj)->getNum();
+}
+
+int _xpdfStringLength(XpdfObject obj) {
+ if (!((Object *)obj)->isString()) {
+ return 0;
+ }
+ return ((Object *)obj)->getString()->getLength();
+}
+
+char *_xpdfStringValue(XpdfObject obj) {
+ if (!((Object *)obj)->isString()) {
+ return 0;
+ }
+ return ((Object *)obj)->getString()->getCString();
+}
+
+char *_xpdfNameValue(XpdfObject obj) {
+ if (!((Object *)obj)->isName()) {
+ return NULL;
+ }
+ return ((Object *)obj)->getName();
+}
+
+int _xpdfArrayLength(XpdfObject obj) {
+ if (!((Object *)obj)->isArray()) {
+ return 0;
+ }
+ return ((Object *)obj)->arrayGetLength();
+}
+
+XpdfObject _xpdfArrayGet(XpdfObject obj, int idx) {
+ Object *elem;
+
+ elem = allocObj();
+ if (!((Object *)obj)->isArray()) {
+ return (XpdfObject)elem->initNull();
+ }
+ return (XpdfObject)((Object *)obj)->arrayGet(idx, elem);
+}
+
+XpdfObject _xpdfDictGet(XpdfObject obj, char *key) {
+ Object *elem;
+
+ elem = allocObj();
+ if (!((Object *)obj)->isDict()) {
+ return (XpdfObject)elem->initNull();
+ }
+ return (XpdfObject)((Object *)obj)->dictLookup(key, elem);
+}
+
+void _xpdfFreeObj(XpdfObject obj) {
+ ((Object *)obj)->free();
+ gfree(obj);
+}
+
+//------------------------------------------------------------------------
+// Memory allocation functions
+//------------------------------------------------------------------------
+
+void *_xpdfMalloc(int size) {
+ return gmalloc(size);
+}
+
+void *_xpdfRealloc(void *p, int size) {
+ return grealloc(p, size);
+}
+
+void _xpdfFree(void *p) {
+ gfree(p);
+}
+
+//------------------------------------------------------------------------
+// Security handlers
+//------------------------------------------------------------------------
+
+void _xpdfRegisterSecurityHandler(XpdfSecurityHandler *handler) {
+ if (handler->version <= xpdfPluginAPIVersion) {
+ globalParams->addSecurityHandler(handler);
+ }
+}
+
+//------------------------------------------------------------------------
+
+XpdfPluginVecTable xpdfPluginVecTable = {
+ xpdfPluginAPIVersion,
+ &_xpdfGetInfoDict,
+ &_xpdfGetCatalog,
+ &_xpdfObjIsBool,
+ &_xpdfObjIsInt,
+ &_xpdfObjIsReal,
+ &_xpdfObjIsString,
+ &_xpdfObjIsName,
+ &_xpdfObjIsNull,
+ &_xpdfObjIsArray,
+ &_xpdfObjIsDict,
+ &_xpdfObjIsStream,
+ &_xpdfObjIsRef,
+ &_xpdfBoolValue,
+ &_xpdfIntValue,
+ &_xpdfRealValue,
+ &_xpdfStringLength,
+ &_xpdfStringValue,
+ &_xpdfNameValue,
+ &_xpdfArrayLength,
+ &_xpdfArrayGet,
+ &_xpdfDictGet,
+ &_xpdfFreeObj,
+ &_xpdfMalloc,
+ &_xpdfRealloc,
+ &_xpdfFree,
+ &_xpdfRegisterSecurityHandler,
+};
+
+#endif // ENABLE_PLUGINS
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/XpdfPluginAPI.h b/Build/source/libs/poppler/poppler-0.36.0/poppler/XpdfPluginAPI.h
new file mode 100644
index 00000000000..6ed890a8f1f
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/XpdfPluginAPI.h
@@ -0,0 +1,342 @@
+/*
+ * XpdfPluginAPI.h
+ *
+ * Copyright 2004 Glyph & Cog, LLC
+ */
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com>
+// Copyright (C) 2014 Peter Breitenlohner <peb@mppmu.mpg.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef XPDFPLUGINAPI_H
+#define XPDFPLUGINAPI_H
+
+#ifdef _WIN32
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+#else
+#define Object XtObject
+#include <X11/Intrinsic.h>
+#undef Object
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*------------------------------------------------------------------------
+ * Macros
+ *------------------------------------------------------------------------*/
+
+/*
+ * The current API version.
+ */
+#define xpdfPluginAPIVersion 1
+
+#ifdef _WIN32
+# ifdef __cplusplus
+# define PLUGINFUNC(retType) extern "C" __declspec(dllexport) retType
+# else
+# define PLUGINFUNC(retType) extern __declspec(dllexport) retType
+# endif
+#else
+# ifdef __cplusplus
+# define PLUGINFUNC(retType) extern "C" retType
+# else
+# define PLUGINFUNC(retType) extern retType
+# endif
+#endif
+
+/*------------------------------------------------------------------------
+ * Plugin setup/cleanup
+ *------------------------------------------------------------------------*/
+
+/*
+ * All plugins are required to implement two functions:
+ *
+ * -- Initialize the plugin. Returns non-zero if successful.
+ * PLUGINFUNC(XpdfBool) xpdfInitPlugin(void);
+ *
+ * -- Free the plugin.
+ * PLUGINFUNC(void) xpdfFreePlugin(void);
+ */
+
+/*------------------------------------------------------------------------
+ * Types
+ *------------------------------------------------------------------------*/
+
+/*
+ * Standard C boolean -- zero = false, non-zero = true.
+ */
+typedef int XpdfBool;
+#define xpdfTrue 1
+#define xpdfFalse 0
+
+/*
+ * PDF document handle.
+ */
+typedef struct _XpdfDoc *XpdfDoc;
+
+/*
+ * PDF object handle.
+ */
+typedef struct _XpdfObject *XpdfObject;
+
+/*
+ * Document access permissions. Any of these can be bitwise 'or'ed
+ * together. If xpdfPermissionOpen is not included, the document
+ * cannot be opened at all, and the other bits are ignored.
+ */
+typedef unsigned int XpdfPermission;
+#define xpdfPermissionOpen (1 << 0)
+#define xpdfPermissionPrint (1 << 2)
+#define xpdfPermissionChange (1 << 3)
+#define xpdfPermissionCopy (1 << 4)
+#define xpdfPermissionNotes (1 << 5)
+
+/*------------------------------------------------------------------------
+ * Security handler
+ *------------------------------------------------------------------------*/
+
+/*
+ * XpdfSecurityHandler - a security handler plugin should create one
+ * of these and pass it to xpdfRegisterSecurityHandler.
+ */
+#ifdef __cplusplus
+struct XpdfSecurityHandler {
+#else
+typedef struct {
+#endif
+
+ /*
+ * Version of the security handler spec (this document) -- use
+ * xpdfPluginAPIVersion.
+ */
+ int version;
+
+ /*
+ * Security handler name.
+ */
+ char *name;
+
+ /*
+ * Any global data the security handler needs. XpdfViewer will pass
+ * this pointer to all handler functions as the <handlerData>
+ * argument.
+ */
+ void *handlerData;
+
+ /*
+ * Allocate and initialize data for a new document. XpdfViewer will
+ * pass the returned pointer to all other handler functions as the
+ * <docData> argument. Returns non-zero if successful.
+ */
+ XpdfBool (*newDoc)(void *handlerData, XpdfDoc doc,
+ XpdfObject encryptDict, void **docData);
+
+ /*
+ * Free the data allocated by newDoc.
+ */
+ void (*freeDoc)(void *handlerData, void *docData);
+
+ /*
+ * Construct authorization data based on the supplied owner and user
+ * passwords (either or both of which may be NULL). This function
+ * is called in "batch" mode, i.e., if the password was supplied on
+ * the command line or via an Xpdf library API. It should not
+ * generate any user interaction (e.g., a password dialog). It is
+ * not required to support this function: the makeAuthData function
+ * pointer can be set to NULL. Returns non-zero if successful.
+ */
+ XpdfBool (*makeAuthData)(void *handlerData, void *docData,
+ char *ownerPassword, char *userPassword,
+ void **authData);
+
+ /*
+ * Request any needed information (e.g., a password) from the user,
+ * and construct an authorization data object. Returns non-zero if
+ * successful.
+ */
+ XpdfBool (*getAuthData)(void *handlerData, void *docData,
+ void **authData);
+
+ /*
+ * Free the data allocated by getAuthData.
+ */
+ void (*freeAuthData)(void *handlerData, void *docData,
+ void *authData);
+
+ /*
+ * Request permission to access the document. This returns all
+ * permissions granted by authData.
+ */
+ XpdfPermission (*authorize)(void *handlerData, void *docData,
+ void *authData);
+
+ /*
+ * Get the decryption key and algorithm version associated with the
+ * document. Returns non-zero if successful.
+ */
+ XpdfBool (*getKey)(void *handlerData, void *docData,
+ char **key, int *keyLen, int *cryptVersion, int *cryptRevision);
+
+ /*
+ * Free the data allocated by getKey.
+ */
+ void (*freeKey)(void *handlerData, void *docData,
+ char *key, int keyLen);
+
+#ifdef __cplusplus
+};
+#else
+} XpdfSecurityHandler;
+#endif
+
+/*------------------------------------------------------------------------*/
+
+typedef struct {
+ int version;
+
+/*------------------------------------------------------------------------
+ * Document access functions
+ *------------------------------------------------------------------------*/
+
+/*
+ * Get a document's info dictionary. (The returned object must be
+ * freed with xpdfFreeObj.)
+ */
+XpdfObject (*_xpdfGetInfoDict)(XpdfDoc doc);
+
+/*
+ * Get a document's catalog ("root") dictionary. (The returned object
+ * must be freed with xpdfFreeObj.)
+ */
+XpdfObject (*_xpdfGetCatalog)(XpdfDoc doc);
+
+/*------------------------------------------------------------------------
+ * Object access functions
+ *------------------------------------------------------------------------*/
+
+/*
+ * Check an object's type.
+ */
+XpdfBool (*_xpdfObjIsBool)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsInt)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsReal)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsString)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsName)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsNull)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsArray)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsDict)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsStream)(XpdfObject obj);
+XpdfBool (*_xpdfObjIsRef)(XpdfObject obj);
+
+/*
+ * Value access.
+ * (Objects returned by xpdfArrayGet and xpdfDictGet must be freed
+ * with xpdfFreeObj.)
+ */
+XpdfBool (*_xpdfBoolValue)(XpdfObject obj);
+int (*_xpdfIntValue)(XpdfObject obj);
+double (*_xpdfRealValue)(XpdfObject obj);
+int (*_xpdfStringLength)(XpdfObject obj);
+char *(*_xpdfStringValue)(XpdfObject obj);
+char *(*_xpdfNameValue)(XpdfObject obj);
+int (*_xpdfArrayLength)(XpdfObject obj);
+XpdfObject (*_xpdfArrayGet)(XpdfObject obj, int idx);
+XpdfObject (*_xpdfDictGet)(XpdfObject obj, char *key);
+
+/*
+ * Object destruction. NB: *all* objects must be freed after use.
+ */
+void (*_xpdfFreeObj)(XpdfObject obj);
+
+/*------------------------------------------------------------------------
+ * Memory allocation functions
+ *------------------------------------------------------------------------*/
+
+void *(*_xpdfMalloc)(int size);
+void *(*_xpdfRealloc)(void *p, int size);
+void (*_xpdfFree)(void *p);
+
+/*------------------------------------------------------------------------
+ * Security handler functions
+ *------------------------------------------------------------------------*/
+
+/*
+ * Register a new security handler.
+ */
+void (*_xpdfRegisterSecurityHandler)(XpdfSecurityHandler *handler);
+
+/*------------------------------------------------------------------------*/
+
+} XpdfPluginVecTable;
+
+#ifdef _WIN32
+
+extern __declspec(dllexport) XpdfPluginVecTable xpdfPluginVecTable;
+
+#define xpdfPluginSetup \
+ extern __declspec(dllexport) \
+ XpdfPluginVecTable xpdfPluginVecTable = {xpdfPluginAPIVersion};
+
+#else
+
+extern XpdfPluginVecTable xpdfPluginVecTable;
+
+#define xpdfPluginSetup \
+ XpdfPluginVecTable xpdfPluginVecTable = {xpdfPluginAPIVersion};
+
+#endif
+
+#define xpdfGetInfoDict (*xpdfPluginVecTable._xpdfGetInfoDict)
+#define xpdfGetCatalog (*xpdfPluginVecTable._xpdfGetCatalog)
+#ifdef _WIN32
+#define xpdfWin32GetWindow (*xpdfPluginVecTable._xpdfWin32GetWindow)
+#else
+#define xpdfXGetWindow (*xpdfPluginVecTable._xpdfXGetWindow)
+#endif
+#define xpdfObjIsBool (*xpdfPluginVecTable._xpdfObjIsBool)
+#define xpdfObjIsInt (*xpdfPluginVecTable._xpdfObjIsInt)
+#define xpdfObjIsReal (*xpdfPluginVecTable._xpdfObjIsReal)
+#define xpdfObjIsString (*xpdfPluginVecTable._xpdfObjIsString)
+#define xpdfObjIsName (*xpdfPluginVecTable._xpdfObjIsName)
+#define xpdfObjIsNull (*xpdfPluginVecTable._xpdfObjIsNull)
+#define xpdfObjIsArray (*xpdfPluginVecTable._xpdfObjIsArray)
+#define xpdfObjIsDict (*xpdfPluginVecTable._xpdfObjIsDict)
+#define xpdfObjIsStream (*xpdfPluginVecTable._xpdfObjIsStream)
+#define xpdfObjIsRef (*xpdfPluginVecTable._xpdfObjIsRef)
+#define xpdfBoolValue (*xpdfPluginVecTable._xpdfBoolValue)
+#define xpdfIntValue (*xpdfPluginVecTable._xpdfIntValue)
+#define xpdfRealValue (*xpdfPluginVecTable._xpdfRealValue)
+#define xpdfStringLength (*xpdfPluginVecTable._xpdfStringLength)
+#define xpdfStringValue (*xpdfPluginVecTable._xpdfStringValue)
+#define xpdfNameValue (*xpdfPluginVecTable._xpdfNameValue)
+#define xpdfArrayLength (*xpdfPluginVecTable._xpdfArrayLength)
+#define xpdfArrayGet (*xpdfPluginVecTable._xpdfArrayGet)
+#define xpdfDictGet (*xpdfPluginVecTable._xpdfDictGet)
+#define xpdfFreeObj (*xpdfPluginVecTable._xpdfFreeObj)
+#define xpdfMalloc (*xpdfPluginVecTable._xpdfMalloc)
+#define xpdfRealloc (*xpdfPluginVecTable._xpdfRealloc)
+#define xpdfFree (*xpdfPluginVecTable._xpdfFree)
+#define xpdfRegisterSecurityHandler (*xpdfPluginVecTable._xpdfRegisterSecurityHandler)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/gen-unicode-tables.py b/Build/source/libs/poppler/poppler-0.36.0/poppler/gen-unicode-tables.py
new file mode 100644
index 00000000000..282f6e52518
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/gen-unicode-tables.py
@@ -0,0 +1,38 @@
+UNICODE_LAST_CHAR_PART1 = 0x2FAFF
+HANGUL_S_BASE = 0xAC00
+HANGUL_S_COUNT = 19 * 21 * 28
+import unicodedata
+
+print """// Generated by gen-unicode-tables.py
+
+typedef struct {
+ Unicode character;
+ int length;
+ int offset;
+} decomposition;
+"""
+
+decomp_table = []
+max_index = 0
+decomp_expansion_index = {}
+decomp_expansion = []
+for u in xrange(0, UNICODE_LAST_CHAR_PART1):
+ if (u >= HANGUL_S_BASE and u < HANGUL_S_BASE + HANGUL_S_COUNT):
+ continue
+ norm = tuple(map(ord, unicodedata.normalize("NFKD", unichr(u))))
+ if norm != (u,):
+ try:
+ i = decomp_expansion_index[norm]
+ decomp_table.append((u, len(norm), i))
+ except KeyError:
+ decomp_table.append((u, len(norm), max_index))
+ decomp_expansion_index[norm] = max_index
+ decomp_expansion.append((norm, max_index))
+ max_index += len(norm)
+print "#define DECOMP_TABLE_LENGTH %d\n" % len(decomp_table)
+print "static const decomposition decomp_table[] = {\n%s\n};\n" % ", \n".join(
+ " { 0x%x, %d, %d }" % (character, length, offset)
+ for character, length, offset in decomp_table)
+print "static const Unicode decomp_expansion[] = {\n%s\n};\n" % ", \n".join(
+ " %s /* offset %d */ " % (", ".join("0x%x" % u for u in norm),
+ index) for norm, index in decomp_expansion)
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/poppler-config.h.cmake b/Build/source/libs/poppler/poppler-0.36.0/poppler/poppler-config.h.cmake
new file mode 100644
index 00000000000..b087a693f92
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/poppler-config.h.cmake
@@ -0,0 +1,195 @@
+//================================================= -*- mode: c++ -*- ====
+//
+// poppler-config.h
+//
+// Copyright 1996-2011 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com>
+// Copyright (C) 2014 Hib Eris <hib@hiberis.nl>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef POPPLER_CONFIG_H
+#define POPPLER_CONFIG_H
+
+#include <stdio.h>
+
+// We duplicate some of the config.h #define's here since they are
+// used in some of the header files we install. The #ifndef/#endif
+// around #undef look odd, but it's to silence warnings about
+// redefining those symbols.
+
+/* Defines the poppler version. */
+#ifndef POPPLER_VERSION
+#define POPPLER_VERSION "${POPPLER_VERSION}"
+#endif
+
+/* Enable multithreading support. */
+#ifndef MULTITHREADED
+#cmakedefine MULTITHREADED 1
+#endif
+
+/* Use fixedpoint. */
+#ifndef USE_FIXEDPOINT
+#cmakedefine USE_FIXEDPOINT 1
+#endif
+
+/* Use single precision arithmetic in the Splash backend */
+#ifndef USE_FLOAT
+#cmakedefine USE_FLOAT 1
+#endif
+
+/* Include support for OPI comments. */
+#ifndef OPI_SUPPORT
+#cmakedefine OPI_SUPPORT 1
+#endif
+
+/* Enable word list support. */
+#ifndef TEXTOUT_WORD_LIST
+#cmakedefine TEXTOUT_WORD_LIST 1
+#endif
+
+/* Support for curl is compiled in. */
+#ifndef POPPLER_HAS_CURL_SUPPORT
+#cmakedefine POPPLER_HAS_CURL_SUPPORT 1
+#endif
+
+/* Use libjpeg instead of builtin jpeg decoder. */
+#ifndef ENABLE_LIBJPEG
+#cmakedefine ENABLE_LIBJPEG 1
+#endif
+
+/* Build against libtiff. */
+#ifndef ENABLE_LIBTIFF
+#cmakedefine ENABLE_LIBTIFF 1
+#endif
+
+/* Build against libpng. */
+#ifndef ENABLE_LIBPNG
+#cmakedefine ENABLE_LIBPNG 1
+#endif
+
+/* Use zlib instead of builtin zlib decoder. */
+#ifndef ENABLE_ZLIB
+#cmakedefine ENABLE_ZLIB 1
+#endif
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#ifndef HAVE_DIRENT_H
+#cmakedefine HAVE_DIRENT_H 1
+#endif
+
+/* Defines if gettimeofday is available on your system */
+#ifndef HAVE_GETTIMEOFDAY
+#cmakedefine HAVE_GETTIMEOFDAY 1
+#endif
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#ifndef HAVE_NDIR_H
+#cmakedefine HAVE_NDIR_H 1
+#endif
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#ifndef HAVE_SYS_DIR_H
+#cmakedefine HAVE_SYS_DIR_H 1
+#endif
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#ifndef HAVE_SYS_NDIR_H
+#cmakedefine HAVE_SYS_NDIR_H 1
+#endif
+
+/* Have FreeType2 include files */
+#ifndef HAVE_FREETYPE_H
+#cmakedefine HAVE_FREETYPE_H 1
+#endif
+
+/* Defines if use cms */
+#ifndef USE_CMS
+#cmakedefine USE_CMS 1
+#endif
+
+// Also, there are preprocessor symbols in the header files
+// that are used but never defined when building poppler using configure
+// or cmake: DISABLE_OUTLINE, DEBUG_MEM, SPLASH_CMYK, HAVE_T1LIB_H,
+// ENABLE_PLUGINS, DEBUG_FORMS, HAVE_FREETYPE_FREETYPE_H
+
+//------------------------------------------------------------------------
+// version
+//------------------------------------------------------------------------
+
+// copyright notice
+#define popplerCopyright "Copyright 2005-2015 The Poppler Developers - http://poppler.freedesktop.org"
+#define xpdfCopyright "Copyright 1996-2011 Glyph & Cog, LLC"
+
+//------------------------------------------------------------------------
+// popen
+//------------------------------------------------------------------------
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define popen _popen
+#define pclose _pclose
+#endif
+
+#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(_WIN32) || defined(__DJGPP__) || defined(MACOS)
+#define POPEN_READ_MODE "rb"
+#else
+#define POPEN_READ_MODE "r"
+#endif
+
+//------------------------------------------------------------------------
+// Win32 stuff
+//------------------------------------------------------------------------
+
+#if defined(_WIN32) && !defined(_MSC_VER)
+#include <windef.h>
+#else
+#define CDECL
+#endif
+
+#if defined(_WIN32)
+#ifdef _MSC_VER
+#define strtok_r strtok_s
+#elif __MINGW32__ && !defined(__WINPTHREADS_VERSION)
+char * strtok_r (char *s, const char *delim, char **save_ptr);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+// Compiler
+//------------------------------------------------------------------------
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#ifdef __MINGW_PRINTF_FORMAT
+#define GCC_PRINTF_FORMAT(fmt_index, va_index) \
+ __attribute__((__format__(__MINGW_PRINTF_FORMAT, fmt_index, va_index)))
+#else
+#define GCC_PRINTF_FORMAT(fmt_index, va_index) \
+ __attribute__((__format__(__printf__, fmt_index, va_index)))
+#endif
+#else
+#define GCC_PRINTF_FORMAT(fmt_index, va_index)
+#endif
+
+#if defined(_MSC_VER)
+#define fmax(a, b) std::max(a, b)
+#define fmin(a, b) std::min(a, b)
+#endif
+
+
+#endif /* POPPLER_CONFIG_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/poppler-config.h.in b/Build/source/libs/poppler/poppler-0.36.0/poppler/poppler-config.h.in
new file mode 100644
index 00000000000..f73d0f66ee9
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/poppler-config.h.in
@@ -0,0 +1,195 @@
+//================================================= -*- mode: c++ -*- ====
+//
+// poppler-config.h
+//
+// Copyright 1996-2011 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com>
+// Copyright (C) 2014 Hib Eris <hib@hiberis.nl>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef POPPLER_CONFIG_H
+#define POPPLER_CONFIG_H
+
+#include <stdio.h>
+
+// We duplicate some of the config.h #define's here since they are
+// used in some of the header files we install. The #ifndef/#endif
+// around #undef look odd, but it's to silence warnings about
+// redefining those symbols.
+
+/* Defines the poppler version. */
+#ifndef POPPLER_VERSION
+#undef POPPLER_VERSION
+#endif
+
+/* Enable multithreading support. */
+#ifndef MULTITHREADED
+#undef MULTITHREADED
+#endif
+
+/* Use fixedpoint. */
+#ifndef USE_FIXEDPOINT
+#undef USE_FIXEDPOINT
+#endif
+
+/* Use single precision arithmetic in the Splash backend */
+#ifndef USE_FLOAT
+#undef USE_FLOAT
+#endif
+
+/* Include support for OPI comments. */
+#ifndef OPI_SUPPORT
+#undef OPI_SUPPORT
+#endif
+
+/* Enable word list support. */
+#ifndef TEXTOUT_WORD_LIST
+#undef TEXTOUT_WORD_LIST
+#endif
+
+/* Support for curl is compiled in. */
+#ifndef POPPLER_HAS_CURL_SUPPORT
+#undef POPPLER_HAS_CURL_SUPPORT
+#endif
+
+/* Use libjpeg instead of builtin jpeg decoder. */
+#ifndef ENABLE_LIBJPEG
+#undef ENABLE_LIBJPEG
+#endif
+
+/* Build against libtiff. */
+#ifndef ENABLE_LIBTIFF
+#undef ENABLE_LIBTIFF
+#endif
+
+/* Build against libpng. */
+#ifndef ENABLE_LIBPNG
+#undef ENABLE_LIBPNG
+#endif
+
+/* Use zlib instead of builtin zlib decoder. */
+#ifndef ENABLE_ZLIB
+#undef ENABLE_ZLIB
+#endif
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#ifndef HAVE_DIRENT_H
+#undef HAVE_DIRENT_H
+#endif
+
+/* Defines if gettimeofday is available on your system */
+#ifndef HAVE_GETTIMEOFDAY
+#undef HAVE_GETTIMEOFDAY
+#endif
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#ifndef HAVE_NDIR_H
+#undef HAVE_NDIR_H
+#endif
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#ifndef HAVE_SYS_DIR_H
+#undef HAVE_SYS_DIR_H
+#endif
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#ifndef HAVE_SYS_NDIR_H
+#undef HAVE_SYS_NDIR_H
+#endif
+
+/* Have FreeType2 include files */
+#ifndef HAVE_FREETYPE_H
+#undef HAVE_FREETYPE_H
+#endif
+
+/* Defines if use cms */
+#ifndef USE_CMS
+#undef USE_CMS
+#endif
+
+// Also, there are preprocessor symbols in the header files
+// that are used but never defined when building poppler using configure
+// or cmake: DISABLE_OUTLINE, DEBUG_MEM, SPLASH_CMYK, HAVE_T1LIB_H,
+// ENABLE_PLUGINS, DEBUG_FORMS, HAVE_FREETYPE_FREETYPE_H
+
+//------------------------------------------------------------------------
+// version
+//------------------------------------------------------------------------
+
+// copyright notice
+#define popplerCopyright "Copyright 2005-2015 The Poppler Developers - http://poppler.freedesktop.org"
+#define xpdfCopyright "Copyright 1996-2011 Glyph & Cog, LLC"
+
+//------------------------------------------------------------------------
+// popen
+//------------------------------------------------------------------------
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define popen _popen
+#define pclose _pclose
+#endif
+
+#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(_WIN32) || defined(__DJGPP__) || defined(MACOS)
+#define POPEN_READ_MODE "rb"
+#else
+#define POPEN_READ_MODE "r"
+#endif
+
+//------------------------------------------------------------------------
+// Win32 stuff
+//------------------------------------------------------------------------
+
+#if defined(_WIN32) && !defined(_MSC_VER)
+#include <windef.h>
+#else
+#define CDECL
+#endif
+
+#if defined(_WIN32)
+#ifdef _MSC_VER
+#define strtok_r strtok_s
+#elif __MINGW32__ && !defined(__WINPTHREADS_VERSION)
+char * strtok_r (char *s, const char *delim, char **save_ptr);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+// Compiler
+//------------------------------------------------------------------------
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#ifdef __MINGW_PRINTF_FORMAT
+#define GCC_PRINTF_FORMAT(fmt_index, va_index) \
+ __attribute__((__format__(__MINGW_PRINTF_FORMAT, fmt_index, va_index)))
+#else
+#define GCC_PRINTF_FORMAT(fmt_index, va_index) \
+ __attribute__((__format__(__printf__, fmt_index, va_index)))
+#endif
+#else
+#define GCC_PRINTF_FORMAT(fmt_index, va_index)
+#endif
+
+#if defined(_MSC_VER)
+#define fmax(a, b) std::max(a, b)
+#define fmin(a, b) std::min(a, b)
+#endif
+
+
+#endif /* POPPLER_CONFIG_H */
diff --git a/Build/source/libs/poppler/poppler-0.36.0/poppler/strtok_r.cpp b/Build/source/libs/poppler/poppler-0.36.0/poppler/strtok_r.cpp
new file mode 100644
index 00000000000..6483e0f7be9
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.36.0/poppler/strtok_r.cpp
@@ -0,0 +1,92 @@
+/* Reentrant string tokenizer. Generic version.
+ Copyright (C) 1991,1996-1999,2001,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Copyright (C) 1991,93,96,97,99,2000,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
+ with help from Dan Sahlin (dan@sics.se) and
+ commentary by Jim Blandy (jimb@ai.mit.edu);
+ adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
+ and implemented by Roland McGrath (roland@ai.mit.edu).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2012 Alexey Pavlov <alexpux@gmail.com>
+// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#if defined(__MINGW32__) && !defined(__WINPTHREADS_VERSION)
+#include <string.h>
+
+#define __rawmemchr strchr
+
+char * strtok_r (char *s, const char *delim, char **save_ptr)
+{
+ char *token;
+
+ if (s == NULL)
+ s = *save_ptr;
+
+ /* Scan leading delimiters. */
+ s += strspn (s, delim);
+ if (*s == '\0')
+ {
+ *save_ptr = s;
+ return NULL;
+ }
+
+ /* Find the end of the token. */
+ token = s;
+ s = strpbrk (token, delim);
+ if (s == NULL)
+ /* This token finishes the string. */
+ *save_ptr = __rawmemchr (token, '\0');
+ else
+ {
+ /* Terminate the token and make *SAVE_PTR point past it. */
+ *s = '\0';
+ *save_ptr = s + 1;
+ }
+ return token;
+}
+#endif