summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/cff.cc
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2014-07-08 06:44:39 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2014-07-08 06:44:39 +0000
commiteadda9e7616e95abf27cb9c9c208db41371a6cf5 (patch)
tree909828105d8a9c05d6af749aefbe39f117bbfa7d /Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/cff.cc
parent0b34c5e54c8d047aa6a34af8ced91b29c5e7ad46 (diff)
lcdf-typetools 2.104
git-svn-id: svn://tug.org/texlive/trunk@34550 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/cff.cc')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/cff.cc1693
1 files changed, 1693 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/cff.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/cff.cc
new file mode 100644
index 00000000000..9244afc9f3c
--- /dev/null
+++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/cff.cc
@@ -0,0 +1,1693 @@
+// -*- related-file-name: "../include/efont/cff.hh" -*-
+
+/* cff.{cc,hh} -- Compact Font Format fonts
+ *
+ * Copyright (c) 1998-2014 Eddie Kohler
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <efont/cff.hh>
+#include <lcdf/error.hh>
+#include <efont/t1item.hh>
+#include <lcdf/straccum.hh>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <efont/t1unparser.hh>
+
+#ifndef static_assert
+#define static_assert(c, msg) switch ((int) (c)) case 0: case (c):
+#endif
+
+namespace Efont {
+
+const char * const Cff::operator_names[] = {
+ "version", "Notice", "FullName", "FamilyName",
+ "Weight", "FontBBox", "BlueValues", "OtherBlues",
+ "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW",
+ "UNKNOWN_12", "UniqueID", "XUID", "charset",
+ "Encoding", "CharStrings", "Private", "Subrs",
+ "defaultWidthX", "nominalWidthX", "UNKNOWN_22", "UNKNOWN_23",
+ "UNKNOWN_24", "UNKNOWN_25", "UNKNOWN_26", "UNKNOWN_27",
+ "UNKNOWN_28", "UNKNOWN_29", "UNKNOWN_30", "UNKNOWN_31",
+ "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition",
+ "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix",
+ "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz",
+ "StemSnapH", "StemSnapV", "ForceBold", "UNKNOWN_12_15",
+ "UNKNOWN_12_16", "LanguageGroup", "ExpansionFactor", "initialRandomSeed",
+ "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend",
+ "UNKNOWN_12_24", "UNKNOWN_12_25", "UNKNOWN_12_26", "UNKNOWN_12_27",
+ "UNKNOWN_12_28", "UNKNOWN_12_29", "ROS", "CIDFontVersion",
+ "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase",
+ "FDArray", "FDSelect", "FontName"
+};
+
+const int Cff::operator_types[] = {
+ tSID, tSID, tSID, tSID, // version, Notice, FullName, FamilyName
+ tSID, tArray4, tP+tArray, tP+tArray, // Weight, FontBBox, BlueValues, OtherBlues
+ tP+tArray, tP+tArray, tP+tNumber, tP+tNumber, // FamBlues, FamOthBlues, StdHW, StdVW
+ tNone, tNumber, tArray, tOffset, // escape, UniqueID, XUID, charset
+ tOffset, tOffset, tPrivateType, tP+tLocalOffset, // Encoding, CharStrings, Private, Subrs
+ tP+tNumber, tP+tNumber, tNone, tNone, // defaultWX, nominalWX, 22, 23
+ tNone, tNone, tNone, tNone, // 24, 25, 26, 27
+ tNone, tNone, tNone, tNone, // 28, 29, 30, 31
+ tSID, tBoolean, tNumber, tNumber, // Copyright, isFixedPitch, ItalicAngle, UnderlinePosition
+ tNumber, tNumber, tNumber, tArray6, // UnderlineThickness, PaintType, CharstringType, FontMatrix
+ tNumber, tP+tNumber, tP+tNumber, tP+tNumber, // StrokeWidth, BlueScale, BlueShift, BlueFuzz
+ tP+tArray, tP+tArray, tP+tBoolean, tNone, // StemSnapH, StemSnapV, ForceBold, 12 15
+ tNone, tP+tNumber, tP+tNumber, tP+tNumber, // 12 16, LanguageGroup, ExpansionFactor, initialRandomSeed
+ tNumber, tSID, tSID, tArray, // SyntheticBase, PostScript, BaseFontName, BaseFontBlend
+ tNone, tNone, tNone, tNone, // 12 24, 12 25, 12 26, 12 27
+ tNone, tNone, tArray, tNumber, // 12 28, 12 29, ROS, CIDFontVersion
+ tNumber, tNumber, tNumber, tNumber, // CIDFontRevision, CIDFontType, CIDCount, UIDBase
+ tOffset, tOffset, tSID // FDArray, FDSelect, FontName
+};
+
+static PermString::Initializer initializer;
+static const char * const standard_strings[] = {
+ // Automatically generated from Appendix A of the CFF specification; do
+ // not edit. Size should be 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 PermString standard_permstrings[Cff::NSTANDARD_STRINGS];
+static HashMap<PermString, int> standard_permstrings_map(-1);
+
+static const int standard_encoding[] = {
+ // Automatically generated from Appendix B of the CFF specification; do
+ // not edit. Size should be 256.
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 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, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 0, 111, 112, 113,
+ 114, 0, 115, 116, 117, 118, 119, 120, 121, 122,
+ 0, 123, 0, 124, 125, 126, 127, 128, 129, 130,
+ 131, 0, 132, 133, 0, 134, 135, 136, 137, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 138, 0, 139, 0, 0,
+ 0, 0, 140, 141, 142, 143, 0, 0, 0, 0,
+ 0, 144, 0, 0, 0, 145, 0, 0, 146, 147,
+ 148, 149, 0, 0, 0, 0
+};
+
+static const int expert_encoding[] = {
+ // Automatically generated from Appendix B of the CFF specification; do
+ // not edit. Size should be 256.
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 229, 230, 0, 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, 0, 253, 254, 255, 256, 257,
+ 0, 0, 0, 258, 0, 0, 259, 260, 261, 262,
+ 0, 0, 263, 264, 265, 0, 266, 109, 110, 267,
+ 268, 269, 0, 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, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 304, 305, 306, 0, 0, 307, 308, 309, 310,
+ 311, 0, 312, 0, 0, 313, 0, 0, 314, 315,
+ 0, 0, 316, 317, 318, 0, 0, 0, 158, 155,
+ 163, 319, 320, 321, 322, 323, 324, 325, 0, 0,
+ 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 const int iso_adobe_charset[] = {
+ // Automatically generated from Appendix C of the CFF specification; do
+ // not edit.
+ 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 int expert_charset[] = {
+ // Automatically generated from Appendix C of the CFF specification; do
+ // not edit.
+ 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 const int expert_subset_charset[] = {
+ // Automatically generated from Appendix C of the CFF specification; do
+ // not edit.
+ 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
+};
+
+static const uint8_t default_dict_cff_data[] = {
+ // CFF header
+ 1, 0, // format major and minor version
+ 4, // header size
+ 4, // absolute offset size
+
+ // Name INDEX
+ 0, 1, // one element in index
+ 1, // offset size
+ 1, 14, // offset array
+ '%', 'D', 'E', 'F', 'A', 'U', 'L', 'T', 'D', 'I', 'C', 'T', '%',
+
+ // Top DICT INDEX
+ 0, 1, // one element in index
+ 1, // offset size
+ 1, 92, // offset array
+ // and the DICT
+ 139, 12, 1, // isFixedPitch false
+ 139, 12, 2, // ItalicAngle 0
+ 39, 12, 3, // UnderlinePosition -100
+ 189, 12, 4, // UnderlineThickness 50
+ 139, 12, 5, // PaintType 0
+ 141, 12, 6, // CharstringType 2
+ 30, 0x0A, 0x00, 0x1F, 139, 139, 30, 0x0A, 0x00, 0x1F, 139, 139, 12, 7,
+ // FontMatrix 0.001 0 0 0.001 0 0
+ 139, 139, 139, 139, 5, // FontBBox 0 0 0 0
+ 139, 12, 8, // StrokeWidth 0
+ 139, 15, // charset 0
+ 139, 16, // Encoding 0
+ 139, 12, 31, // CIDFontVersion 0
+ 139, 12, 32, // CIDFontRevision 0
+ 139, 12, 33, // CIDFontType 0
+ 28, 34, 16, 12, 34, // CIDCount 8720
+ 30, 0x0A, 0x03, 0x96, 0x25, 0xFF, 12, 9, // BlueScale 0.039625
+ 146, 12, 10, // BlueShift 7
+ 140, 12, 11, // BlueFuzz 1
+ 139, 12, 14, // ForceBold false
+ 139, 12, 17, // LanguageGroup 0
+ 30, 0x0A, 0x06, 0xFF, 12, 18, // ExpansionFactor 0.06
+ 139, 12, 19, // initialRandomSeed 0
+ 139, 20, // defaultWidthX 0
+ 139, 21, // nominalWidthX 0
+
+ // String INDEX
+ 0, 0,
+
+ // Gsubr INDEX
+ 0, 0
+};
+
+static const Cff::Dict &
+default_dict()
+{
+ static Cff *cff;
+ static Cff::Font *cfffont;
+ if (!cfffont) {
+ cff = new Cff(String::make_stable((const char *) default_dict_cff_data, sizeof(default_dict_cff_data)),
+ 0, ErrorHandler::default_handler());
+ cfffont = (Cff::Font *) cff->font();
+ }
+ return cfffont->top_dict();
+}
+
+
+#define POS_GT(pos1, pos2) ((unsigned)(pos1) > (unsigned)(pos2))
+
+
+Cff::Cff(const String& s, unsigned units_per_em, ErrorHandler* errh)
+ : _data_string(s), _data(reinterpret_cast<const uint8_t *>(_data_string.data())), _len(_data_string.length()),
+ _strings_map(-2), _units_per_em(units_per_em)
+{
+ static_assert((sizeof(standard_strings) / sizeof(standard_strings[0])) == NSTANDARD_STRINGS,
+ "NSTANDARD_STRINGS defined incorrectly");
+ static_assert((sizeof(standard_encoding) / sizeof(standard_encoding[0])) == 256,
+ "standard_encoding has wrong size");
+ static_assert((sizeof(expert_encoding) / sizeof(expert_encoding[0])) == 256,
+ "expert_encoding has wrong size");
+ _error = parse_header(errh ? errh : ErrorHandler::silent_handler());
+}
+
+Cff::~Cff()
+{
+ for (int i = 0; i < _gsubrs_cs.size(); i++)
+ delete _gsubrs_cs[i];
+}
+
+/*
+ * Parsing the file header
+ */
+
+int
+Cff::parse_header(ErrorHandler *errh)
+{
+ if (_gsubrs_index.error() >= 0) // already done
+ return 0;
+
+ // parse header
+ if (_len == 0)
+ return errh->error("not a PostScript-flavored OpenType font"), -EFAULT;
+ if (_len < HEADER_SIZE)
+ return errh->error("CFF file corrupted (too small)"), -EFAULT;
+ if (_data[0] != 1) // major version number
+ return errh->error("bad major version number %d", _data[0]), -ERANGE;
+ int hdrSize = _data[2], offSize = _data[3];
+ if (hdrSize < 4 || hdrSize > _len || offSize < 1 || offSize > 4)
+ return errh->error("corrupted file header"), -EINVAL;
+ int name_index_pos = hdrSize;
+
+ // parse name INDEX
+ IndexIterator niter(_data, name_index_pos, _len, errh, "Name INDEX");
+ if (niter.error() < 0)
+ return niter.error();
+ _name_index.clear();
+ for (; niter; niter++) {
+ const uint8_t *d0 = niter[0];
+ const uint8_t *d1 = niter[1];
+ if (d0 == d1 || d0[0] == 0)
+ _name_index.push_back(PermString());
+ else
+ _name_index.push_back(PermString(reinterpret_cast<const char *>(d0), d1 - d0));
+ }
+ int top_dict_index_pos = niter.index_end() - _data;
+
+ // check top DICT INDEX
+ _top_dict_index = IndexIterator(_data, top_dict_index_pos, _len, errh, "Top DICT INDEX");
+ if (_top_dict_index.error() < 0)
+ return _top_dict_index.error();
+ else if (_top_dict_index.nitems() != nfonts())
+ return errh->error("invalid font: Top DICT INDEX has %d elements, but there are %d fonts", _top_dict_index.nitems(), nfonts()), -EINVAL;
+ int string_index_pos = _top_dict_index.index_end() - _data;
+
+ // check strings INDEX
+ _strings_index = IndexIterator(_data, string_index_pos, _len, errh, "Strings INDEX");
+ if (_strings_index.error() < 0)
+ return _strings_index.error();
+ else if (NSTANDARD_STRINGS + _strings_index.nitems() - 1 > MAX_SID)
+ return errh->error("too many strings defined in font"), -EINVAL;
+ _strings.assign(_strings_index.nitems(), PermString());
+ int global_subr_index_pos = _strings_index.index_end() - _data;
+
+ // check gsubr INDEX
+ _gsubrs_index = IndexIterator(_data, global_subr_index_pos, _len, errh, "Gsubrs INDEX");
+ if (_gsubrs_index.error() < 0)
+ return _gsubrs_index.error();
+ _gsubrs_cs.assign(ngsubrs(), 0);
+
+ return 0;
+}
+
+int
+Cff::sid(PermString s)
+{
+ if (!s) // XXX?
+ return -1;
+
+ // check standard strings
+ if (standard_permstrings_map["a"] < 0)
+ for (int i = 0; i < NSTANDARD_STRINGS; i++) {
+ if (!standard_permstrings[i])
+ standard_permstrings[i] = PermString(standard_strings[i]);
+ standard_permstrings_map.insert(standard_permstrings[i], i);
+ }
+ int sid = standard_permstrings_map[s];
+ if (sid >= 0)
+ return sid;
+
+ // check user strings
+ sid = _strings_map[s];
+ if (sid >= -1)
+ return sid;
+
+ for (int i = 0; i < _strings.size(); i++)
+ if (!_strings[i] && s.length() == _strings_index[i+1] - _strings_index[i] && memcmp(s.c_str(), _strings_index[i], s.length()) == 0) {
+ _strings[i] = s;
+ _strings_map.insert(s, i + NSTANDARD_STRINGS);
+ return i + NSTANDARD_STRINGS;
+ }
+
+ _strings_map.insert(s, -1);
+ return -1;
+}
+
+String
+Cff::sid_string(int sid) const
+{
+ if (sid < 0)
+ return String();
+ else if (sid < NSTANDARD_STRINGS)
+ return String(sid_permstring(sid));
+ else {
+ sid -= NSTANDARD_STRINGS;
+ if (sid >= _strings.size())
+ return String();
+ else if (_strings[sid])
+ return String(_strings[sid]);
+ else
+ return String(reinterpret_cast<const char *>(_strings_index[sid]), _strings_index[sid + 1] - _strings_index[sid]);
+ }
+}
+
+PermString
+Cff::sid_permstring(int sid) const
+{
+ if (sid < 0)
+ return PermString();
+ else if (sid < NSTANDARD_STRINGS) {
+ if (!standard_permstrings[sid])
+ standard_permstrings[sid] = PermString(standard_strings[sid]);
+ return standard_permstrings[sid];
+ } else {
+ sid -= NSTANDARD_STRINGS;
+ if (sid >= _strings.size())
+ return PermString();
+ else if (_strings[sid])
+ return _strings[sid];
+ else {
+ PermString s = PermString(reinterpret_cast<const char *>(_strings_index[sid]), _strings_index[sid + 1] - _strings_index[sid]);
+ _strings[sid] = s;
+ _strings_map.insert(s, sid + NSTANDARD_STRINGS);
+ return s;
+ }
+ }
+}
+
+int
+Cff::font_offset(int findex, int &offset, int &length) const
+{
+ if (findex < 0 || findex >= nfonts())
+ return -ENOENT;
+ offset = _top_dict_index[findex] - _data;
+ length = _top_dict_index[findex + 1] - _top_dict_index[findex];
+ return 0;
+}
+
+int
+Cff::font_offset(PermString name, int &offset, int &length) const
+{
+ for (int i = 0; i < _name_index.size(); i++)
+ if (_name_index[i] == name && name)
+ return font_offset(i, offset, length);
+ return -ENOENT;
+}
+
+Cff::FontParent *
+Cff::font(PermString font_name, ErrorHandler *errh)
+{
+ if (!errh)
+ errh = ErrorHandler::silent_handler();
+
+ if (!ok())
+ return errh->error("invalid CFF"), (FontParent *) 0;
+
+ // search for a font named 'font_name'
+ for (int i = 0; i < _name_index.size(); i++)
+ if (_name_index[i] && (!font_name || font_name == _name_index[i])) {
+ int td_offset = _top_dict_index[i] - _data;
+ int td_length = _top_dict_index[i + 1] - _top_dict_index[i];
+ Dict top_dict(this, td_offset, td_length, errh, "Top DICT");
+ if (!top_dict.ok())
+ return 0;
+ else if (top_dict.has_first(oROS))
+ return new Cff::CIDFont(this, _name_index[i], top_dict, errh);
+ else
+ return new Cff::Font(this, _name_index[i], top_dict, errh);
+ }
+
+ if (!font_name)
+ errh->error("no fonts in CFF");
+ else
+ errh->error("font %<%s%> not found", font_name.c_str());
+ return 0;
+}
+
+static inline int
+subr_bias(int charstring_type, int nsubrs)
+{
+ if (charstring_type == 1)
+ return 0;
+ else if (nsubrs < 1240)
+ return 107;
+ else if (nsubrs < 33900)
+ return 1131;
+ else
+ return 32768;
+}
+
+Charstring *
+Cff::gsubr(int i)
+{
+ i += subr_bias(2, ngsubrs());
+ if (i < 0 || i >= ngsubrs())
+ return 0;
+ if (!_gsubrs_cs[i]) {
+ const uint8_t *s1 = _gsubrs_index[i];
+ int slen = _gsubrs_index[i + 1] - s1;
+ String cs = data_string().substring(s1 - data(), slen);
+ if (slen == 0)
+ return 0;
+ else
+ _gsubrs_cs[i] = new Type2Charstring(cs);
+ }
+ return _gsubrs_cs[i];
+}
+
+
+/*****
+ * Cff::Charset
+ **/
+
+Cff::Charset::Charset(const Cff *cff, int pos, int nglyphs, int max_sid, ErrorHandler *errh)
+{
+ assign(cff, pos, nglyphs, max_sid, errh);
+}
+
+void
+Cff::Charset::assign(const Cff *cff, int pos, int nglyphs, int max_sid, ErrorHandler *errh)
+{
+ if (!errh)
+ errh = ErrorHandler::silent_handler();
+
+ _sids.reserve(nglyphs);
+
+ if (pos == 0)
+ assign(iso_adobe_charset, sizeof(iso_adobe_charset) / sizeof(int), nglyphs);
+ else if (pos == 1)
+ assign(expert_charset, sizeof(expert_charset) / sizeof(int), nglyphs);
+ else if (pos == 2)
+ assign(expert_subset_charset, sizeof(expert_subset_charset) / sizeof(int), nglyphs);
+ else
+ _error = parse(cff, pos, nglyphs, max_sid, errh);
+
+ if (_error >= 0)
+ for (int g = 0; g < _sids.size(); g++) {
+ if (_gids[_sids[g]] >= 0) {
+ errh->error("glyph %<%s%> in charset twice", cff->sid_permstring(_sids[g]).c_str());
+ _error = -EEXIST;
+ }
+ _gids[_sids[g]] = g;
+ }
+}
+
+void
+Cff::Charset::assign(const int *data, int size, int nglyphs)
+{
+ if (size < nglyphs)
+ size = nglyphs;
+ _sids.resize(size);
+ memcpy(&_sids[0], data, sizeof(const int) * size);
+ _gids.resize(data[size-1] + 1, -1);
+ _error = 0;
+}
+
+int
+Cff::Charset::parse(const Cff *cff, int pos, int nglyphs, int max_sid, ErrorHandler *errh)
+{
+ const uint8_t *data = cff->data();
+ int len = cff->length();
+
+ if (pos + 1 > len)
+ return errh->error("charset position out of range"), -EFAULT;
+
+ _sids.push_back(0);
+ int actual_max_sid = 0;
+
+ int format = data[pos];
+ if (format == 0) {
+ if (pos + 1 + (nglyphs - 1) * 2 > len)
+ return errh->error("charset [format 0] out of range"), -EFAULT;
+ const uint8_t *p = data + pos + 1;
+ for (; _sids.size() < nglyphs; p += 2) {
+ int sid = (p[0] << 8) | p[1];
+ if (sid > actual_max_sid)
+ actual_max_sid = sid;
+ _sids.push_back(sid);
+ }
+
+ } else if (format == 1) {
+ const uint8_t *p = data + pos + 1;
+ for (; _sids.size() < nglyphs; p += 3) {
+ if (p + 3 > data + len)
+ return errh->error("charset [format 1] out of range"), -EFAULT;
+ int sid = (p[0] << 8) | p[1];
+ int n = p[2];
+ if (sid + n > actual_max_sid)
+ actual_max_sid = sid + n;
+ for (int i = 0; i <= n; i++)
+ _sids.push_back(sid + i);
+ }
+
+ } else if (format == 2) {
+ const uint8_t *p = data + pos + 1;
+ for (; _sids.size() < nglyphs; p += 4) {
+ if (p + 4 > data + len)
+ return errh->error("charset [format 2] out of range"), -EFAULT;
+ int sid = (p[0] << 8) | p[1];
+ int n = (p[2] << 8) | p[3];
+ if (sid + n > actual_max_sid)
+ actual_max_sid = sid + n;
+ for (int i = 0; i <= n; i++)
+ _sids.push_back(sid + i);
+ }
+
+ } else
+ return errh->error("unknown charset format %d", format), -EINVAL;
+
+ if (max_sid >= 0 && actual_max_sid > max_sid)
+ return errh->error("charset [format %d] uses bad SID %d", format, actual_max_sid), -EINVAL;
+ _sids.resize(nglyphs);
+ _gids.resize(actual_max_sid + 1, -1);
+ return 0;
+}
+
+
+/*****
+ * Cff::FDSelect
+ **/
+
+void
+Cff::FDSelect::assign(const Cff *cff, int pos, int nglyphs, ErrorHandler *errh)
+{
+ if (!errh)
+ errh = ErrorHandler::silent_handler();
+ if (_my_fds)
+ delete[] _fds;
+ _fds = 0;
+ _my_fds = false;
+ _nglyphs = nglyphs;
+ _error = parse(cff, pos, nglyphs, errh);
+}
+
+Cff::FDSelect::~FDSelect()
+{
+ if (_my_fds)
+ delete[] _fds;
+}
+
+int
+Cff::FDSelect::parse(const Cff *cff, int pos, int nglyphs, ErrorHandler *errh)
+{
+ const uint8_t *data = cff->data();
+ int len = cff->length();
+
+ if (pos + 1 > len)
+ return errh->error("FDSelect position out of range"), -EFAULT;
+
+ int format = data[pos];
+ if (format == 0) {
+ if (pos + 1 + nglyphs > len)
+ return errh->error("FDSelect [format 0] out of range"), -EFAULT;
+ _fds = data + pos + 1;
+ _my_fds = false;
+ return 0;
+
+ } else if (format == 3) {
+ int nranges = (data[pos+1] << 8) | data[pos+2];
+ if (pos + 3 + 3*nranges + 2 > len)
+ return errh->error("FDSelect [format 3] out of range"), -EFAULT;
+
+ const uint8_t *p = data + pos + 3;
+ int last_glyph = (p[3*nranges] << 8) | p[3*nranges + 1];
+ if (p[0] || p[1] || last_glyph != nglyphs)
+ return errh->error("FDSelect [format 3] bad values"), -EINVAL;
+
+ _fds = new uint8_t[nglyphs];
+ _my_fds = true;
+ int curglyph = 0;
+ for (; curglyph < nglyphs; p += 3) {
+ int nextglyph = (p[3] << 8) | p[4];
+ if (nextglyph > nglyphs || nextglyph < curglyph)
+ return errh->error("FDSelect [format 3] sorting error"), -EINVAL;
+ memset(const_cast<uint8_t *>(_fds + curglyph), p[2], nextglyph - curglyph);
+ curglyph = nextglyph;
+ }
+ return 0;
+
+ } else
+ return errh->error("unknown charset format %d", format), -EINVAL;
+}
+
+
+/*****
+ * Cff::IndexIterator
+ **/
+
+Cff::IndexIterator::IndexIterator(const uint8_t *data, int pos, int len, ErrorHandler *errh, const char *index_name)
+ : _contents(0), _offset(0), _last_offset(0)
+{
+ if (!errh)
+ errh = ErrorHandler::silent_handler();
+
+ // check header
+ int nitems = 0;
+ if (POS_GT(pos + 2, len)) {
+ errh->error("%s: position out of range", index_name);
+ _offsize = -EFAULT;
+ } else if (data[pos] == 0 && data[pos + 1] == 0) {
+ _contents = data + pos + 2;
+ _offsize = 0;
+ } else if (POS_GT(pos + 3, len)) {
+ errh->error("%s: position out of range", index_name);
+ _offsize = -EFAULT;
+ } else if ((_offsize = data[pos + 2]), (_offsize < 1 || _offsize > 4)) {
+ errh->error("%s: offset size %d out of range", index_name, _offsize);
+ _offsize = -EINVAL;
+ } else {
+ nitems = (data[pos] << 8) | data[pos + 1];
+ if (POS_GT(pos + 3 + (nitems + 1) * _offsize, len)) {
+ errh->error("%s: data out of range", index_name);
+ _offsize = -EFAULT;
+ } else {
+ _offset = data + pos + 3;
+ _last_offset = _offset + nitems * _offsize;
+ _contents = _last_offset + _offsize - 1;
+ }
+ }
+
+ // check items in offset array
+ uint32_t max_doff_allowed = len - (pos + 2 + (nitems + 1) * _offsize);
+ uint32_t last_doff = 1;
+ for (const uint8_t *o = _offset; o <= _last_offset && _offsize > 0; o += _offsize) {
+ uint32_t doff = offset_at(o);
+ if (doff > max_doff_allowed) {
+ errh->error("%s: element out of range", index_name);
+ _offsize = -EFAULT;
+ } else if (doff < last_doff) {
+ errh->error("%s: garbled elements", index_name);
+ break;
+ }
+ last_doff = doff;
+ }
+}
+
+const uint8_t *
+Cff::IndexIterator::index_end() const
+{
+ if (_offsize <= 0)
+ return _contents;
+ else
+ return _contents + offset_at(_last_offset);
+}
+
+int
+Cff::IndexIterator::nitems() const
+{
+ if (_offsize <= 0)
+ return 0;
+ else
+ return (_last_offset - _offset) / _offsize;
+}
+
+
+
+/*****
+ * Cff::Dict
+ **/
+
+Cff::Dict::Dict()
+ : _cff(0), _pos(0), _error(-ENOENT)
+{
+}
+
+Cff::Dict::Dict(Cff *cff, int pos, int dict_len, ErrorHandler *errh, const char *dict_name)
+{
+ assign(cff, pos, dict_len, errh, dict_name);
+}
+
+int
+Cff::Dict::assign(Cff *cff, int pos, int dict_len, ErrorHandler *errh, const char *dict_name)
+{
+ _cff = cff;
+ _pos = pos;
+ _operators.clear();
+ _pointers.clear();
+ _operands.clear();
+
+ if (!errh)
+ errh = ErrorHandler::silent_handler();
+
+ const uint8_t *data = cff->data() + pos;
+ const uint8_t *end_data = data + dict_len;
+
+ _pointers.push_back(0);
+ while (data < end_data)
+ switch (data[0]) {
+
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ case 8: case 9: case 10: case 11: case 13: case 14: case 15:
+ case 16: case 17: case 18: case 19: case 20: case 21:
+ _operators.push_back(data[0]);
+ _pointers.push_back(_operands.size());
+ data++;
+ break;
+
+ case 22: case 23: case 24: case 25: case 26: case 27: case 31:
+ case 255: // reserved
+ errh->error("%s: reserved operator %d", dict_name, data[0]);
+ return (_error = -ERANGE);
+
+ case 12:
+ if (data + 1 >= end_data)
+ goto runoff;
+ _operators.push_back(32 + data[1]);
+ _pointers.push_back(_operands.size());
+ data += 2;
+ break;
+
+ case 28: {
+ if (data + 2 >= end_data)
+ goto runoff;
+ int16_t val = (data[1] << 8) | data[2];
+ _operands.push_back(val);
+ data += 3;
+ break;
+ }
+
+ case 29: {
+ if (data + 4 >= end_data)
+ goto runoff;
+ int32_t val = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
+ _operands.push_back(val);
+ data += 5;
+ break;
+ }
+
+ case 30: {
+ char buf[1024];
+ int pos = 0;
+ if (data + 1 >= end_data)
+ goto runoff;
+ for (data++; data < end_data && pos < 1020; data++) {
+ int d = *data;
+ for (int i = 0; i < 2; i++, d <<= 4) {
+ int digit = (d >> 4) & 0xF;
+ switch (digit) {
+ case 10:
+ buf[pos++] = '.';
+ break;
+ case 11:
+ buf[pos++] = 'E';
+ break;
+ case 12:
+ buf[pos++] = 'E';
+ buf[pos++] = '-';
+ break;
+ case 13:
+ errh->error("%s: bad digit in real number", dict_name);
+ goto invalid;
+ case 14:
+ buf[pos++] = '-';
+ break;
+ case 15:
+ goto found;
+ default:
+ buf[pos++] = digit + '0';
+ break;
+ }
+ }
+ }
+ // number not found
+ goto runoff;
+ found:
+ char *endptr;
+ buf[pos] = '\0';
+ _operands.push_back(strtod(buf, &endptr));
+ if (*endptr) {
+ errh->error("%s: real number syntax error", dict_name);
+ goto invalid;
+ }
+ data++;
+ break;
+ }
+
+ case 247: case 248: case 249: case 250: {
+ if (data + 1 >= end_data)
+ goto runoff;
+ int val = ((data[0] - 247) << 8) + data[1] + 108;
+ _operands.push_back(val);
+ data += 2;
+ break;
+ }
+
+ case 251: case 252: case 253: case 254: {
+ if (data + 1 >= end_data)
+ goto runoff;
+ int val = -((data[0] - 251) << 8) - data[1] - 108;
+ _operands.push_back(val);
+ data += 2;
+ break;
+ }
+
+ default:
+ _operands.push_back(data[0] - 139);
+ data++;
+ break;
+
+ }
+
+ // not closed by an operator?
+ if (_pointers.back() != _operands.size()) {
+ errh->error("%s: not closed by an operator", dict_name);
+ goto invalid;
+ }
+
+ return (_error = 0);
+
+ runoff:
+ errh->error("%s: runoff end of DICT", dict_name);
+ return (_error = -EFAULT);
+
+ invalid:
+ return (_error = -EINVAL);
+}
+
+int
+Cff::Dict::check(bool is_private, ErrorHandler *errh, const char *dict_name) const
+{
+ if (!errh)
+ errh = ErrorHandler::silent_handler();
+ int before_nerrors = errh->nerrors();
+
+ // keep track of operator reuse
+ Vector<int> operators_used;
+
+ for (int i = 0; i < _operators.size(); i++) {
+ int arity = _pointers[i+1] - _pointers[i];
+ double num = (arity == 0 ? 0 : _operands[_pointers[i]]);
+ double truncnum = floor(num);
+ int op = _operators[i];
+ int type = (op > oLastOperator ? tNone : operator_types[op]);
+
+ // check reuse
+ if (op >= operators_used.size())
+ operators_used.resize(op + 1, 0);
+ if (operators_used[op] && (type & tTypeMask) != tNone)
+ errh->error("%s: operator %<%s%> specified twice", dict_name, operator_names[op]);
+ operators_used[op]++;
+
+ // check data
+ switch (type & tTypeMask) {
+
+ case tNone:
+ if (op >= 32)
+ errh->warning("%s: unknown operator %<12 %d%>", dict_name, op - 32);
+ else
+ errh->warning("%s: unknown operator %<%d%>", dict_name, op);
+ continue;
+
+ case tSID:
+ if (arity != 1 || num != truncnum || num < 0 || num > _cff->max_sid())
+ goto bad_data;
+ break;
+
+ case tFontNumber:
+ if (arity != 1 || num != truncnum || num < 0 || num >= _cff->nfonts())
+ goto bad_data;
+ break;
+
+ case tBoolean:
+ if (arity != 1)
+ goto bad_data;
+ else if (num != 0 && num != 1)
+ errh->warning("%s: data for Boolean operator %<%s%> not 0 or 1", dict_name, operator_names[op]);
+ break;
+
+ case tNumber:
+ if (arity != 1)
+ goto bad_data;
+ break;
+
+ case tOffset:
+ if (arity != 1 || num != truncnum || num < 0 || num >= _cff->length())
+ goto bad_data;
+ break;
+
+ case tLocalOffset:
+ if (arity != 1 || num != truncnum || _pos + num < 0 || _pos + num >= _cff->length())
+ goto bad_data;
+ break;
+
+ case tPrivateType: {
+ if (arity != 2 || num != truncnum || num < 0)
+ goto bad_data;
+ double off = _operands[_pointers[i] + 1];
+ if (off < 0 || off + num > _cff->length())
+ goto bad_data;
+ break;
+ }
+
+ case tArray2: case tArray3: case tArray4:
+ case tArray5: case tArray6:
+ if (arity != (type & tTypeMask) - tArray2 + 2)
+ goto bad_data;
+ break;
+
+ case tArray:
+ break;
+
+ }
+
+ // check dict location
+ if (((type & tPrivate) != 0) != is_private)
+ errh->warning("%s: operator %<%s%> in wrong DICT", dict_name, operator_names[op]);
+
+ continue;
+
+ bad_data:
+ errh->error("%s: bad data for operator %<%s%>", dict_name, operator_names[op]);
+ }
+
+ return (errh->nerrors() != before_nerrors ? -1 : 0);
+}
+
+bool
+Cff::Dict::has(DictOperator op) const
+{
+ for (int i = 0; i < _operators.size(); i++)
+ if (_operators[i] == op)
+ return true;
+ return false;
+}
+
+bool
+Cff::Dict::xvalue(DictOperator op, Vector<double> &out) const
+{
+ out.clear();
+ for (int i = 0; i < _operators.size(); i++)
+ if (_operators[i] == op) {
+ for (int j = _pointers[i]; j < _pointers[i+1]; j++)
+ out.push_back(_operands[j]);
+ return true;
+ }
+ return false;
+}
+
+bool
+Cff::Dict::xvalue(DictOperator op, int *val) const
+{
+ for (int i = 0; i < _operators.size(); i++)
+ if (_operators[i] == op && _pointers[i] + 1 == _pointers[i+1]) {
+ *val = (int) _operands[_pointers[i]];
+ return true;
+ }
+ return false;
+}
+
+bool
+Cff::Dict::xvalue(DictOperator op, double *val) const
+{
+ for (int i = 0; i < _operators.size(); i++)
+ if (_operators[i] == op && _pointers[i] + 1 == _pointers[i+1]) {
+ *val = _operands[_pointers[i]];
+ return true;
+ }
+ return false;
+}
+
+bool
+Cff::Dict::value(DictOperator op, Vector<double> &out) const
+{
+ return xvalue(op, out) || default_dict().xvalue(op, out);
+}
+
+bool
+Cff::Dict::value(DictOperator op, int *val) const
+{
+ return xvalue(op, val) || default_dict().xvalue(op, val);
+}
+
+bool
+Cff::Dict::value(DictOperator op, double *val) const
+{
+ return xvalue(op, val) || default_dict().xvalue(op, val);
+}
+
+void
+Cff::Dict::unparse(ErrorHandler *errh, const char *dict_name) const
+{
+ StringAccum sa;
+ for (int i = 0; i < _operators.size(); i++) {
+ sa.clear();
+ if (_pointers[i] + 1 == _pointers[i+1])
+ sa << _operands[_pointers[i]];
+ else {
+ sa << "[";
+ for (int j = _pointers[i]; j < _pointers[i+1]; j++)
+ sa << _operands[j] << ' ';
+ sa.pop_back();
+ sa << "]";
+ }
+ errh->message("%s: %s %s", dict_name, operator_names[_operators[i]], sa.c_str());
+ }
+}
+
+
+/*****
+ * CffFontParent
+ **/
+
+static int
+handle_private(Cff *cff, const Cff::Dict &top_dict, Cff::Dict &private_dict,
+ double &default_width_x, double &nominal_width_x,
+ Cff::IndexIterator &subrs_index, Vector<Charstring *> &subrs_cs,
+ ErrorHandler *errh)
+{
+ Vector<double> private_info;
+ top_dict.value(Cff::oPrivate, private_info);
+ int private_offset = (int) private_info[1];
+ private_dict.assign(cff, private_offset, (int) private_info[0], errh, "Private DICT");
+ if (private_dict.error() < 0)
+ return private_dict.error();
+ else if (private_dict.check(true, errh, "Private DICT") < 0)
+ return -EINVAL;
+ //private_dict.unparse(errh, "Private DICT");
+
+ private_dict.value(Cff::oDefaultWidthX, &default_width_x);
+ private_dict.value(Cff::oNominalWidthX, &nominal_width_x);
+ if (private_dict.has(Cff::oSubrs)) {
+ int subrs_offset = 0;
+ private_dict.value(Cff::oSubrs, &subrs_offset);
+ subrs_index = Cff::IndexIterator(cff->data(), private_offset + subrs_offset, cff->length(), errh, "Subrs INDEX");
+ if (subrs_index.error() < 0)
+ return subrs_index.error();
+ }
+ subrs_cs.assign(subrs_index.nitems(), 0);
+ return 0;
+}
+
+
+Cff::FontParent::FontParent(Cff* cff)
+ : CharstringProgram(cff->units_per_em()), _cff(cff), _error(-1)
+{
+}
+
+Charstring *
+Cff::FontParent::charstring(const IndexIterator &iiter, int which) const
+{
+ const uint8_t *s1 = iiter[which];
+ int slen = iiter[which + 1] - s1;
+ String cs = _cff->data_string().substring(s1 - _cff->data(), slen);
+ if (slen == 0)
+ return 0;
+ else if (_charstring_type == 1)
+ return new Type1Charstring(cs);
+ else
+ return new Type2Charstring(cs);
+}
+
+Charstring *
+Cff::FontParent::gsubr(int i) const
+{
+ return _cff->gsubr(i);
+}
+
+int
+Cff::FontParent::gsubr_bias() const
+{
+ return Efont::subr_bias(2, ngsubrs_x());
+}
+
+
+/*****
+ * CffFont
+ **/
+
+Cff::Font::Font(Cff *cff, PermString font_name, const Dict &top_dict, ErrorHandler *errh)
+ : ChildFont(cff, 0, 2, top_dict, errh), _font_name(font_name),
+ _t1encoding(0)
+{
+ assert(!_top_dict.has_first(oROS));
+ if (_error < 0)
+ return;
+
+ // extract CharStrings
+ // must use xvalue because we could be creating the default dict!
+ int charstrings_offset = 0;
+ _top_dict.xvalue(oCharStrings, &charstrings_offset);
+ _charstrings_index = Cff::IndexIterator(cff->data(), charstrings_offset, cff->length(), errh, "CharStrings INDEX");
+ if (_charstrings_index.error() < 0) {
+ _error = _charstrings_index.error();
+ return;
+ }
+ _charstrings_cs.assign(_charstrings_index.nitems(), 0);
+
+ int charset = 0;
+ _top_dict.xvalue(oCharset, &charset);
+ _charset.assign(cff, charset, _charstrings_index.nitems(), cff->max_sid(), errh);
+ if (_charset.error() < 0) {
+ _error = _charset.error();
+ return;
+ }
+
+ int Encoding = 0;
+ _top_dict.xvalue(oEncoding, &Encoding);
+ if (parse_encoding(Encoding, errh) < 0)
+ return;
+
+ // success!
+ _error = 0;
+}
+
+Cff::Font::~Font()
+{
+ for (int i = 0; i < _charstrings_cs.size(); i++)
+ delete _charstrings_cs[i];
+ delete _t1encoding;
+}
+
+int
+Cff::Font::parse_encoding(int pos, ErrorHandler *errh)
+{
+ _encoding_pos = pos;
+ for (int i = 0; i < 256; i++)
+ _encoding[i] = 0;
+
+ // check for standard encodings
+ if (pos == 0)
+ return assign_standard_encoding(standard_encoding);
+ else if (pos == 1)
+ return assign_standard_encoding(expert_encoding);
+
+ // otherwise, a custom encoding
+ const uint8_t *data = _cff->data();
+ int len = _cff->length();
+ if (pos + 1 > len)
+ return errh->error("Encoding position out of range"), -EFAULT;
+ bool supplemented = (data[pos] & 0x80) != 0;
+ int format = (data[pos] & 0x7F);
+
+ int retval = 0;
+ int endpos, g = 1;
+ if (format == 0) {
+ endpos = pos + 2 + data[pos + 1];
+ if (endpos > len)
+ return errh->error("Encoding[0] out of range"), -EFAULT;
+ const uint8_t *p = data + pos + 2;
+ int n = data[pos + 1];
+ for (; g <= n; g++, p++) {
+ int e = p[0];
+ if (_encoding[e])
+ retval = 1;
+ _encoding[e] = g;
+ }
+
+ } else if (format == 1) {
+ endpos = pos + 2 + data[pos + 1] * 2;
+ if (endpos > len)
+ return errh->error("Encoding[1] out of range"), -EFAULT;
+ const uint8_t *p = data + pos + 2;
+ int n = data[pos + 1];
+ for (int i = 0; i < n; i++, p += 2) {
+ int first = p[0];
+ int nLeft = p[1];
+ for (int e = first; e <= first + nLeft; e++) {
+ if (_encoding[e])
+ retval = 1;
+ _encoding[e] = g++;
+ }
+ }
+
+ } else
+ return errh->error("unknown Encoding format %d", format), -EINVAL;
+
+ if (g > _charset.nglyphs())
+ return errh->error("Encoding glyph %d out of range", g), -EINVAL;
+
+ // check supplements
+ if (supplemented) {
+ if (endpos + data[endpos] * 3 > len)
+ return -EINVAL;
+ const uint8_t *p = data + endpos + 1;
+ int n = data[endpos];
+ for (int i = 0; i < n; i++, p += 3) {
+ int e = p[0];
+ int s = (p[1] << 8) | p[2];
+ int g = _charset.sid_to_gid(s);
+ if (_encoding[e])
+ retval = 1;
+ if (g < 0 || g >= _charset.nglyphs())
+ return errh->error("Encoding glyph %d out of range", g), -EINVAL;
+ _encoding[e] = g;
+ }
+ }
+
+ // successfully done
+ return retval;
+}
+
+int
+Cff::Font::assign_standard_encoding(const int *standard_encoding)
+{
+ for (int i = 0; i < 256; i++)
+ _encoding[i] = _charset.sid_to_gid(standard_encoding[i]);
+ return 0;
+}
+
+void
+Cff::Font::font_matrix(double matrix[6]) const
+{
+ Vector<double> t1d_matrix;
+ if (dict_value(oFontMatrix, t1d_matrix) && t1d_matrix.size() == 6)
+ memcpy(&matrix[0], &t1d_matrix[0], sizeof(double) * 6);
+ else {
+ matrix[0] = matrix[3] = 0.001;
+ matrix[1] = matrix[2] = matrix[4] = matrix[5] = 0;
+ }
+}
+
+PermString
+Cff::Font::glyph_name(int gid) const
+{
+ if (gid >= 0 && gid < nglyphs())
+ return _cff->sid_permstring(_charset.gid_to_sid(gid));
+ else
+ return PermString();
+}
+
+void
+Cff::Font::glyph_names(Vector<PermString> &gnames) const
+{
+ gnames.resize(nglyphs());
+ for (int i = 0; i < nglyphs(); i++)
+ gnames[i] = _cff->sid_permstring(_charset.gid_to_sid(i));
+}
+
+Charstring *
+Cff::Font::glyph(int gid) const
+{
+ if (gid < 0 || gid >= nglyphs())
+ return 0;
+ if (!_charstrings_cs[gid])
+ _charstrings_cs[gid] = charstring(_charstrings_index, gid);
+ return _charstrings_cs[gid];
+}
+
+Charstring *
+Cff::Font::glyph(PermString name) const
+{
+ int gid = _charset.sid_to_gid(_cff->sid(name));
+ if (gid < 0)
+ return 0;
+ if (!_charstrings_cs[gid])
+ _charstrings_cs[gid] = charstring(_charstrings_index, gid);
+ return _charstrings_cs[gid];
+}
+
+int
+Cff::Font::glyphid(PermString name) const
+{
+ return _charset.sid_to_gid(_cff->sid(name));
+}
+
+Type1Encoding *
+Cff::Font::type1_encoding() const
+{
+ if (_encoding_pos == 0)
+ return Type1Encoding::standard_encoding();
+ if (!_t1encoding)
+ _t1encoding = type1_encoding_copy();
+ return _t1encoding;
+}
+
+Type1Encoding *
+Cff::Font::type1_encoding_copy() const
+{
+ if (_encoding_pos == 0)
+ return Type1Encoding::standard_encoding();
+ Type1Encoding *e = new Type1Encoding;
+ for (int i = 0; i < 256; i++)
+ if (_encoding[i])
+ e->put(i, _cff->sid_permstring(_charset.gid_to_sid(_encoding[i])));
+ return e;
+}
+
+bool
+Cff::Font::dict_has(DictOperator op) const
+{
+ return dict_of(op).has(op);
+}
+
+String
+Cff::Font::dict_string(DictOperator op) const
+{
+ Vector<double> vec;
+ dict_of(op).value(op, vec);
+ if (vec.size() == 1 && vec[0] >= 0 && vec[0] <= _cff->max_sid())
+ return _cff->sid_string((int) vec[0]);
+ else
+ return String();
+}
+
+
+/*****
+ * Cff::CIDFont
+ **/
+
+Cff::CIDFont::CIDFont(Cff *cff, PermString font_name, const Dict &top_dict, ErrorHandler *errh)
+ : FontParent(cff), _font_name(font_name), _top_dict(top_dict)
+{
+ assert(_top_dict.has_first(oROS));
+
+ // parse top DICT
+ _error = -EINVAL;
+ if (_top_dict.check(false, errh, "Top DICT") < 0)
+ return;
+ else if (!_top_dict.has(oCharStrings)) {
+ errh->error("font has no CharStrings dictionary");
+ return;
+ }
+ //_top_dict.unparse(errh, "Top DICT");
+
+ // extract offsets and information from TOP DICT
+ _top_dict.value(oCharstringType, &_charstring_type);
+ if (_charstring_type != 1 && _charstring_type != 2) {
+ errh->error("unknown CharString type %d", _charstring_type);
+ return;
+ }
+
+ int charstrings_offset = 0;
+ _top_dict.value(oCharStrings, &charstrings_offset);
+ _charstrings_index = Cff::IndexIterator(cff->data(), charstrings_offset, cff->length(), errh, "CharStrings INDEX");
+ if (_charstrings_index.error() < 0) {
+ _error = _charstrings_index.error();
+ return;
+ }
+ _charstrings_cs.assign(_charstrings_index.nitems(), 0);
+
+ int charset = 0;
+ _top_dict.value(oCharset, &charset);
+ _charset.assign(cff, charset, _charstrings_index.nitems(), -1, errh);
+ if (_charset.error() < 0) {
+ _error = _charset.error();
+ return;
+ }
+
+ // extract information about child fonts
+ int fdarray_offset = 0;
+ if (!_top_dict.value(oFDArray, &fdarray_offset)) {
+ errh->error("CID-keyed font missing FDArray");
+ return;
+ }
+ IndexIterator fdarray_index(cff->data(), fdarray_offset, cff->length(), errh, "FDArray INDEX");
+ for (; fdarray_index; fdarray_index++) {
+ Dict d(cff, fdarray_index[0] - cff->data(), fdarray_index[1] - fdarray_index[0], errh, "Top DICT");
+ if (!d.ok() || d.check(false, errh, "Top DICT") < 0) {
+ _error = d.error();
+ return;
+ }
+ _child_fonts.push_back(new ChildFont(cff, this, _charstring_type, d, errh));
+ if (!_child_fonts.back()->ok())
+ return;
+ }
+
+ int fdselect_offset = 0;
+ if (!_top_dict.value(oFDSelect, &fdselect_offset)) {
+ errh->error("CID-keyed font missing FDSelect");
+ return;
+ }
+ _fdselect.assign(cff, fdselect_offset, _charstrings_cs.size(), errh);
+ if (_fdselect.error() < 0)
+ return;
+
+ // success!
+ _error = 0;
+ set_parent_program(true);
+}
+
+Cff::CIDFont::~CIDFont()
+{
+ for (int i = 0; i < _charstrings_cs.size(); i++)
+ delete _charstrings_cs[i];
+ for (int i = 0; i < _child_fonts.size(); i++)
+ delete _child_fonts[i];
+}
+
+void
+Cff::CIDFont::font_matrix(double matrix[6]) const
+{
+ // XXX
+ matrix[0] = matrix[3] = 0.001;
+ matrix[1] = matrix[2] = matrix[4] = matrix[5] = 0;
+}
+
+const CharstringProgram *
+Cff::CIDFont::child_program(int gid) const
+{
+ int fd = _fdselect.gid_to_fd(gid);
+ if (fd >= 0 && fd < _child_fonts.size())
+ return _child_fonts.at_u(fd);
+ else
+ return 0;
+}
+
+PermString
+Cff::CIDFont::glyph_name(int gid) const
+{
+ if (gid >= 0 && gid < nglyphs())
+ return permprintf("#%d", _charset.gid_to_sid(gid));
+ else
+ return PermString();
+}
+
+void
+Cff::CIDFont::glyph_names(Vector<PermString> &gnames) const
+{
+ gnames.resize(nglyphs());
+ for (int i = 0; i < nglyphs(); i++)
+ gnames[i] = permprintf("#%d", _charset.gid_to_sid(i));
+}
+
+Charstring *
+Cff::CIDFont::glyph(int gid) const
+{
+ if (gid < 0 || gid >= nglyphs())
+ return 0;
+ if (!_charstrings_cs[gid])
+ _charstrings_cs[gid] = charstring(_charstrings_index, gid);
+ return _charstrings_cs[gid];
+}
+
+int
+Cff::CIDFont::glyphid(PermString name) const
+{
+ if (name.length() <= 1 || name[0] != '#' || !isdigit((unsigned char) name[1]))
+ return -1;
+ char *endptr;
+ long cid = strtol(name.c_str() + 1, &endptr, 10);
+ if (*endptr != 0)
+ return -1;
+ return _charset.sid_to_gid(cid);
+}
+
+Charstring *
+Cff::CIDFont::glyph(PermString name) const
+{
+ return CIDFont::glyph(CIDFont::glyphid(name));
+}
+
+
+/*****
+ * ChildFont
+ **/
+
+Cff::ChildFont::ChildFont(Cff *cff, Cff::CIDFont *parent, int charstring_type, const Dict &top_dict, ErrorHandler *errh)
+ : FontParent(cff), _parent(parent), _top_dict(top_dict)
+{
+ if (!errh)
+ errh = ErrorHandler::silent_handler();
+
+ if (!cff->ok() || !_top_dict.ok()) {
+ errh->error("invalid CFF");
+ _error = -EINVAL;
+ return;
+ }
+
+ // extract offsets and information from TOP DICT
+ _charstring_type = charstring_type;
+ _top_dict.value(oCharstringType, &_charstring_type);
+ if (_charstring_type != 1 && _charstring_type != 2) {
+ errh->error("unknown CharString type %d", _charstring_type);
+ return;
+ }
+
+ // extract information from Private DICT
+ if (_top_dict.has(oPrivate)
+ && (_error = handle_private(cff, _top_dict, _private_dict, _default_width_x, _nominal_width_x, _subrs_index, _subrs_cs, errh)) < 0)
+ return;
+
+ // success!
+ _error = 0;
+}
+
+Cff::ChildFont::~ChildFont()
+{
+ for (int i = 0; i < _subrs_cs.size(); i++)
+ delete _subrs_cs[i];
+}
+
+Charstring *
+Cff::ChildFont::charstring(const IndexIterator &iiter, int which) const
+{
+ const uint8_t *s1 = iiter[which];
+ int slen = iiter[which + 1] - s1;
+ String cs = _cff->data_string().substring(s1 - _cff->data(), slen);
+ if (slen == 0)
+ return 0;
+ else if (_charstring_type == 1)
+ return new Type1Charstring(cs);
+ else
+ return new Type2Charstring(cs);
+}
+
+Charstring *
+Cff::ChildFont::subr(int i) const
+{
+ i += Efont::subr_bias(_charstring_type, nsubrs_x());
+ if (i < 0 || i >= nsubrs_x())
+ return 0;
+ if (!_subrs_cs[i])
+ _subrs_cs[i] = charstring(_subrs_index, i);
+ return _subrs_cs[i];
+}
+
+int
+Cff::ChildFont::subr_bias() const
+{
+ return Efont::subr_bias(_charstring_type, nsubrs_x());
+}
+
+double
+Cff::ChildFont::global_width_x(bool is_nominal) const
+{
+ return (is_nominal ? _nominal_width_x : _default_width_x);
+}
+
+}