From 14d0fbe96c6abdb9da80e99953aec672f999948c Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Sun, 13 Dec 2020 19:22:19 +0900 Subject: Renaming of files in preparation for code style tools. Signed-off-by: Michele Calgaro --- kpdf/xpdf/fofi/CMakeLists.txt | 4 +- kpdf/xpdf/fofi/FoFiBase.cc | 156 --- kpdf/xpdf/fofi/FoFiBase.cpp | 156 +++ kpdf/xpdf/fofi/FoFiEncodings.cc | 994 --------------- kpdf/xpdf/fofi/FoFiEncodings.cpp | 994 +++++++++++++++ kpdf/xpdf/fofi/FoFiTrueType.cc | 2040 ----------------------------- kpdf/xpdf/fofi/FoFiTrueType.cpp | 2040 +++++++++++++++++++++++++++++ kpdf/xpdf/fofi/FoFiType1.cc | 257 ---- kpdf/xpdf/fofi/FoFiType1.cpp | 257 ++++ kpdf/xpdf/fofi/FoFiType1C.cc | 2603 -------------------------------------- kpdf/xpdf/fofi/FoFiType1C.cpp | 2603 ++++++++++++++++++++++++++++++++++++++ kpdf/xpdf/fofi/Makefile.am | 4 +- 12 files changed, 6054 insertions(+), 6054 deletions(-) delete mode 100644 kpdf/xpdf/fofi/FoFiBase.cc create mode 100644 kpdf/xpdf/fofi/FoFiBase.cpp delete mode 100644 kpdf/xpdf/fofi/FoFiEncodings.cc create mode 100644 kpdf/xpdf/fofi/FoFiEncodings.cpp delete mode 100644 kpdf/xpdf/fofi/FoFiTrueType.cc create mode 100644 kpdf/xpdf/fofi/FoFiTrueType.cpp delete mode 100644 kpdf/xpdf/fofi/FoFiType1.cc create mode 100644 kpdf/xpdf/fofi/FoFiType1.cpp delete mode 100644 kpdf/xpdf/fofi/FoFiType1C.cc create mode 100644 kpdf/xpdf/fofi/FoFiType1C.cpp (limited to 'kpdf/xpdf/fofi') diff --git a/kpdf/xpdf/fofi/CMakeLists.txt b/kpdf/xpdf/fofi/CMakeLists.txt index e98957f3..2f983315 100644 --- a/kpdf/xpdf/fofi/CMakeLists.txt +++ b/kpdf/xpdf/fofi/CMakeLists.txt @@ -21,6 +21,6 @@ include_directories( tde_add_library( fofi STATIC_PIC SOURCES - FoFiBase.cc FoFiEncodings.cc FoFiTrueType.cc FoFiType1.cc - FoFiType1C.cc + FoFiBase.cpp FoFiEncodings.cpp FoFiTrueType.cpp FoFiType1.cpp + FoFiType1C.cpp ) diff --git a/kpdf/xpdf/fofi/FoFiBase.cc b/kpdf/xpdf/fofi/FoFiBase.cc deleted file mode 100644 index 28d0b8ca..00000000 --- a/kpdf/xpdf/fofi/FoFiBase.cc +++ /dev/null @@ -1,156 +0,0 @@ -//======================================================================== -// -// FoFiBase.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "FoFiBase.h" - -//------------------------------------------------------------------------ -// FoFiBase -//------------------------------------------------------------------------ - -FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) { - fileData = file = (Guchar *)fileA; - len = lenA; - freeFileData = freeFileDataA; -} - -FoFiBase::~FoFiBase() { - if (freeFileData) { - gfree(fileData); - } -} - -char *FoFiBase::readFile(char *fileName, int *fileLen) { - FILE *f; - char *buf; - int n; - - if (!(f = fopen(fileName, "rb"))) { - return NULL; - } - fseek(f, 0, SEEK_END); - n = (int)ftell(f); - fseek(f, 0, SEEK_SET); - buf = (char *)gmalloc(n); - if ((int)fread(buf, 1, n, f) != n) { - gfree(buf); - fclose(f); - return NULL; - } - fclose(f); - *fileLen = n; - return buf; -} - -int FoFiBase::getS8(int pos, GBool *ok) { - int x; - - if (pos < 0 || pos >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - if (x & 0x80) { - x |= ~0xff; - } - return x; -} - -int FoFiBase::getU8(int pos, GBool *ok) { - if (pos < 0 || pos >= len) { - *ok = gFalse; - return 0; - } - return file[pos]; -} - -int FoFiBase::getS16BE(int pos, GBool *ok) { - int x; - - if (pos < 0 || pos+1 >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - x = (x << 8) + file[pos+1]; - if (x & 0x8000) { - x |= ~0xffff; - } - return x; -} - -int FoFiBase::getU16BE(int pos, GBool *ok) { - int x; - - if (pos < 0 || pos+1 >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - x = (x << 8) + file[pos+1]; - return x; -} - -int FoFiBase::getS32BE(int pos, GBool *ok) { - int x; - - if (pos < 0 || pos+3 >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - x = (x << 8) + file[pos+1]; - x = (x << 8) + file[pos+2]; - x = (x << 8) + file[pos+3]; - if (x & 0x80000000) { - x |= ~0xffffffff; - } - return x; -} - -Guint FoFiBase::getU32BE(int pos, GBool *ok) { - Guint x; - - if (pos < 0 || pos+3 >= len) { - *ok = gFalse; - return 0; - } - x = file[pos]; - x = (x << 8) + file[pos+1]; - x = (x << 8) + file[pos+2]; - x = (x << 8) + file[pos+3]; - return x; -} - -Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) { - Guint x; - int i; - - if (pos < 0 || pos + size > len) { - *ok = gFalse; - return 0; - } - x = 0; - for (i = 0; i < size; ++i) { - x = (x << 8) + file[pos + i]; - } - return x; -} - -GBool FoFiBase::checkRegion(int pos, int size) { - return pos >= 0 && - pos + size >= pos && - pos + size <= len; -} diff --git a/kpdf/xpdf/fofi/FoFiBase.cpp b/kpdf/xpdf/fofi/FoFiBase.cpp new file mode 100644 index 00000000..af6fe112 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiBase.cpp @@ -0,0 +1,156 @@ +//======================================================================== +// +// FoFiBase.cpp +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "FoFiBase.h" + +//------------------------------------------------------------------------ +// FoFiBase +//------------------------------------------------------------------------ + +FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) { + fileData = file = (Guchar *)fileA; + len = lenA; + freeFileData = freeFileDataA; +} + +FoFiBase::~FoFiBase() { + if (freeFileData) { + gfree(fileData); + } +} + +char *FoFiBase::readFile(char *fileName, int *fileLen) { + FILE *f; + char *buf; + int n; + + if (!(f = fopen(fileName, "rb"))) { + return NULL; + } + fseek(f, 0, SEEK_END); + n = (int)ftell(f); + fseek(f, 0, SEEK_SET); + buf = (char *)gmalloc(n); + if ((int)fread(buf, 1, n, f) != n) { + gfree(buf); + fclose(f); + return NULL; + } + fclose(f); + *fileLen = n; + return buf; +} + +int FoFiBase::getS8(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + if (x & 0x80) { + x |= ~0xff; + } + return x; +} + +int FoFiBase::getU8(int pos, GBool *ok) { + if (pos < 0 || pos >= len) { + *ok = gFalse; + return 0; + } + return file[pos]; +} + +int FoFiBase::getS16BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+1 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + if (x & 0x8000) { + x |= ~0xffff; + } + return x; +} + +int FoFiBase::getU16BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+1 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + return x; +} + +int FoFiBase::getS32BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+3]; + if (x & 0x80000000) { + x |= ~0xffffffff; + } + return x; +} + +Guint FoFiBase::getU32BE(int pos, GBool *ok) { + Guint x; + + if (pos < 0 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+3]; + return x; +} + +Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) { + Guint x; + int i; + + if (pos < 0 || pos + size > len) { + *ok = gFalse; + return 0; + } + x = 0; + for (i = 0; i < size; ++i) { + x = (x << 8) + file[pos + i]; + } + return x; +} + +GBool FoFiBase::checkRegion(int pos, int size) { + return pos >= 0 && + pos + size >= pos && + pos + size <= len; +} diff --git a/kpdf/xpdf/fofi/FoFiEncodings.cc b/kpdf/xpdf/fofi/FoFiEncodings.cc deleted file mode 100644 index 37a17f5d..00000000 --- a/kpdf/xpdf/fofi/FoFiEncodings.cc +++ /dev/null @@ -1,994 +0,0 @@ -//======================================================================== -// -// FoFiEncodings.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "FoFiEncodings.h" - -//------------------------------------------------------------------------ -// Type 1 and 1C font data -//------------------------------------------------------------------------ - -char *fofiType1StandardEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - NULL, - "endash", - "dagger", - "daggerdbl", - "periodcentered", - NULL, - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - NULL, - "questiondown", - NULL, - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - NULL, - "ring", - "cedilla", - NULL, - "hungarumlaut", - "ogonek", - "caron", - "emdash", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "AE", - NULL, - "ordfeminine", - NULL, - NULL, - NULL, - NULL, - "Lslash", - "Oslash", - "OE", - "ordmasculine", - NULL, - NULL, - NULL, - NULL, - NULL, - "ae", - NULL, - NULL, - NULL, - "dotlessi", - NULL, - NULL, - "lslash", - "oslash", - "oe", - "germandbls", - NULL, - NULL, - NULL, - NULL -}; - -char *fofiType1ExpertEncoding[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclamsmall", - "Hungarumlautsmall", - NULL, - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "comma", - "hyphen", - "period", - "fraction", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "colon", - "semicolon", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - NULL, - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - NULL, - NULL, - NULL, - "isuperior", - NULL, - NULL, - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - NULL, - NULL, - "rsuperior", - "ssuperior", - "tsuperior", - NULL, - "ff", - "fi", - "fl", - "ffi", - "ffl", - "parenleftinferior", - NULL, - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - NULL, - NULL, - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - NULL, - "Dotaccentsmall", - NULL, - NULL, - "Macronsmall", - NULL, - NULL, - "figuredash", - "hypheninferior", - NULL, - NULL, - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - NULL, - NULL, - NULL, - "onequarter", - "onehalf", - "threequarters", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - NULL, - NULL, - "zerosuperior", - "onesuperior", - "twosuperior", - "threesuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall" -}; - -//------------------------------------------------------------------------ -// Type 1C font data -//------------------------------------------------------------------------ - -char *fofiType1CStdStrings[391] = { - ".notdef", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "endash", - "dagger", - "daggerdbl", - "periodcentered", - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - "questiondown", - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "emdash", - "AE", - "ordfeminine", - "Lslash", - "Oslash", - "OE", - "ordmasculine", - "ae", - "dotlessi", - "lslash", - "oslash", - "oe", - "germandbls", - "onesuperior", - "logicalnot", - "mu", - "trademark", - "Eth", - "onehalf", - "plusminus", - "Thorn", - "onequarter", - "divide", - "brokenbar", - "degree", - "thorn", - "threequarters", - "twosuperior", - "registered", - "minus", - "eth", - "multiply", - "threesuperior", - "copyright", - "Aacute", - "Acircumflex", - "Adieresis", - "Agrave", - "Aring", - "Atilde", - "Ccedilla", - "Eacute", - "Ecircumflex", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Ntilde", - "Oacute", - "Ocircumflex", - "Odieresis", - "Ograve", - "Otilde", - "Scaron", - "Uacute", - "Ucircumflex", - "Udieresis", - "Ugrave", - "Yacute", - "Ydieresis", - "Zcaron", - "aacute", - "acircumflex", - "adieresis", - "agrave", - "aring", - "atilde", - "ccedilla", - "eacute", - "ecircumflex", - "edieresis", - "egrave", - "iacute", - "icircumflex", - "idieresis", - "igrave", - "ntilde", - "oacute", - "ocircumflex", - "odieresis", - "ograve", - "otilde", - "scaron", - "uacute", - "ucircumflex", - "udieresis", - "ugrave", - "yacute", - "ydieresis", - "zcaron", - "exclamsmall", - "Hungarumlautsmall", - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - "isuperior", - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - "rsuperior", - "ssuperior", - "tsuperior", - "ff", - "ffi", - "ffl", - "parenleftinferior", - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - "Dotaccentsmall", - "Macronsmall", - "figuredash", - "hypheninferior", - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - "zerosuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall", - "001.000", - "001.001", - "001.002", - "001.003", - "Black", - "Bold", - "Book", - "Light", - "Medium", - "Regular", - "Roman", - "Semibold" -}; - -Gushort fofiType1CISOAdobeCharset[229] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228 -}; - -Gushort fofiType1CExpertCharset[166] = { - 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, - 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, - 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, - 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378 -}; - -Gushort fofiType1CExpertSubsetCharset[87] = { - 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, - 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, - 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, - 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, - 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346 -}; diff --git a/kpdf/xpdf/fofi/FoFiEncodings.cpp b/kpdf/xpdf/fofi/FoFiEncodings.cpp new file mode 100644 index 00000000..3c0d39a3 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiEncodings.cpp @@ -0,0 +1,994 @@ +//======================================================================== +// +// FoFiEncodings.cpp +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "FoFiEncodings.h" + +//------------------------------------------------------------------------ +// Type 1 and 1C font data +//------------------------------------------------------------------------ + +char *fofiType1StandardEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + NULL, + "endash", + "dagger", + "daggerdbl", + "periodcentered", + NULL, + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + NULL, + "questiondown", + NULL, + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + NULL, + "ring", + "cedilla", + NULL, + "hungarumlaut", + "ogonek", + "caron", + "emdash", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "AE", + NULL, + "ordfeminine", + NULL, + NULL, + NULL, + NULL, + "Lslash", + "Oslash", + "OE", + "ordmasculine", + NULL, + NULL, + NULL, + NULL, + NULL, + "ae", + NULL, + NULL, + NULL, + "dotlessi", + NULL, + NULL, + "lslash", + "oslash", + "oe", + "germandbls", + NULL, + NULL, + NULL, + NULL +}; + +char *fofiType1ExpertEncoding[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "space", + "exclamsmall", + "Hungarumlautsmall", + NULL, + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "comma", + "hyphen", + "period", + "fraction", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "colon", + "semicolon", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + NULL, + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + NULL, + NULL, + NULL, + "isuperior", + NULL, + NULL, + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + NULL, + NULL, + "rsuperior", + "ssuperior", + "tsuperior", + NULL, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + NULL, + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + NULL, + NULL, + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + NULL, + "Dotaccentsmall", + NULL, + NULL, + "Macronsmall", + NULL, + NULL, + "figuredash", + "hypheninferior", + NULL, + NULL, + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + NULL, + NULL, + NULL, + "onequarter", + "onehalf", + "threequarters", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + NULL, + NULL, + "zerosuperior", + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall" +}; + +//------------------------------------------------------------------------ +// Type 1C font data +//------------------------------------------------------------------------ + +char *fofiType1CStdStrings[391] = { + ".notdef", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotesingle", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcentered", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "lslash", + "oslash", + "oe", + "germandbls", + "onesuperior", + "logicalnot", + "mu", + "trademark", + "Eth", + "onehalf", + "plusminus", + "Thorn", + "onequarter", + "divide", + "brokenbar", + "degree", + "thorn", + "threequarters", + "twosuperior", + "registered", + "minus", + "eth", + "multiply", + "threesuperior", + "copyright", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "Zcaron", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "ccedilla", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "otilde", + "scaron", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "zcaron", + "exclamsmall", + "Hungarumlautsmall", + "dollaroldstyle", + "dollarsuperior", + "ampersandsmall", + "Acutesmall", + "parenleftsuperior", + "parenrightsuperior", + "twodotenleader", + "onedotenleader", + "zerooldstyle", + "oneoldstyle", + "twooldstyle", + "threeoldstyle", + "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", + "sevenoldstyle", + "eightoldstyle", + "nineoldstyle", + "commasuperior", + "threequartersemdash", + "periodsuperior", + "questionsmall", + "asuperior", + "bsuperior", + "centsuperior", + "dsuperior", + "esuperior", + "isuperior", + "lsuperior", + "msuperior", + "nsuperior", + "osuperior", + "rsuperior", + "ssuperior", + "tsuperior", + "ff", + "ffi", + "ffl", + "parenleftinferior", + "parenrightinferior", + "Circumflexsmall", + "hyphensuperior", + "Gravesmall", + "Asmall", + "Bsmall", + "Csmall", + "Dsmall", + "Esmall", + "Fsmall", + "Gsmall", + "Hsmall", + "Ismall", + "Jsmall", + "Ksmall", + "Lsmall", + "Msmall", + "Nsmall", + "Osmall", + "Psmall", + "Qsmall", + "Rsmall", + "Ssmall", + "Tsmall", + "Usmall", + "Vsmall", + "Wsmall", + "Xsmall", + "Ysmall", + "Zsmall", + "colonmonetary", + "onefitted", + "rupiah", + "Tildesmall", + "exclamdownsmall", + "centoldstyle", + "Lslashsmall", + "Scaronsmall", + "Zcaronsmall", + "Dieresissmall", + "Brevesmall", + "Caronsmall", + "Dotaccentsmall", + "Macronsmall", + "figuredash", + "hypheninferior", + "Ogoneksmall", + "Ringsmall", + "Cedillasmall", + "questiondownsmall", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + "zerosuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "eightsuperior", + "ninesuperior", + "zeroinferior", + "oneinferior", + "twoinferior", + "threeinferior", + "fourinferior", + "fiveinferior", + "sixinferior", + "seveninferior", + "eightinferior", + "nineinferior", + "centinferior", + "dollarinferior", + "periodinferior", + "commainferior", + "Agravesmall", + "Aacutesmall", + "Acircumflexsmall", + "Atildesmall", + "Adieresissmall", + "Aringsmall", + "AEsmall", + "Ccedillasmall", + "Egravesmall", + "Eacutesmall", + "Ecircumflexsmall", + "Edieresissmall", + "Igravesmall", + "Iacutesmall", + "Icircumflexsmall", + "Idieresissmall", + "Ethsmall", + "Ntildesmall", + "Ogravesmall", + "Oacutesmall", + "Ocircumflexsmall", + "Otildesmall", + "Odieresissmall", + "OEsmall", + "Oslashsmall", + "Ugravesmall", + "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", + "Yacutesmall", + "Thornsmall", + "Ydieresissmall", + "001.000", + "001.001", + "001.002", + "001.003", + "Black", + "Bold", + "Book", + "Light", + "Medium", + "Regular", + "Roman", + "Semibold" +}; + +Gushort fofiType1CISOAdobeCharset[229] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228 +}; + +Gushort fofiType1CExpertCharset[166] = { + 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, + 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 +}; + +Gushort fofiType1CExpertSubsetCharset[87] = { + 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, + 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, + 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, + 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, + 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 +}; diff --git a/kpdf/xpdf/fofi/FoFiTrueType.cc b/kpdf/xpdf/fofi/FoFiTrueType.cc deleted file mode 100644 index a205a068..00000000 --- a/kpdf/xpdf/fofi/FoFiTrueType.cc +++ /dev/null @@ -1,2040 +0,0 @@ -//======================================================================== -// -// FoFiTrueType.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gtypes.h" -#include "gmem.h" -#include "GString.h" -#include "GHash.h" -#include "FoFiType1C.h" -#include "FoFiTrueType.h" - -// -// Terminology -// ----------- -// -// character code = number used as an element of a text string -// -// character name = glyph name = name for a particular glyph within a -// font -// -// glyph index = GID = position (within some internal table in the font) -// where the instructions to draw a particular glyph are -// stored -// -// Type 1 fonts -// ------------ -// -// Type 1 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of instructions, keyed by character names, -// maps character name to glyph data -// -// CharStrings[charName] = glyphData -// -// TrueType fonts -// -------------- -// -// TrueType fonts contain: -// -// 'cmap' table: mapping from character code to glyph index; there may -// be multiple cmaps in a TrueType font -// -// cmap[charCode] = gid -// -// 'post' table: mapping from glyph index to glyph name -// -// post[gid] = glyphName -// -// Type 42 fonts -// ------------- -// -// Type 42 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of glyph indexes, keyed by character names, -// maps character name to glyph index -// -// CharStrings[charName] = gid -// - -//------------------------------------------------------------------------ - -#define ttcfTag 0x74746366 - -//------------------------------------------------------------------------ - -struct TrueTypeTable { - Guint tag; - Guint checksum; - int offset; - int origOffset; - int len; -}; - -struct TrueTypeCmap { - int platform; - int encoding; - int offset; - int len; - int fmt; -}; - -struct TrueTypeLoca { - int idx; - int origOffset; - int newOffset; - int len; -}; - -#define cmapTag 0x636d6170 -#define glyfTag 0x676c7966 -#define headTag 0x68656164 -#define hheaTag 0x68686561 -#define hmtxTag 0x686d7478 -#define locaTag 0x6c6f6361 -#define nameTag 0x6e616d65 -#define os2Tag 0x4f532f32 -#define postTag 0x706f7374 - -static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) { - TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; - TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; - - if (loca1->origOffset == loca2->origOffset) { - return loca1->idx - loca2->idx; - } - return loca1->origOffset - loca2->origOffset; -} - -static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { - TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; - TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; - - return loca1->idx - loca2->idx; -} - -static int cmpTrueTypeTableTag(const void *p1, const void *p2) { - TrueTypeTable *tab1 = (TrueTypeTable *)p1; - TrueTypeTable *tab2 = (TrueTypeTable *)p2; - - return (int)tab1->tag - (int)tab2->tag; -} - -//------------------------------------------------------------------------ - -struct T42Table { - char *tag; // 4-byte tag - GBool required; // required by the TrueType spec? -}; - -// TrueType tables to be embedded in Type 42 fonts. -// NB: the table names must be in alphabetical order here. -#define nT42Tables 11 -static T42Table t42Tables[nT42Tables] = { - { "cvt ", gTrue }, - { "fpgm", gTrue }, - { "glyf", gTrue }, - { "head", gTrue }, - { "hhea", gTrue }, - { "hmtx", gTrue }, - { "loca", gTrue }, - { "maxp", gTrue }, - { "prep", gTrue }, - { "vhea", gFalse }, - { "vmtx", gFalse } -}; -#define t42HeadTable 3 -#define t42LocaTable 6 -#define t42GlyfTable 2 -#define t42VheaTable 9 -#define t42VmtxTable 10 - -//------------------------------------------------------------------------ - -// Glyph names in some arbitrary standard order that Apple uses for -// their TrueType fonts. -static char *macGlyphNames[258] = { - ".notdef", "null", "CR", "space", - "exclam", "quotedbl", "numbersign", "dollar", - "percent", "ampersand", "quotesingle", "parenleft", - "parenright", "asterisk", "plus", "comma", - "hyphen", "period", "slash", "zero", - "one", "two", "three", "four", - "five", "six", "seven", "eight", - "nine", "colon", "semicolon", "less", - "equal", "greater", "question", "at", - "A", "B", "C", "D", - "E", "F", "G", "H", - "I", "J", "K", "L", - "M", "N", "O", "P", - "Q", "R", "S", "T", - "U", "V", "W", "X", - "Y", "Z", "bracketleft", "backslash", - "bracketright", "asciicircum", "underscore", "grave", - "a", "b", "c", "d", - "e", "f", "g", "h", - "i", "j", "k", "l", - "m", "n", "o", "p", - "q", "r", "s", "t", - "u", "v", "w", "x", - "y", "z", "braceleft", "bar", - "braceright", "asciitilde", "Adieresis", "Aring", - "Ccedilla", "Eacute", "Ntilde", "Odieresis", - "Udieresis", "aacute", "agrave", "acircumflex", - "adieresis", "atilde", "aring", "ccedilla", - "eacute", "egrave", "ecircumflex", "edieresis", - "iacute", "igrave", "icircumflex", "idieresis", - "ntilde", "oacute", "ograve", "ocircumflex", - "odieresis", "otilde", "uacute", "ugrave", - "ucircumflex", "udieresis", "dagger", "degree", - "cent", "sterling", "section", "bullet", - "paragraph", "germandbls", "registered", "copyright", - "trademark", "acute", "dieresis", "notequal", - "AE", "Oslash", "infinity", "plusminus", - "lessequal", "greaterequal", "yen", "mu1", - "partialdiff", "summation", "product", "pi", - "integral", "ordfeminine", "ordmasculine", "Ohm", - "ae", "oslash", "questiondown", "exclamdown", - "logicalnot", "radical", "florin", "approxequal", - "increment", "guillemotleft", "guillemotright", "ellipsis", - "nbspace", "Agrave", "Atilde", "Otilde", - "OE", "oe", "endash", "emdash", - "quotedblleft", "quotedblright", "quoteleft", "quoteright", - "divide", "lozenge", "ydieresis", "Ydieresis", - "fraction", "currency", "guilsinglleft", "guilsinglright", - "fi", "fl", "daggerdbl", "periodcentered", - "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", - "Ecircumflex", "Aacute", "Edieresis", "Egrave", - "Iacute", "Icircumflex", "Idieresis", "Igrave", - "Oacute", "Ocircumflex", "applelogo", "Ograve", - "Uacute", "Ucircumflex", "Ugrave", "dotlessi", - "circumflex", "tilde", "overscore", "breve", - "dotaccent", "ring", "cedilla", "hungarumlaut", - "ogonek", "caron", "Lslash", "lslash", - "Scaron", "scaron", "Zcaron", "zcaron", - "brokenbar", "Eth", "eth", "Yacute", - "yacute", "Thorn", "thorn", "minus", - "multiply", "onesuperior", "twosuperior", "threesuperior", - "onehalf", "onequarter", "threequarters", "franc", - "Gbreve", "gbreve", "Idot", "Scedilla", - "scedilla", "Cacute", "cacute", "Ccaron", - "ccaron", "dmacron" -}; - -//------------------------------------------------------------------------ -// FoFiTrueType -//------------------------------------------------------------------------ - -FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) { - FoFiTrueType *ff; - - ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA); - if (!ff->parsedOk) { - delete ff; - return NULL; - } - return ff; -} - -FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) { - FoFiTrueType *ff; - char *fileA; - int lenA; - - if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { - return NULL; - } - ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA); - if (!ff->parsedOk) { - delete ff; - return NULL; - } - return ff; -} - -FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA): - FoFiBase(fileA, lenA, freeFileDataA) -{ - tables = NULL; - nTables = 0; - cmaps = NULL; - nCmaps = 0; - nameToGID = NULL; - parsedOk = gFalse; - faceIndex = faceIndexA; - - parse(); -} - -FoFiTrueType::~FoFiTrueType() { - gfree(tables); - gfree(cmaps); - if (nameToGID) { - delete nameToGID; - } -} - -int FoFiTrueType::getNumCmaps() { - return nCmaps; -} - -int FoFiTrueType::getCmapPlatform(int i) { - return cmaps[i].platform; -} - -int FoFiTrueType::getCmapEncoding(int i) { - return cmaps[i].encoding; -} - -int FoFiTrueType::findCmap(int platform, int encoding) { - int i; - - for (i = 0; i < nCmaps; ++i) { - if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) { - return i; - } - } - return -1; -} - -Gushort FoFiTrueType::mapCodeToGID(int i, int c) { - Gushort gid; - int segCnt, segEnd, segStart, segDelta, segOffset; - int cmapFirst, cmapLen; - int pos, a, b, m; - GBool ok; - - if (i < 0 || i >= nCmaps) { - return 0; - } - ok = gTrue; - pos = cmaps[i].offset; - switch (cmaps[i].fmt) { - case 0: - if (c < 0 || c >= cmaps[i].len - 6) { - return 0; - } - gid = getU8(cmaps[i].offset + 6 + c, &ok); - break; - case 4: - segCnt = getU16BE(pos + 6, &ok) / 2; - a = -1; - b = segCnt - 1; - segEnd = getU16BE(pos + 14 + 2*b, &ok); - if (c > segEnd) { - // malformed font -- the TrueType spec requires the last segEnd - // to be 0xffff - return 0; - } - // invariant: seg[a].end < code <= seg[b].end - while (b - a > 1 && ok) { - m = (a + b) / 2; - segEnd = getU16BE(pos + 14 + 2*m, &ok); - if (segEnd < c) { - a = m; - } else { - b = m; - } - } - segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok); - segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok); - segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok); - if (c < segStart) { - return 0; - } - if (segOffset == 0) { - gid = (c + segDelta) & 0xffff; - } else { - gid = getU16BE(pos + 16 + 6*segCnt + 2*b + - segOffset + 2 * (c - segStart), &ok); - if (gid != 0) { - gid = (gid + segDelta) & 0xffff; - } - } - break; - case 6: - cmapFirst = getU16BE(pos + 6, &ok); - cmapLen = getU16BE(pos + 8, &ok); - if (c < cmapFirst || c >= cmapFirst + cmapLen) { - return 0; - } - gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok); - break; - default: - return 0; - } - if (!ok) { - return 0; - } - return gid; -} - -int FoFiTrueType::mapNameToGID(char *name) { - if (!nameToGID) { - return 0; - } - return nameToGID->lookupInt(name); -} - -Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) { - FoFiType1C *ff; - Gushort *map; - int i; - - *nCIDs = 0; - if (!openTypeCFF) { - return NULL; - } - i = seekTable("CFF "); - if (!checkRegion(tables[i].offset, tables[i].len)) { - return NULL; - } - if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, - tables[i].len))) { - return NULL; - } - map = ff->getCIDToGIDMap(nCIDs); - delete ff; - return map; -} - -int FoFiTrueType::getEmbeddingRights() { - int i, fsType; - GBool ok; - - if ((i = seekTable("OS/2")) < 0) { - return 4; - } - ok = gTrue; - fsType = getU16BE(tables[i].offset + 8, &ok); - if (!ok) { - return 4; - } - if (fsType & 0x0008) { - return 2; - } - if (fsType & 0x0004) { - return 1; - } - if (fsType & 0x0002) { - return 0; - } - return 3; -} - -void FoFiTrueType::convertToType42(char *psName, char **encoding, - Gushort *codeToGID, - FoFiOutputFunc outputFunc, - void *outputStream) { - GString *buf; - GBool ok; - - if (openTypeCFF) { - return; - } - - // write the header - ok = gTrue; - buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", - (double)getS32BE(0, &ok) / 65536.0); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - - // begin the font dictionary - (*outputFunc)(outputStream, "10 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - - // write the guts of the dictionary - cvtEncoding(encoding, outputFunc, outputStream); - cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); - cvtSfnts(outputFunc, outputStream, NULL, gFalse); - - // end the dictionary and define the font - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); -} - -void FoFiTrueType::convertToType1(char *psName, char **newEncoding, - GBool ascii, FoFiOutputFunc outputFunc, - void *outputStream) { - FoFiType1C *ff; - int i; - - if (!openTypeCFF) { - return; - } - i = seekTable("CFF "); - if (!checkRegion(tables[i].offset, tables[i].len)) { - return; - } - if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, - tables[i].len))) { - return; - } - ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream); - delete ff; -} - -void FoFiTrueType::convertToCIDType2(char *psName, - Gushort *cidMap, int nCIDs, - GBool needVerticalMetrics, - FoFiOutputFunc outputFunc, - void *outputStream) { - GString *buf; - Gushort cid; - GBool ok; - int i, j, k; - - if (openTypeCFF) { - return; - } - - // write the header - ok = gTrue; - buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", - (double)getS32BE(0, &ok) / 65536.0); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - - // begin the font dictionary - (*outputFunc)(outputStream, "20 dict begin\n", 14); - (*outputFunc)(outputStream, "/CIDFontName /", 14); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); - (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); - (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); - (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); - (*outputFunc)(outputStream, " end def\n", 10); - (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); - if (cidMap) { - buf = GString::format("/CIDCount {0:d} def\n", nCIDs); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - if (nCIDs > 32767) { - (*outputFunc)(outputStream, "/CIDMap [", 9); - for (i = 0; i < nCIDs; i += 32768 - 16) { - (*outputFunc)(outputStream, "<\n", 2); - for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { - (*outputFunc)(outputStream, " ", 2); - for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { - cid = cidMap[i+j+k]; - buf = GString::format("{0:02x}{1:02x}", - (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "\n", 1); - } - (*outputFunc)(outputStream, " >", 3); - } - (*outputFunc)(outputStream, "\n", 1); - (*outputFunc)(outputStream, "] def\n", 6); - } else { - (*outputFunc)(outputStream, "/CIDMap <\n", 10); - for (i = 0; i < nCIDs; i += 16) { - (*outputFunc)(outputStream, " ", 2); - for (j = 0; j < 16 && i+j < nCIDs; ++j) { - cid = cidMap[i+j]; - buf = GString::format("{0:02x}{1:02x}", - (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "\n", 1); - } - (*outputFunc)(outputStream, "> def\n", 6); - } - } else { - // direct mapping - just fill the string(s) with s[i]=i - buf = GString::format("/CIDCount {0:d} def\n", nGlyphs); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - if (nGlyphs > 32767) { - (*outputFunc)(outputStream, "/CIDMap [\n", 10); - for (i = 0; i < nGlyphs; i += 32767) { - j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; - buf = GString::format(" {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format(" 2 copy dup 2 mul exch {0:d} add -8 bitshift put\n", - i); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format(" 1 index exch dup 2 mul 1 add exch {0:d} add" - " 255 and put\n", i); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, " } for\n", 8); - } - (*outputFunc)(outputStream, "] def\n", 6); - } else { - buf = GString::format("/CIDMap {0:d} string\n", 2 * nGlyphs); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format(" 0 1 {0:d} {{\n", nGlyphs - 1); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, - " 2 copy dup 2 mul exch -8 bitshift put\n", 42); - (*outputFunc)(outputStream, - " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); - (*outputFunc)(outputStream, " } for\n", 8); - (*outputFunc)(outputStream, "def\n", 4); - } - } - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); - (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); - (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); - (*outputFunc)(outputStream, " end readonly def\n", 19); - - // write the guts of the dictionary - cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics); - - // end the dictionary and define the font - (*outputFunc)(outputStream, - "CIDFontName currentdict end /CIDFont defineresource pop\n", - 56); -} - -void FoFiTrueType::convertToCIDType0(char *psName, - FoFiOutputFunc outputFunc, - void *outputStream) { - FoFiType1C *ff; - int i; - - if (!openTypeCFF) { - return; - } - i = seekTable("CFF "); - if (!checkRegion(tables[i].offset, tables[i].len)) { - return; - } - if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, - tables[i].len))) { - return; - } - ff->convertToCIDType0(psName, outputFunc, outputStream); - delete ff; -} - -void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, - GBool needVerticalMetrics, - FoFiOutputFunc outputFunc, - void *outputStream) { - GString *buf; - GString *sfntsName; - int n, i, j; - - if (openTypeCFF) { - return; - } - - // write the Type 42 sfnts array - sfntsName = (new GString(psName))->append("_sfnts"); - cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics); - delete sfntsName; - - // write the descendant Type 42 fonts - n = cidMap ? nCIDs : nGlyphs; - for (i = 0; i < n; i += 256) { - (*outputFunc)(outputStream, "10 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - buf = GString::format("_{0:02x} def\n", i >> 8); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - (*outputFunc)(outputStream, "/sfnts ", 7); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, "_sfnts def\n", 11); - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - for (j = 0; j < 256 && i+j < n; ++j) { - buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "readonly def\n", 13); - (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); - (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); - for (j = 0; j < 256 && i+j < n; ++j) { - buf = GString::format("/c{0:02x} {1:d} def\n", - j, cidMap ? cidMap[i+j] : i+j); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "end readonly def\n", 17); - (*outputFunc)(outputStream, - "FontName currentdict end definefont pop\n", 40); - } - - // write the Type 0 parent font - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 0 def\n", 16); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); - (*outputFunc)(outputStream, "/Encoding [\n", 12); - for (i = 0; i < n; i += 256) { - buf = GString::format("{0:d}\n", i >> 8); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "/FDepVector [\n", 14); - for (i = 0; i < n; i += 256) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, psName, strlen(psName)); - buf = GString::format("_{0:02x} findfont\n", i >> 8); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); -} - -void FoFiTrueType::convertToType0(char *psName, - FoFiOutputFunc outputFunc, - void *outputStream) { - FoFiType1C *ff; - int i; - - if (!openTypeCFF) { - return; - } - i = seekTable("CFF "); - if (!checkRegion(tables[i].offset, tables[i].len)) { - return; - } - if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, - tables[i].len))) { - return; - } - ff->convertToType0(psName, outputFunc, outputStream); - delete ff; -} - -void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, - void *outputStream, char *name, - Gushort *codeToGID) { - // this substitute cmap table maps char codes 0000-ffff directly to - // glyphs 0000-ffff - static char cmapTab[36] = { - 0, 0, // table version number - 0, 1, // number of encoding tables - 0, 1, // platform ID - 0, 0, // encoding ID - 0, 0, 0, 12, // offset of subtable - 0, 4, // subtable format - 0, 24, // subtable length - 0, 0, // subtable version - 0, 2, // segment count * 2 - 0, 2, // 2 * 2 ^ floor(log2(segCount)) - 0, 0, // floor(log2(segCount)) - 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) - (char)0xff, (char)0xff, // endCount[0] - 0, 0, // reserved - 0, 0, // startCount[0] - 0, 0, // idDelta[0] - 0, 0 // pad to a mulitple of four bytes - }; - static char nameTab[8] = { - 0, 0, // format - 0, 0, // number of name records - 0, 6, // offset to start of string storage - 0, 0 // pad to multiple of four bytes - }; - static char postTab[32] = { - 0, 1, 0, 0, // format - 0, 0, 0, 0, // italic angle - 0, 0, // underline position - 0, 0, // underline thickness - 0, 0, 0, 0, // fixed pitch - 0, 0, 0, 0, // min Type 42 memory - 0, 0, 0, 0, // max Type 42 memory - 0, 0, 0, 0, // min Type 1 memory - 0, 0, 0, 0 // max Type 1 memory - }; - static char os2Tab[86] = { - 0, 1, // version - 0, 1, // xAvgCharWidth - 0, 0, // usWeightClass - 0, 0, // usWidthClass - 0, 0, // fsType - 0, 0, // ySubscriptXSize - 0, 0, // ySubscriptYSize - 0, 0, // ySubscriptXOffset - 0, 0, // ySubscriptYOffset - 0, 0, // ySuperscriptXSize - 0, 0, // ySuperscriptYSize - 0, 0, // ySuperscriptXOffset - 0, 0, // ySuperscriptYOffset - 0, 0, // yStrikeoutSize - 0, 0, // yStrikeoutPosition - 0, 0, // sFamilyClass - 0, 0, 0, 0, 0, // panose - 0, 0, 0, 0, 0, - 0, 0, 0, 0, // ulUnicodeRange1 - 0, 0, 0, 0, // ulUnicodeRange2 - 0, 0, 0, 0, // ulUnicodeRange3 - 0, 0, 0, 0, // ulUnicodeRange4 - 0, 0, 0, 0, // achVendID - 0, 0, // fsSelection - 0, 0, // usFirstCharIndex - 0, 0, // usLastCharIndex - 0, 0, // sTypoAscender - 0, 0, // sTypoDescender - 0, 0, // sTypoLineGap - 0, 0, // usWinAscent - 0, 0, // usWinDescent - 0, 0, 0, 0, // ulCodePageRange1 - 0, 0, 0, 0 // ulCodePageRange2 - }; - GBool missingCmap, missingName, missingPost, missingOS2; - GBool unsortedLoca, badCmapLen, abbrevHMTX; - int nZeroLengthTables; - int nHMetrics, advWidth, lsb; - TrueTypeLoca *locaTable; - TrueTypeTable *newTables; - char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab; - int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; - int newHHEALen, newHMTXLen; - Guint locaChecksum, glyfChecksum, fileChecksum; - char *tableDir; - char locaBuf[4], checksumBuf[4]; - GBool ok; - Guint t; - int pos, i, j, k, n; - - if (openTypeCFF) { - return; - } - - // check for missing tables - // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver - // will embed a PCL TrueType font with the pitch field set to zero, - // which apparently causes divide-by-zero errors. As far as I can - // tell, the only important field in the OS/2 table is - // xAvgCharWidth.) - missingCmap = (cmapIdx = seekTable("cmap")) < 0; - missingName = seekTable("name") < 0; - missingPost = seekTable("post") < 0; - missingOS2 = seekTable("OS/2") < 0; - - // read the loca table, check to see if it's sorted - locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); - unsortedLoca = gFalse; - i = seekTable("loca"); - pos = tables[i].offset; - ok = gTrue; - for (i = 0; i <= nGlyphs; ++i) { - if (locaFmt) { - locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); - } else { - locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); - } - if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { - unsortedLoca = gTrue; - } - // glyph descriptions must be at least 12 bytes long (nContours, - // xMin, yMin, xMax, yMax, instructionLength - two bytes each); - // invalid glyph descriptions (even if they're never used) make - // Windows choke, so we work around that problem here (ideally, - // this would parse the glyph descriptions in the glyf table and - // remove any that were invalid, but this quick test is a decent - // start) - if (i > 0 && - locaTable[i].origOffset - locaTable[i-1].origOffset > 0 && - locaTable[i].origOffset - locaTable[i-1].origOffset < 12) { - locaTable[i-1].origOffset = locaTable[i].origOffset; - unsortedLoca = gTrue; - } - locaTable[i].idx = i; - } - - // check for zero-length tables - nZeroLengthTables = 0; - for (i = 0; i < nTables; ++i) { - if (tables[i].len == 0) { - ++nZeroLengthTables; - } - } - - // check for an incorrect cmap table length - badCmapLen = gFalse; - cmapLen = 0; // make gcc happy - if (!missingCmap) { - cmapLen = cmaps[0].offset + cmaps[0].len; - for (i = 1; i < nCmaps; ++i) { - if (cmaps[i].offset + cmaps[i].len > cmapLen) { - cmapLen = cmaps[i].offset + cmaps[i].len; - } - } - cmapLen -= tables[cmapIdx].offset; - if (cmapLen > tables[cmapIdx].len) { - badCmapLen = gTrue; - } - } - - // check for an abbreviated hmtx table (this is completely legal, - // but confuses the Microsoft PCL5 printer driver, which generates - // embedded fonts with the pitch field set to zero) - i = seekTable("hhea"); - nHMetrics = getU16BE(tables[i].offset + 34, &ok); - abbrevHMTX = nHMetrics < nGlyphs; - - // if nothing is broken, just write the TTF file as is - if (!missingCmap && !missingName && !missingPost && !missingOS2 && - !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 && - !name && !codeToGID) { - (*outputFunc)(outputStream, (char *)file, len); - goto done1; - } - - // sort the 'loca' table: some (non-compliant) fonts have - // out-of-order loca tables; in order to correctly handle the case - // where (compliant) fonts have empty entries in the middle of the - // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, - // and idx as its secondary key (ensuring that adjacent entries with - // the same pos value remain in the same order) - glyfLen = 0; // make gcc happy - if (unsortedLoca) { - qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaOffset); - for (i = 0; i < nGlyphs; ++i) { - locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; - } - locaTable[nGlyphs].len = 0; - qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaIdx); - pos = 0; - for (i = 0; i <= nGlyphs; ++i) { - locaTable[i].newOffset = pos; - pos += locaTable[i].len; - if (pos & 3) { - pos += 4 - (pos & 3); - } - } - glyfLen = pos; - } - - // compute checksums for the loca and glyf tables - locaChecksum = glyfChecksum = 0; - if (unsortedLoca) { - if (locaFmt) { - for (j = 0; j <= nGlyphs; ++j) { - locaChecksum += locaTable[j].newOffset; - } - } else { - for (j = 0; j <= nGlyphs; j += 2) { - locaChecksum += locaTable[j].newOffset << 16; - if (j + 1 <= nGlyphs) { - locaChecksum += locaTable[j+1].newOffset; - } - } - } - pos = tables[seekTable("glyf")].offset; - for (j = 0; j < nGlyphs; ++j) { - n = locaTable[j].len; - if (n > 0) { - k = locaTable[j].origOffset; - if (checkRegion(pos + k, n)) { - glyfChecksum += computeTableChecksum(file + pos + k, n); - } - } - } - } - - // construct the new name table - if (name) { - n = strlen(name); - newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; - newNameTab = (char *)gmalloc(newNameLen); - memset(newNameTab, 0, newNameLen); - newNameTab[0] = 0; // format selector - newNameTab[1] = 0; - newNameTab[2] = 0; // number of name records - newNameTab[3] = 4; - newNameTab[4] = 0; // offset to start of string storage - newNameTab[5] = 6 + 4*12; - next = 0; - for (i = 0; i < 4; ++i) { - newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft - newNameTab[6 + i*12 + 1] = 3; - newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode - newNameTab[6 + i*12 + 3] = 1; - newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English - newNameTab[6 + i*12 + 5] = 0x09; - newNameTab[6 + i*12 + 6] = 0; // name ID - newNameTab[6 + i*12 + 7] = i + 1; - newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length - newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); - newNameTab[6 + i*12 + 10] = next >> 8; // string offset - newNameTab[6 + i*12 + 11] = next & 0xff; - if (i+1 == 2) { - memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); - next += 14; - } else { - for (j = 0; j < n; ++j) { - newNameTab[6 + 4*12 + next + 2*j] = 0; - newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; - } - next += 2*n; - } - } - } else { - newNameLen = 0; - newNameTab = NULL; - } - - // construct the new cmap table - if (codeToGID) { - newCmapLen = 44 + 256 * 2; - newCmapTab = (char *)gmalloc(newCmapLen); - newCmapTab[0] = 0; // table version number = 0 - newCmapTab[1] = 0; - newCmapTab[2] = 0; // number of encoding tables = 1 - newCmapTab[3] = 1; - newCmapTab[4] = 0; // platform ID = Microsoft - newCmapTab[5] = 3; - newCmapTab[6] = 0; // encoding ID = Unicode - newCmapTab[7] = 1; - newCmapTab[8] = 0; // offset of subtable - newCmapTab[9] = 0; - newCmapTab[10] = 0; - newCmapTab[11] = 12; - newCmapTab[12] = 0; // subtable format = 4 - newCmapTab[13] = 4; - newCmapTab[14] = 0x02; // subtable length - newCmapTab[15] = 0x20; - newCmapTab[16] = 0; // subtable version = 0 - newCmapTab[17] = 0; - newCmapTab[18] = 0; // segment count * 2 - newCmapTab[19] = 4; - newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) - newCmapTab[21] = 4; - newCmapTab[22] = 0; // floor(log2(segCount)) - newCmapTab[23] = 1; - newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) - newCmapTab[25] = 0; - newCmapTab[26] = 0x00; // endCount[0] - newCmapTab[27] = (char)0xff; - newCmapTab[28] = (char)0xff; // endCount[1] - newCmapTab[29] = (char)0xff; - newCmapTab[30] = 0; // reserved - newCmapTab[31] = 0; - newCmapTab[32] = 0x00; // startCount[0] - newCmapTab[33] = 0x00; - newCmapTab[34] = (char)0xff; // startCount[1] - newCmapTab[35] = (char)0xff; - newCmapTab[36] = 0; // idDelta[0] - newCmapTab[37] = 0; - newCmapTab[38] = 0; // idDelta[1] - newCmapTab[39] = 1; - newCmapTab[40] = 0; // idRangeOffset[0] - newCmapTab[41] = 4; - newCmapTab[42] = 0; // idRangeOffset[1] - newCmapTab[43] = 0; - for (i = 0; i < 256; ++i) { - newCmapTab[44 + 2*i] = codeToGID[i] >> 8; - newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; - } - } else { - newCmapLen = 0; - newCmapTab = NULL; - } - - // generate the new hmtx table and the updated hhea table - if (abbrevHMTX) { - i = seekTable("hhea"); - pos = tables[i].offset; - newHHEALen = 36; - newHHEATab = (char *)gmalloc(newHHEALen); - for (i = 0; i < newHHEALen; ++i) { - newHHEATab[i] = getU8(pos++, &ok); - } - newHHEATab[34] = nGlyphs >> 8; - newHHEATab[35] = nGlyphs & 0xff; - i = seekTable("hmtx"); - pos = tables[i].offset; - newHMTXLen = 4 * nGlyphs; - newHMTXTab = (char *)gmalloc(newHMTXLen); - advWidth = 0; - for (i = 0; i < nHMetrics; ++i) { - advWidth = getU16BE(pos, &ok); - lsb = getU16BE(pos + 2, &ok); - pos += 4; - newHMTXTab[4*i ] = advWidth >> 8; - newHMTXTab[4*i + 1] = advWidth & 0xff; - newHMTXTab[4*i + 2] = lsb >> 8; - newHMTXTab[4*i + 3] = lsb & 0xff; - } - for (; i < nGlyphs; ++i) { - lsb = getU16BE(pos, &ok); - pos += 2; - newHMTXTab[4*i ] = advWidth >> 8; - newHMTXTab[4*i + 1] = advWidth & 0xff; - newHMTXTab[4*i + 2] = lsb >> 8; - newHMTXTab[4*i + 3] = lsb & 0xff; - } - } else { - newHHEATab = newHMTXTab = NULL; - newHHEALen = newHMTXLen = 0; // make gcc happy - } - - // construct the new table directory: - // - keep all original tables with non-zero length - // - fix the cmap table's length, if necessary - // - add missing tables - // - sort the table by tag - // - compute new table positions, including 4-byte alignment - // - (re)compute table checksums - nNewTables = nTables - nZeroLengthTables + - (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + - (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0); - newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); - j = 0; - for (i = 0; i < nTables; ++i) { - if (tables[i].len > 0) { - newTables[j] = tables[i]; - newTables[j].origOffset = tables[i].offset; - if (checkRegion(tables[i].offset, newTables[i].len)) { - newTables[j].checksum = - computeTableChecksum(file + tables[i].offset, tables[i].len); - if (tables[i].tag == headTag) { - // don't include the file checksum - newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); - } - } - if (newTables[j].tag == cmapTag && codeToGID) { - newTables[j].len = newCmapLen; - newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, - newCmapLen); - } else if (newTables[j].tag == cmapTag && badCmapLen) { - newTables[j].len = cmapLen; - } else if (newTables[j].tag == locaTag && unsortedLoca) { - newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); - newTables[j].checksum = locaChecksum; - } else if (newTables[j].tag == glyfTag && unsortedLoca) { - newTables[j].len = glyfLen; - newTables[j].checksum = glyfChecksum; - } else if (newTables[j].tag == nameTag && name) { - newTables[j].len = newNameLen; - newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, - newNameLen); - } else if (newTables[j].tag == hheaTag && abbrevHMTX) { - newTables[j].len = newHHEALen; - newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab, - newHHEALen); - } else if (newTables[j].tag == hmtxTag && abbrevHMTX) { - newTables[j].len = newHMTXLen; - newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab, - newHMTXLen); - } - ++j; - } - } - if (missingCmap) { - newTables[j].tag = cmapTag; - if (codeToGID) { - newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, - newCmapLen); - newTables[j].len = newCmapLen; - } else { - newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, - sizeof(cmapTab)); - newTables[j].len = sizeof(cmapTab); - } - ++j; - } - if (missingName) { - newTables[j].tag = nameTag; - if (name) { - newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, - newNameLen); - newTables[j].len = newNameLen; - } else { - newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, - sizeof(nameTab)); - newTables[j].len = sizeof(nameTab); - } - ++j; - } - if (missingPost) { - newTables[j].tag = postTag; - newTables[j].checksum = computeTableChecksum((Guchar *)postTab, - sizeof(postTab)); - newTables[j].len = sizeof(postTab); - ++j; - } - if (missingOS2) { - newTables[j].tag = os2Tag; - newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab, - sizeof(os2Tab)); - newTables[j].len = sizeof(os2Tab); - ++j; - } - qsort(newTables, nNewTables, sizeof(TrueTypeTable), - &cmpTrueTypeTableTag); - pos = 12 + nNewTables * 16; - for (i = 0; i < nNewTables; ++i) { - newTables[i].offset = pos; - pos += newTables[i].len; - if (pos & 3) { - pos += 4 - (pos & 3); - } - } - - // write the table directory - tableDir = (char *)gmalloc(12 + nNewTables * 16); - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables - tableDir[5] = (char)(nNewTables & 0xff); - for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ; - t = 1 << (4 + i); - tableDir[6] = (char)((t >> 8) & 0xff); // searchRange - tableDir[7] = (char)(t & 0xff); - tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector - tableDir[9] = (char)(i & 0xff); - t = nNewTables * 16 - t; - tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift - tableDir[11] = (char)(t & 0xff); - pos = 12; - for (i = 0; i < nNewTables; ++i) { - tableDir[pos ] = (char)(newTables[i].tag >> 24); - tableDir[pos+ 1] = (char)(newTables[i].tag >> 16); - tableDir[pos+ 2] = (char)(newTables[i].tag >> 8); - tableDir[pos+ 3] = (char) newTables[i].tag; - tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24); - tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16); - tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8); - tableDir[pos+ 7] = (char) newTables[i].checksum; - tableDir[pos+ 8] = (char)(newTables[i].offset >> 24); - tableDir[pos+ 9] = (char)(newTables[i].offset >> 16); - tableDir[pos+10] = (char)(newTables[i].offset >> 8); - tableDir[pos+11] = (char) newTables[i].offset; - tableDir[pos+12] = (char)(newTables[i].len >> 24); - tableDir[pos+13] = (char)(newTables[i].len >> 16); - tableDir[pos+14] = (char)(newTables[i].len >> 8); - tableDir[pos+15] = (char) newTables[i].len; - pos += 16; - } - (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); - - // compute the file checksum - fileChecksum = computeTableChecksum((Guchar *)tableDir, - 12 + nNewTables * 16); - for (i = 0; i < nNewTables; ++i) { - fileChecksum += newTables[i].checksum; - } - fileChecksum = 0xb1b0afba - fileChecksum; - - // write the tables - for (i = 0; i < nNewTables; ++i) { - if (newTables[i].tag == headTag) { - if (checkRegion(newTables[i].origOffset, newTables[i].len)) { - (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); - checksumBuf[0] = fileChecksum >> 24; - checksumBuf[1] = fileChecksum >> 16; - checksumBuf[2] = fileChecksum >> 8; - checksumBuf[3] = fileChecksum; - (*outputFunc)(outputStream, checksumBuf, 4); - (*outputFunc)(outputStream, - (char *)file + newTables[i].origOffset + 12, - newTables[i].len - 12); - } else { - for (j = 0; j < newTables[i].len; ++j) { - (*outputFunc)(outputStream, "\0", 1); - } - } - } else if (newTables[i].tag == cmapTag && codeToGID) { - (*outputFunc)(outputStream, newCmapTab, newTables[i].len); - } else if (newTables[i].tag == cmapTag && missingCmap) { - (*outputFunc)(outputStream, cmapTab, newTables[i].len); - } else if (newTables[i].tag == nameTag && name) { - (*outputFunc)(outputStream, newNameTab, newTables[i].len); - } else if (newTables[i].tag == nameTag && missingName) { - (*outputFunc)(outputStream, nameTab, newTables[i].len); - } else if (newTables[i].tag == postTag && missingPost) { - (*outputFunc)(outputStream, postTab, newTables[i].len); - } else if (newTables[i].tag == os2Tag && missingOS2) { - (*outputFunc)(outputStream, os2Tab, newTables[i].len); - } else if (newTables[i].tag == hheaTag && abbrevHMTX) { - (*outputFunc)(outputStream, newHHEATab, newTables[i].len); - } else if (newTables[i].tag == hmtxTag && abbrevHMTX) { - (*outputFunc)(outputStream, newHMTXTab, newTables[i].len); - } else if (newTables[i].tag == locaTag && unsortedLoca) { - for (j = 0; j <= nGlyphs; ++j) { - if (locaFmt) { - locaBuf[0] = (char)(locaTable[j].newOffset >> 24); - locaBuf[1] = (char)(locaTable[j].newOffset >> 16); - locaBuf[2] = (char)(locaTable[j].newOffset >> 8); - locaBuf[3] = (char) locaTable[j].newOffset; - (*outputFunc)(outputStream, locaBuf, 4); - } else { - locaBuf[0] = (char)(locaTable[j].newOffset >> 9); - locaBuf[1] = (char)(locaTable[j].newOffset >> 1); - (*outputFunc)(outputStream, locaBuf, 2); - } - } - } else if (newTables[i].tag == glyfTag && unsortedLoca) { - pos = tables[seekTable("glyf")].offset; - for (j = 0; j < nGlyphs; ++j) { - n = locaTable[j].len; - if (n > 0) { - k = locaTable[j].origOffset; - if (checkRegion(pos + k, n)) { - (*outputFunc)(outputStream, (char *)file + pos + k, n); - } else { - for (k = 0; k < n; ++k) { - (*outputFunc)(outputStream, "\0", 1); - } - } - if ((k = locaTable[j].len & 3)) { - (*outputFunc)(outputStream, "\0\0\0\0", 4 - k); - } - } - } - } else { - if (checkRegion(newTables[i].origOffset, newTables[i].len)) { - (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, - newTables[i].len); - } else { - for (j = 0; j < newTables[i].len; ++j) { - (*outputFunc)(outputStream, "\0", 1); - } - } - } - if (newTables[i].len & 3) { - (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3)); - } - } - - gfree(newHMTXTab); - gfree(newHHEATab); - gfree(newCmapTab); - gfree(newNameTab); - gfree(tableDir); - gfree(newTables); - done1: - gfree(locaTable); -} - -void FoFiTrueType::cvtEncoding(char **encoding, - FoFiOutputFunc outputFunc, - void *outputStream) { - char *name; - GString *buf; - int i; - - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - if (encoding) { - for (i = 0; i < 256; ++i) { - if (!(name = encoding[i])) { - name = ".notdef"; - } - buf = GString::format("dup {0:d} /", i); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " put\n", 5); - } - } else { - for (i = 0; i < 256; ++i) { - buf = GString::format("dup {0:d} /c{1:02x} put\n", i, i); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - } - (*outputFunc)(outputStream, "readonly def\n", 13); -} - -void FoFiTrueType::cvtCharStrings(char **encoding, - Gushort *codeToGID, - FoFiOutputFunc outputFunc, - void *outputStream) { - char *name; - GString *buf; - char buf2[16]; - int i, k; - - // always define '.notdef' - (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); - (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); - - // if there's no 'cmap' table, punt - if (nCmaps == 0) { - goto err; - } - - // map char name to glyph index: - // 1. use encoding to map name to char code - // 2. use codeToGID to map char code to glyph index - // N.B. We do this in reverse order because font subsets can have - // weird encodings that use the same character name twice, and - // the first definition is probably the one we want. - k = 0; // make gcc happy - for (i = 255; i >= 0; --i) { - if (encoding) { - name = encoding[i]; - } else { - sprintf(buf2, "c%02x", i); - name = buf2; - } - if (name && strcmp(name, ".notdef")) { - k = codeToGID[i]; - // note: Distiller (maybe Adobe's PS interpreter in general) - // doesn't like TrueType fonts that have CharStrings entries - // which point to nonexistent glyphs, hence the (k < nGlyphs) - // test - if (k > 0 && k < nGlyphs) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name, strlen(name)); - buf = GString::format(" {0:d} def\n", k); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - } - } - - err: - (*outputFunc)(outputStream, "end readonly def\n", 17); -} - -void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, - void *outputStream, GString *name, - GBool needVerticalMetrics) { - Guchar headData[54]; - TrueTypeLoca *locaTable; - Guchar *locaData; - TrueTypeTable newTables[nT42Tables]; - Guchar tableDir[12 + nT42Tables*16]; - GBool ok; - Guint checksum; - int nNewTables; - int length, pos, glyfPos, i, j, k; - Guchar vheaTab[36] = { - 0, 1, 0, 0, // table version number - 0, 0, // ascent - 0, 0, // descent - 0, 0, // reserved - 0, 0, // max advance height - 0, 0, // min top side bearing - 0, 0, // min bottom side bearing - 0, 0, // y max extent - 0, 0, // caret slope rise - 0, 1, // caret slope run - 0, 0, // caret offset - 0, 0, // reserved - 0, 0, // reserved - 0, 0, // reserved - 0, 0, // reserved - 0, 0, // metric data format - 0, 1 // number of advance heights in vmtx table - }; - Guchar *vmtxTab; - GBool needVhea, needVmtx; - int advance; - - // construct the 'head' table, zero out the font checksum - i = seekTable("head"); - pos = tables[i].offset; - if (!checkRegion(pos, 54)) { - return; - } - memcpy(headData, file + pos, 54); - headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0; - - // read the original 'loca' table, pad entries out to 4 bytes, and - // sort it into proper order -- some (non-compliant) fonts have - // out-of-order loca tables; in order to correctly handle the case - // where (compliant) fonts have empty entries in the middle of the - // table, cmpTrueTypeLocaPos uses offset as its primary sort key, - // and idx as its secondary key (ensuring that adjacent entries with - // the same pos value remain in the same order) - locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); - i = seekTable("loca"); - pos = tables[i].offset; - ok = gTrue; - for (i = 0; i <= nGlyphs; ++i) { - locaTable[i].idx = i; - if (locaFmt) { - locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); - } else { - locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); - } - } - qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaOffset); - for (i = 0; i < nGlyphs; ++i) { - locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; - } - locaTable[nGlyphs].len = 0; - qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaIdx); - pos = 0; - for (i = 0; i <= nGlyphs; ++i) { - locaTable[i].newOffset = pos; - pos += locaTable[i].len; - if (pos & 3) { - pos += 4 - (pos & 3); - } - } - - // construct the new 'loca' table - locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); - for (i = 0; i <= nGlyphs; ++i) { - pos = locaTable[i].newOffset; - if (locaFmt) { - locaData[4*i ] = (Guchar)(pos >> 24); - locaData[4*i+1] = (Guchar)(pos >> 16); - locaData[4*i+2] = (Guchar)(pos >> 8); - locaData[4*i+3] = (Guchar) pos; - } else { - locaData[2*i ] = (Guchar)(pos >> 9); - locaData[2*i+1] = (Guchar)(pos >> 1); - } - } - - // count the number of tables - nNewTables = 0; - for (i = 0; i < nT42Tables; ++i) { - if (t42Tables[i].required || - seekTable(t42Tables[i].tag) >= 0) { - ++nNewTables; - } - } - vmtxTab = NULL; // make gcc happy - advance = 0; // make gcc happy - if (needVerticalMetrics) { - needVhea = seekTable("vhea") < 0; - needVmtx = seekTable("vmtx") < 0; - if (needVhea || needVmtx) { - i = seekTable("head"); - advance = getU16BE(tables[i].offset + 18, &ok); // units per em - if (needVhea) { - ++nNewTables; - } - if (needVmtx) { - ++nNewTables; - } - } - } - - // construct the new table headers, including table checksums - // (pad each table out to a multiple of 4 bytes) - pos = 12 + nNewTables*16; - k = 0; - for (i = 0; i < nT42Tables; ++i) { - length = -1; - checksum = 0; // make gcc happy - if (i == t42HeadTable) { - length = 54; - checksum = computeTableChecksum(headData, 54); - } else if (i == t42LocaTable) { - length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - checksum = computeTableChecksum(locaData, length); - } else if (i == t42GlyfTable) { - length = 0; - checksum = 0; - glyfPos = tables[seekTable("glyf")].offset; - for (j = 0; j < nGlyphs; ++j) { - length += locaTable[j].len; - if (length & 3) { - length += 4 - (length & 3); - } - if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { - checksum += - computeTableChecksum(file + glyfPos + locaTable[j].origOffset, - locaTable[j].len); - } - } - } else { - if ((j = seekTable(t42Tables[i].tag)) >= 0) { - length = tables[j].len; - if (checkRegion(tables[j].offset, length)) { - checksum = computeTableChecksum(file + tables[j].offset, length); - } - } else if (needVerticalMetrics && i == t42VheaTable) { - vheaTab[10] = advance / 256; // max advance height - vheaTab[11] = advance % 256; - length = sizeof(vheaTab); - checksum = computeTableChecksum(vheaTab, length); - } else if (needVerticalMetrics && i == t42VmtxTable) { - length = 4 + (nGlyphs - 1) * 4; - vmtxTab = (Guchar *)gmalloc(length); - vmtxTab[0] = advance / 256; - vmtxTab[1] = advance % 256; - for (j = 2; j < length; j += 2) { - vmtxTab[j] = 0; - vmtxTab[j+1] = 0; - } - checksum = computeTableChecksum(vmtxTab, length); - } else if (t42Tables[i].required) { - //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", - //~ t42Tables[i].tag); - length = 0; - checksum = 0; - } - } - if (length >= 0) { - newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) | - ((t42Tables[i].tag[1] & 0xff) << 16) | - ((t42Tables[i].tag[2] & 0xff) << 8) | - (t42Tables[i].tag[3] & 0xff); - newTables[k].checksum = checksum; - newTables[k].offset = pos; - newTables[k].len = length; - pos += length; - if (pos & 3) { - pos += 4 - (length & 3); - } - ++k; - } - } - - // construct the table directory - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = 0; // numTables - tableDir[5] = nNewTables; - tableDir[6] = 0; // searchRange - tableDir[7] = (Guchar)128; - tableDir[8] = 0; // entrySelector - tableDir[9] = 3; - tableDir[10] = 0; // rangeShift - tableDir[11] = (Guchar)(16 * nNewTables - 128); - pos = 12; - for (i = 0; i < nNewTables; ++i) { - tableDir[pos ] = (Guchar)(newTables[i].tag >> 24); - tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16); - tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8); - tableDir[pos+ 3] = (Guchar) newTables[i].tag; - tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24); - tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16); - tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8); - tableDir[pos+ 7] = (Guchar) newTables[i].checksum; - tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24); - tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16); - tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8); - tableDir[pos+11] = (Guchar) newTables[i].offset; - tableDir[pos+12] = (Guchar)(newTables[i].len >> 24); - tableDir[pos+13] = (Guchar)(newTables[i].len >> 16); - tableDir[pos+14] = (Guchar)(newTables[i].len >> 8); - tableDir[pos+15] = (Guchar) newTables[i].len; - pos += 16; - } - - // compute the font checksum and store it in the head table - checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); - for (i = 0; i < nNewTables; ++i) { - checksum += newTables[i].checksum; - } - checksum = 0xb1b0afba - checksum; // because the TrueType spec says so - headData[ 8] = (Guchar)(checksum >> 24); - headData[ 9] = (Guchar)(checksum >> 16); - headData[10] = (Guchar)(checksum >> 8); - headData[11] = (Guchar) checksum; - - // start the sfnts array - if (name) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - (*outputFunc)(outputStream, " [\n", 3); - } else { - (*outputFunc)(outputStream, "/sfnts [\n", 9); - } - - // write the table directory - dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); - - // write the tables - for (i = 0; i < nNewTables; ++i) { - if (i == t42HeadTable) { - dumpString(headData, 54, outputFunc, outputStream); - } else if (i == t42LocaTable) { - length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - dumpString(locaData, length, outputFunc, outputStream); - } else if (i == t42GlyfTable) { - glyfPos = tables[seekTable("glyf")].offset; - for (j = 0; j < nGlyphs; ++j) { - if (locaTable[j].len > 0 && - checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { - dumpString(file + glyfPos + locaTable[j].origOffset, - locaTable[j].len, outputFunc, outputStream); - } - } - } else { - // length == 0 means the table is missing and the error was - // already reported during the construction of the table - // headers - if ((length = newTables[i].len) > 0) { - if ((j = seekTable(t42Tables[i].tag)) >= 0 && - checkRegion(tables[j].offset, tables[j].len)) { - dumpString(file + tables[j].offset, tables[j].len, - outputFunc, outputStream); - } else if (needVerticalMetrics && i == t42VheaTable) { - dumpString(vheaTab, length, outputFunc, outputStream); - } else if (needVerticalMetrics && i == t42VmtxTable) { - dumpString(vmtxTab, length, outputFunc, outputStream); - gfree(vmtxTab); - } - } - } - } - - // end the sfnts array - (*outputFunc)(outputStream, "] def\n", 6); - - gfree(locaData); - gfree(locaTable); -} - -void FoFiTrueType::dumpString(Guchar *s, int length, - FoFiOutputFunc outputFunc, - void *outputStream) { - GString *buf; - int pad, i, j; - - (*outputFunc)(outputStream, "<", 1); - for (i = 0; i < length; i += 32) { - for (j = 0; j < 32 && i+j < length; ++j) { - buf = GString::format("{0:02x}", s[i+j] & 0xff); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (i % (65536 - 32) == 65536 - 64) { - (*outputFunc)(outputStream, ">\n<", 3); - } else if (i+32 < length) { - (*outputFunc)(outputStream, "\n", 1); - } - } - if (length & 3) { - pad = 4 - (length & 3); - for (i = 0; i < pad; ++i) { - (*outputFunc)(outputStream, "00", 2); - } - } - // add an extra zero byte because the Adobe Type 42 spec says so - (*outputFunc)(outputStream, "00>\n", 4); -} - -Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { - Guint checksum, word; - int i; - - checksum = 0; - for (i = 0; i+3 < length; i += 4) { - word = ((data[i ] & 0xff) << 24) + - ((data[i+1] & 0xff) << 16) + - ((data[i+2] & 0xff) << 8) + - (data[i+3] & 0xff); - checksum += word; - } - if (length & 3) { - word = 0; - i = length & ~3; - switch (length & 3) { - case 3: - word |= (data[i+2] & 0xff) << 8; - case 2: - word |= (data[i+1] & 0xff) << 16; - case 1: - word |= (data[i ] & 0xff) << 24; - break; - } - checksum += word; - } - return checksum; -} - -void FoFiTrueType::parse() { - Guint topTag; - int pos, ver, i, j; - - parsedOk = gTrue; - - // look for a collection (TTC) - topTag = getU32BE(0, &parsedOk); - if (!parsedOk) { - return; - } - if (topTag == ttcfTag) { - /* TTC font */ - int dircount; - - dircount = getU32BE(8, &parsedOk); - if (!parsedOk) - return; - if (! dircount) { - parsedOk = gFalse; - return; - } - - if (faceIndex >= dircount) - faceIndex = 0; - pos = getU32BE(12 + faceIndex * 4, &parsedOk); - if (! parsedOk) - return; - } else { - pos = 0; - } - - // check the sfnt version - ver = getU32BE(pos, &parsedOk); - if (!parsedOk) { - return; - } - openTypeCFF = ver == 0x4f54544f; // 'OTTO' - - // read the table directory - nTables = getU16BE(pos + 4, &parsedOk); - if (!parsedOk) { - return; - } - tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); - pos += 12; - for (i = 0; i < nTables; ++i) { - tables[i].tag = getU32BE(pos, &parsedOk); - tables[i].checksum = getU32BE(pos + 4, &parsedOk); - tables[i].offset = (int)getU32BE(pos + 8, &parsedOk); - tables[i].len = (int)getU32BE(pos + 12, &parsedOk); - if (tables[i].offset + tables[i].len < tables[i].offset || - tables[i].offset + tables[i].len > len) { - parsedOk = gFalse; - } - pos += 16; - } - if (!parsedOk) { - return; - } - - // check for tables that are required by both the TrueType spec and - // the Type 42 spec - if (seekTable("head") < 0 || - seekTable("hhea") < 0 || - seekTable("maxp") < 0 || - seekTable("hmtx") < 0 || - (!openTypeCFF && seekTable("loca") < 0) || - (!openTypeCFF && seekTable("glyf") < 0) || - (openTypeCFF && seekTable("CFF ") < 0)) { - parsedOk = gFalse; - return; - } - - // read the cmaps - if ((i = seekTable("cmap")) >= 0) { - pos = tables[i].offset + 2; - nCmaps = getU16BE(pos, &parsedOk); - pos += 2; - if (!parsedOk) { - return; - } - cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); - for (j = 0; j < nCmaps; ++j) { - cmaps[j].platform = getU16BE(pos, &parsedOk); - cmaps[j].encoding = getU16BE(pos + 2, &parsedOk); - cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk); - pos += 8; - cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk); - cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk); - } - if (!parsedOk) { - return; - } - } else { - nCmaps = 0; - } - - // get the number of glyphs from the maxp table - i = seekTable("maxp"); - nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk); - if (!parsedOk) { - return; - } - - // get the bbox and loca table format from the head table - i = seekTable("head"); - bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk); - bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk); - bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk); - bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk); - locaFmt = getS16BE(tables[i].offset + 50, &parsedOk); - if (!parsedOk) { - return; - } - - // make sure the loca table is sane (correct length and entries are - // in bounds) - if (!openTypeCFF) { - i = seekTable("loca"); - if (tables[i].len < 0) { - parsedOk = gFalse; - return; - } - if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { - nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1; - } - for (j = 0; j <= nGlyphs; ++j) { - if (locaFmt) { - pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk); - } else { - pos = getU16BE(tables[i].offset + j*2, &parsedOk); - } - if (pos < 0 || pos > len) { - parsedOk = gFalse; - } - } - if (!parsedOk) { - return; - } - } - - // read the post table - readPostTable(); -} - -void FoFiTrueType::readPostTable() { - GString *name; - int tablePos, postFmt, stringIdx, stringPos; - GBool ok; - int i, j, n, m; - - ok = gTrue; - if ((i = seekTable("post")) < 0) { - return; - } - tablePos = tables[i].offset; - postFmt = getU32BE(tablePos, &ok); - if (!ok) { - goto err; - } - if (postFmt == 0x00010000) { - nameToGID = new GHash(gTrue); - for (i = 0; i < 258; ++i) { - nameToGID->add(new GString(macGlyphNames[i]), i); - } - } else if (postFmt == 0x00020000) { - nameToGID = new GHash(gTrue); - n = getU16BE(tablePos + 32, &ok); - if (!ok) { - goto err; - } - if (n > nGlyphs) { - n = nGlyphs; - } - stringIdx = 0; - stringPos = tablePos + 34 + 2*n; - for (i = 0; i < n; ++i) { - j = getU16BE(tablePos + 34 + 2*i, &ok); - if (j < 258) { - nameToGID->removeInt(macGlyphNames[j]); - nameToGID->add(new GString(macGlyphNames[j]), i); - } else { - j -= 258; - if (j != stringIdx) { - for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; - stringIdx < j; - ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; - if (!ok) { - goto err; - } - } - m = getU8(stringPos, &ok); - if (!ok || !checkRegion(stringPos + 1, m)) { - goto err; - } - name = new GString((char *)&file[stringPos + 1], m); - nameToGID->removeInt(name); - nameToGID->add(name, i); - ++stringIdx; - stringPos += 1 + m; - } - } - } else if (postFmt == 0x00028000) { - nameToGID = new GHash(gTrue); - for (i = 0; i < nGlyphs; ++i) { - j = getU8(tablePos + 32 + i, &ok); - if (!ok) { - goto err; - } - if (j < 258) { - nameToGID->removeInt(macGlyphNames[j]); - nameToGID->add(new GString(macGlyphNames[j]), i); - } - } - } - - return; - - err: - if (nameToGID) { - delete nameToGID; - nameToGID = NULL; - } -} - -int FoFiTrueType::seekTable(char *tag) { - Guint tagI; - int i; - - tagI = ((tag[0] & 0xff) << 24) | - ((tag[1] & 0xff) << 16) | - ((tag[2] & 0xff) << 8) | - (tag[3] & 0xff); - for (i = 0; i < nTables; ++i) { - if (tables[i].tag == tagI) { - return i; - } - } - return -1; -} diff --git a/kpdf/xpdf/fofi/FoFiTrueType.cpp b/kpdf/xpdf/fofi/FoFiTrueType.cpp new file mode 100644 index 00000000..18253335 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiTrueType.cpp @@ -0,0 +1,2040 @@ +//======================================================================== +// +// FoFiTrueType.cpp +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gtypes.h" +#include "gmem.h" +#include "GString.h" +#include "GHash.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" + +// +// Terminology +// ----------- +// +// character code = number used as an element of a text string +// +// character name = glyph name = name for a particular glyph within a +// font +// +// glyph index = GID = position (within some internal table in the font) +// where the instructions to draw a particular glyph are +// stored +// +// Type 1 fonts +// ------------ +// +// Type 1 fonts contain: +// +// Encoding: array of glyph names, maps char codes to glyph names +// +// Encoding[charCode] = charName +// +// CharStrings: dictionary of instructions, keyed by character names, +// maps character name to glyph data +// +// CharStrings[charName] = glyphData +// +// TrueType fonts +// -------------- +// +// TrueType fonts contain: +// +// 'cmap' table: mapping from character code to glyph index; there may +// be multiple cmaps in a TrueType font +// +// cmap[charCode] = gid +// +// 'post' table: mapping from glyph index to glyph name +// +// post[gid] = glyphName +// +// Type 42 fonts +// ------------- +// +// Type 42 fonts contain: +// +// Encoding: array of glyph names, maps char codes to glyph names +// +// Encoding[charCode] = charName +// +// CharStrings: dictionary of glyph indexes, keyed by character names, +// maps character name to glyph index +// +// CharStrings[charName] = gid +// + +//------------------------------------------------------------------------ + +#define ttcfTag 0x74746366 + +//------------------------------------------------------------------------ + +struct TrueTypeTable { + Guint tag; + Guint checksum; + int offset; + int origOffset; + int len; +}; + +struct TrueTypeCmap { + int platform; + int encoding; + int offset; + int len; + int fmt; +}; + +struct TrueTypeLoca { + int idx; + int origOffset; + int newOffset; + int len; +}; + +#define cmapTag 0x636d6170 +#define glyfTag 0x676c7966 +#define headTag 0x68656164 +#define hheaTag 0x68686561 +#define hmtxTag 0x686d7478 +#define locaTag 0x6c6f6361 +#define nameTag 0x6e616d65 +#define os2Tag 0x4f532f32 +#define postTag 0x706f7374 + +static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) { + TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; + TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; + + if (loca1->origOffset == loca2->origOffset) { + return loca1->idx - loca2->idx; + } + return loca1->origOffset - loca2->origOffset; +} + +static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { + TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; + TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; + + return loca1->idx - loca2->idx; +} + +static int cmpTrueTypeTableTag(const void *p1, const void *p2) { + TrueTypeTable *tab1 = (TrueTypeTable *)p1; + TrueTypeTable *tab2 = (TrueTypeTable *)p2; + + return (int)tab1->tag - (int)tab2->tag; +} + +//------------------------------------------------------------------------ + +struct T42Table { + char *tag; // 4-byte tag + GBool required; // required by the TrueType spec? +}; + +// TrueType tables to be embedded in Type 42 fonts. +// NB: the table names must be in alphabetical order here. +#define nT42Tables 11 +static T42Table t42Tables[nT42Tables] = { + { "cvt ", gTrue }, + { "fpgm", gTrue }, + { "glyf", gTrue }, + { "head", gTrue }, + { "hhea", gTrue }, + { "hmtx", gTrue }, + { "loca", gTrue }, + { "maxp", gTrue }, + { "prep", gTrue }, + { "vhea", gFalse }, + { "vmtx", gFalse } +}; +#define t42HeadTable 3 +#define t42LocaTable 6 +#define t42GlyfTable 2 +#define t42VheaTable 9 +#define t42VmtxTable 10 + +//------------------------------------------------------------------------ + +// Glyph names in some arbitrary standard order that Apple uses for +// their TrueType fonts. +static char *macGlyphNames[258] = { + ".notdef", "null", "CR", "space", + "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quotesingle", "parenleft", + "parenright", "asterisk", "plus", "comma", + "hyphen", "period", "slash", "zero", + "one", "two", "three", "four", + "five", "six", "seven", "eight", + "nine", "colon", "semicolon", "less", + "equal", "greater", "question", "at", + "A", "B", "C", "D", + "E", "F", "G", "H", + "I", "J", "K", "L", + "M", "N", "O", "P", + "Q", "R", "S", "T", + "U", "V", "W", "X", + "Y", "Z", "bracketleft", "backslash", + "bracketright", "asciicircum", "underscore", "grave", + "a", "b", "c", "d", + "e", "f", "g", "h", + "i", "j", "k", "l", + "m", "n", "o", "p", + "q", "r", "s", "t", + "u", "v", "w", "x", + "y", "z", "braceleft", "bar", + "braceright", "asciitilde", "Adieresis", "Aring", + "Ccedilla", "Eacute", "Ntilde", "Odieresis", + "Udieresis", "aacute", "agrave", "acircumflex", + "adieresis", "atilde", "aring", "ccedilla", + "eacute", "egrave", "ecircumflex", "edieresis", + "iacute", "igrave", "icircumflex", "idieresis", + "ntilde", "oacute", "ograve", "ocircumflex", + "odieresis", "otilde", "uacute", "ugrave", + "ucircumflex", "udieresis", "dagger", "degree", + "cent", "sterling", "section", "bullet", + "paragraph", "germandbls", "registered", "copyright", + "trademark", "acute", "dieresis", "notequal", + "AE", "Oslash", "infinity", "plusminus", + "lessequal", "greaterequal", "yen", "mu1", + "partialdiff", "summation", "product", "pi", + "integral", "ordfeminine", "ordmasculine", "Ohm", + "ae", "oslash", "questiondown", "exclamdown", + "logicalnot", "radical", "florin", "approxequal", + "increment", "guillemotleft", "guillemotright", "ellipsis", + "nbspace", "Agrave", "Atilde", "Otilde", + "OE", "oe", "endash", "emdash", + "quotedblleft", "quotedblright", "quoteleft", "quoteright", + "divide", "lozenge", "ydieresis", "Ydieresis", + "fraction", "currency", "guilsinglleft", "guilsinglright", + "fi", "fl", "daggerdbl", "periodcentered", + "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + "Ecircumflex", "Aacute", "Edieresis", "Egrave", + "Iacute", "Icircumflex", "Idieresis", "Igrave", + "Oacute", "Ocircumflex", "applelogo", "Ograve", + "Uacute", "Ucircumflex", "Ugrave", "dotlessi", + "circumflex", "tilde", "overscore", "breve", + "dotaccent", "ring", "cedilla", "hungarumlaut", + "ogonek", "caron", "Lslash", "lslash", + "Scaron", "scaron", "Zcaron", "zcaron", + "brokenbar", "Eth", "eth", "Yacute", + "yacute", "Thorn", "thorn", "minus", + "multiply", "onesuperior", "twosuperior", "threesuperior", + "onehalf", "onequarter", "threequarters", "franc", + "Gbreve", "gbreve", "Idot", "Scedilla", + "scedilla", "Cacute", "cacute", "Ccaron", + "ccaron", "dmacron" +}; + +//------------------------------------------------------------------------ +// FoFiTrueType +//------------------------------------------------------------------------ + +FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) { + FoFiTrueType *ff; + + ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) { + FoFiTrueType *ff; + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + tables = NULL; + nTables = 0; + cmaps = NULL; + nCmaps = 0; + nameToGID = NULL; + parsedOk = gFalse; + faceIndex = faceIndexA; + + parse(); +} + +FoFiTrueType::~FoFiTrueType() { + gfree(tables); + gfree(cmaps); + if (nameToGID) { + delete nameToGID; + } +} + +int FoFiTrueType::getNumCmaps() { + return nCmaps; +} + +int FoFiTrueType::getCmapPlatform(int i) { + return cmaps[i].platform; +} + +int FoFiTrueType::getCmapEncoding(int i) { + return cmaps[i].encoding; +} + +int FoFiTrueType::findCmap(int platform, int encoding) { + int i; + + for (i = 0; i < nCmaps; ++i) { + if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) { + return i; + } + } + return -1; +} + +Gushort FoFiTrueType::mapCodeToGID(int i, int c) { + Gushort gid; + int segCnt, segEnd, segStart, segDelta, segOffset; + int cmapFirst, cmapLen; + int pos, a, b, m; + GBool ok; + + if (i < 0 || i >= nCmaps) { + return 0; + } + ok = gTrue; + pos = cmaps[i].offset; + switch (cmaps[i].fmt) { + case 0: + if (c < 0 || c >= cmaps[i].len - 6) { + return 0; + } + gid = getU8(cmaps[i].offset + 6 + c, &ok); + break; + case 4: + segCnt = getU16BE(pos + 6, &ok) / 2; + a = -1; + b = segCnt - 1; + segEnd = getU16BE(pos + 14 + 2*b, &ok); + if (c > segEnd) { + // malformed font -- the TrueType spec requires the last segEnd + // to be 0xffff + return 0; + } + // invariant: seg[a].end < code <= seg[b].end + while (b - a > 1 && ok) { + m = (a + b) / 2; + segEnd = getU16BE(pos + 14 + 2*m, &ok); + if (segEnd < c) { + a = m; + } else { + b = m; + } + } + segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok); + segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok); + segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok); + if (c < segStart) { + return 0; + } + if (segOffset == 0) { + gid = (c + segDelta) & 0xffff; + } else { + gid = getU16BE(pos + 16 + 6*segCnt + 2*b + + segOffset + 2 * (c - segStart), &ok); + if (gid != 0) { + gid = (gid + segDelta) & 0xffff; + } + } + break; + case 6: + cmapFirst = getU16BE(pos + 6, &ok); + cmapLen = getU16BE(pos + 8, &ok); + if (c < cmapFirst || c >= cmapFirst + cmapLen) { + return 0; + } + gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok); + break; + default: + return 0; + } + if (!ok) { + return 0; + } + return gid; +} + +int FoFiTrueType::mapNameToGID(char *name) { + if (!nameToGID) { + return 0; + } + return nameToGID->lookupInt(name); +} + +Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) { + FoFiType1C *ff; + Gushort *map; + int i; + + *nCIDs = 0; + if (!openTypeCFF) { + return NULL; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return NULL; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return NULL; + } + map = ff->getCIDToGIDMap(nCIDs); + delete ff; + return map; +} + +int FoFiTrueType::getEmbeddingRights() { + int i, fsType; + GBool ok; + + if ((i = seekTable("OS/2")) < 0) { + return 4; + } + ok = gTrue; + fsType = getU16BE(tables[i].offset + 8, &ok); + if (!ok) { + return 4; + } + if (fsType & 0x0008) { + return 2; + } + if (fsType & 0x0004) { + return 1; + } + if (fsType & 0x0002) { + return 0; + } + return 3; +} + +void FoFiTrueType::convertToType42(char *psName, char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + GBool ok; + + if (openTypeCFF) { + return; + } + + // write the header + ok = gTrue; + buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", + (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // begin the font dictionary + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + + // write the guts of the dictionary + cvtEncoding(encoding, outputFunc, outputStream); + cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); + cvtSfnts(outputFunc, outputStream, NULL, gFalse); + + // end the dictionary and define the font + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::convertToType1(char *psName, char **newEncoding, + GBool ascii, FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream); + delete ff; +} + +void FoFiTrueType::convertToCIDType2(char *psName, + Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + Gushort cid; + GBool ok; + int i, j, k; + + if (openTypeCFF) { + return; + } + + // write the header + ok = gTrue; + buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", + (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // begin the font dictionary + (*outputFunc)(outputStream, "20 dict begin\n", 14); + (*outputFunc)(outputStream, "/CIDFontName /", 14); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); + (*outputFunc)(outputStream, " end def\n", 10); + (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); + if (cidMap) { + buf = GString::format("/CIDCount {0:d} def\n", nCIDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (nCIDs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [", 9); + for (i = 0; i < nCIDs; i += 32768 - 16) { + (*outputFunc)(outputStream, "<\n", 2); + for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { + (*outputFunc)(outputStream, " ", 2); + for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { + cid = cidMap[i+j+k]; + buf = GString::format("{0:02x}{1:02x}", + (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, " >", 3); + } + (*outputFunc)(outputStream, "\n", 1); + (*outputFunc)(outputStream, "] def\n", 6); + } else { + (*outputFunc)(outputStream, "/CIDMap <\n", 10); + for (i = 0; i < nCIDs; i += 16) { + (*outputFunc)(outputStream, " ", 2); + for (j = 0; j < 16 && i+j < nCIDs; ++j) { + cid = cidMap[i+j]; + buf = GString::format("{0:02x}{1:02x}", + (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, "> def\n", 6); + } + } else { + // direct mapping - just fill the string(s) with s[i]=i + buf = GString::format("/CIDCount {0:d} def\n", nGlyphs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (nGlyphs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [\n", 10); + for (i = 0; i < nGlyphs; i += 32767) { + j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; + buf = GString::format(" {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 2 copy dup 2 mul exch {0:d} add -8 bitshift put\n", + i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 1 index exch dup 2 mul 1 add exch {0:d} add" + " 255 and put\n", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, " } for\n", 8); + } + (*outputFunc)(outputStream, "] def\n", 6); + } else { + buf = GString::format("/CIDMap {0:d} string\n", 2 * nGlyphs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format(" 0 1 {0:d} {{\n", nGlyphs - 1); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, + " 2 copy dup 2 mul exch -8 bitshift put\n", 42); + (*outputFunc)(outputStream, + " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); + (*outputFunc)(outputStream, " } for\n", 8); + (*outputFunc)(outputStream, "def\n", 4); + } + } + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); + (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); + (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); + (*outputFunc)(outputStream, " end readonly def\n", 19); + + // write the guts of the dictionary + cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics); + + // end the dictionary and define the font + (*outputFunc)(outputStream, + "CIDFontName currentdict end /CIDFont defineresource pop\n", + 56); +} + +void FoFiTrueType::convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToCIDType0(psName, outputFunc, outputStream); + delete ff; +} + +void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + GString *sfntsName; + int n, i, j; + + if (openTypeCFF) { + return; + } + + // write the Type 42 sfnts array + sfntsName = (new GString(psName))->append("_sfnts"); + cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics); + delete sfntsName; + + // write the descendant Type 42 fonts + n = cidMap ? nCIDs : nGlyphs; + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + buf = GString::format("_{0:02x} def\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/sfnts ", 7); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, "_sfnts def\n", 11); + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < n; ++j) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + for (j = 0; j < 256 && i+j < n; ++j) { + buf = GString::format("/c{0:02x} {1:d} def\n", + j, cidMap ? cidMap[i+j] : i+j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, + "FontName currentdict end definefont pop\n", 40); + } + + // write the Type 0 parent font + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < n; i += 256) { + buf = GString::format("{0:d}\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, strlen(psName)); + buf = GString::format("_{0:02x} findfont\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::convertToType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToType0(psName, outputFunc, outputStream); + delete ff; +} + +void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, + void *outputStream, char *name, + Gushort *codeToGID) { + // this substitute cmap table maps char codes 0000-ffff directly to + // glyphs 0000-ffff + static char cmapTab[36] = { + 0, 0, // table version number + 0, 1, // number of encoding tables + 0, 1, // platform ID + 0, 0, // encoding ID + 0, 0, 0, 12, // offset of subtable + 0, 4, // subtable format + 0, 24, // subtable length + 0, 0, // subtable version + 0, 2, // segment count * 2 + 0, 2, // 2 * 2 ^ floor(log2(segCount)) + 0, 0, // floor(log2(segCount)) + 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) + (char)0xff, (char)0xff, // endCount[0] + 0, 0, // reserved + 0, 0, // startCount[0] + 0, 0, // idDelta[0] + 0, 0 // pad to a mulitple of four bytes + }; + static char nameTab[8] = { + 0, 0, // format + 0, 0, // number of name records + 0, 6, // offset to start of string storage + 0, 0 // pad to multiple of four bytes + }; + static char postTab[32] = { + 0, 1, 0, 0, // format + 0, 0, 0, 0, // italic angle + 0, 0, // underline position + 0, 0, // underline thickness + 0, 0, 0, 0, // fixed pitch + 0, 0, 0, 0, // min Type 42 memory + 0, 0, 0, 0, // max Type 42 memory + 0, 0, 0, 0, // min Type 1 memory + 0, 0, 0, 0 // max Type 1 memory + }; + static char os2Tab[86] = { + 0, 1, // version + 0, 1, // xAvgCharWidth + 0, 0, // usWeightClass + 0, 0, // usWidthClass + 0, 0, // fsType + 0, 0, // ySubscriptXSize + 0, 0, // ySubscriptYSize + 0, 0, // ySubscriptXOffset + 0, 0, // ySubscriptYOffset + 0, 0, // ySuperscriptXSize + 0, 0, // ySuperscriptYSize + 0, 0, // ySuperscriptXOffset + 0, 0, // ySuperscriptYOffset + 0, 0, // yStrikeoutSize + 0, 0, // yStrikeoutPosition + 0, 0, // sFamilyClass + 0, 0, 0, 0, 0, // panose + 0, 0, 0, 0, 0, + 0, 0, 0, 0, // ulUnicodeRange1 + 0, 0, 0, 0, // ulUnicodeRange2 + 0, 0, 0, 0, // ulUnicodeRange3 + 0, 0, 0, 0, // ulUnicodeRange4 + 0, 0, 0, 0, // achVendID + 0, 0, // fsSelection + 0, 0, // usFirstCharIndex + 0, 0, // usLastCharIndex + 0, 0, // sTypoAscender + 0, 0, // sTypoDescender + 0, 0, // sTypoLineGap + 0, 0, // usWinAscent + 0, 0, // usWinDescent + 0, 0, 0, 0, // ulCodePageRange1 + 0, 0, 0, 0 // ulCodePageRange2 + }; + GBool missingCmap, missingName, missingPost, missingOS2; + GBool unsortedLoca, badCmapLen, abbrevHMTX; + int nZeroLengthTables; + int nHMetrics, advWidth, lsb; + TrueTypeLoca *locaTable; + TrueTypeTable *newTables; + char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab; + int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; + int newHHEALen, newHMTXLen; + Guint locaChecksum, glyfChecksum, fileChecksum; + char *tableDir; + char locaBuf[4], checksumBuf[4]; + GBool ok; + Guint t; + int pos, i, j, k, n; + + if (openTypeCFF) { + return; + } + + // check for missing tables + // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver + // will embed a PCL TrueType font with the pitch field set to zero, + // which apparently causes divide-by-zero errors. As far as I can + // tell, the only important field in the OS/2 table is + // xAvgCharWidth.) + missingCmap = (cmapIdx = seekTable("cmap")) < 0; + missingName = seekTable("name") < 0; + missingPost = seekTable("post") < 0; + missingOS2 = seekTable("OS/2") < 0; + + // read the loca table, check to see if it's sorted + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); + unsortedLoca = gFalse; + i = seekTable("loca"); + pos = tables[i].offset; + ok = gTrue; + for (i = 0; i <= nGlyphs; ++i) { + if (locaFmt) { + locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); + } else { + locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); + } + if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { + unsortedLoca = gTrue; + } + // glyph descriptions must be at least 12 bytes long (nContours, + // xMin, yMin, xMax, yMax, instructionLength - two bytes each); + // invalid glyph descriptions (even if they're never used) make + // Windows choke, so we work around that problem here (ideally, + // this would parse the glyph descriptions in the glyf table and + // remove any that were invalid, but this quick test is a decent + // start) + if (i > 0 && + locaTable[i].origOffset - locaTable[i-1].origOffset > 0 && + locaTable[i].origOffset - locaTable[i-1].origOffset < 12) { + locaTable[i-1].origOffset = locaTable[i].origOffset; + unsortedLoca = gTrue; + } + locaTable[i].idx = i; + } + + // check for zero-length tables + nZeroLengthTables = 0; + for (i = 0; i < nTables; ++i) { + if (tables[i].len == 0) { + ++nZeroLengthTables; + } + } + + // check for an incorrect cmap table length + badCmapLen = gFalse; + cmapLen = 0; // make gcc happy + if (!missingCmap) { + cmapLen = cmaps[0].offset + cmaps[0].len; + for (i = 1; i < nCmaps; ++i) { + if (cmaps[i].offset + cmaps[i].len > cmapLen) { + cmapLen = cmaps[i].offset + cmaps[i].len; + } + } + cmapLen -= tables[cmapIdx].offset; + if (cmapLen > tables[cmapIdx].len) { + badCmapLen = gTrue; + } + } + + // check for an abbreviated hmtx table (this is completely legal, + // but confuses the Microsoft PCL5 printer driver, which generates + // embedded fonts with the pitch field set to zero) + i = seekTable("hhea"); + nHMetrics = getU16BE(tables[i].offset + 34, &ok); + abbrevHMTX = nHMetrics < nGlyphs; + + // if nothing is broken, just write the TTF file as is + if (!missingCmap && !missingName && !missingPost && !missingOS2 && + !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 && + !name && !codeToGID) { + (*outputFunc)(outputStream, (char *)file, len); + goto done1; + } + + // sort the 'loca' table: some (non-compliant) fonts have + // out-of-order loca tables; in order to correctly handle the case + // where (compliant) fonts have empty entries in the middle of the + // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, + // and idx as its secondary key (ensuring that adjacent entries with + // the same pos value remain in the same order) + glyfLen = 0; // make gcc happy + if (unsortedLoca) { + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaOffset); + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; + } + locaTable[nGlyphs].len = 0; + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].newOffset = pos; + pos += locaTable[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + glyfLen = pos; + } + + // compute checksums for the loca and glyf tables + locaChecksum = glyfChecksum = 0; + if (unsortedLoca) { + if (locaFmt) { + for (j = 0; j <= nGlyphs; ++j) { + locaChecksum += locaTable[j].newOffset; + } + } else { + for (j = 0; j <= nGlyphs; j += 2) { + locaChecksum += locaTable[j].newOffset << 16; + if (j + 1 <= nGlyphs) { + locaChecksum += locaTable[j+1].newOffset; + } + } + } + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + glyfChecksum += computeTableChecksum(file + pos + k, n); + } + } + } + } + + // construct the new name table + if (name) { + n = strlen(name); + newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; + newNameTab = (char *)gmalloc(newNameLen); + memset(newNameTab, 0, newNameLen); + newNameTab[0] = 0; // format selector + newNameTab[1] = 0; + newNameTab[2] = 0; // number of name records + newNameTab[3] = 4; + newNameTab[4] = 0; // offset to start of string storage + newNameTab[5] = 6 + 4*12; + next = 0; + for (i = 0; i < 4; ++i) { + newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft + newNameTab[6 + i*12 + 1] = 3; + newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode + newNameTab[6 + i*12 + 3] = 1; + newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English + newNameTab[6 + i*12 + 5] = 0x09; + newNameTab[6 + i*12 + 6] = 0; // name ID + newNameTab[6 + i*12 + 7] = i + 1; + newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length + newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); + newNameTab[6 + i*12 + 10] = next >> 8; // string offset + newNameTab[6 + i*12 + 11] = next & 0xff; + if (i+1 == 2) { + memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); + next += 14; + } else { + for (j = 0; j < n; ++j) { + newNameTab[6 + 4*12 + next + 2*j] = 0; + newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; + } + next += 2*n; + } + } + } else { + newNameLen = 0; + newNameTab = NULL; + } + + // construct the new cmap table + if (codeToGID) { + newCmapLen = 44 + 256 * 2; + newCmapTab = (char *)gmalloc(newCmapLen); + newCmapTab[0] = 0; // table version number = 0 + newCmapTab[1] = 0; + newCmapTab[2] = 0; // number of encoding tables = 1 + newCmapTab[3] = 1; + newCmapTab[4] = 0; // platform ID = Microsoft + newCmapTab[5] = 3; + newCmapTab[6] = 0; // encoding ID = Unicode + newCmapTab[7] = 1; + newCmapTab[8] = 0; // offset of subtable + newCmapTab[9] = 0; + newCmapTab[10] = 0; + newCmapTab[11] = 12; + newCmapTab[12] = 0; // subtable format = 4 + newCmapTab[13] = 4; + newCmapTab[14] = 0x02; // subtable length + newCmapTab[15] = 0x20; + newCmapTab[16] = 0; // subtable version = 0 + newCmapTab[17] = 0; + newCmapTab[18] = 0; // segment count * 2 + newCmapTab[19] = 4; + newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) + newCmapTab[21] = 4; + newCmapTab[22] = 0; // floor(log2(segCount)) + newCmapTab[23] = 1; + newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) + newCmapTab[25] = 0; + newCmapTab[26] = 0x00; // endCount[0] + newCmapTab[27] = (char)0xff; + newCmapTab[28] = (char)0xff; // endCount[1] + newCmapTab[29] = (char)0xff; + newCmapTab[30] = 0; // reserved + newCmapTab[31] = 0; + newCmapTab[32] = 0x00; // startCount[0] + newCmapTab[33] = 0x00; + newCmapTab[34] = (char)0xff; // startCount[1] + newCmapTab[35] = (char)0xff; + newCmapTab[36] = 0; // idDelta[0] + newCmapTab[37] = 0; + newCmapTab[38] = 0; // idDelta[1] + newCmapTab[39] = 1; + newCmapTab[40] = 0; // idRangeOffset[0] + newCmapTab[41] = 4; + newCmapTab[42] = 0; // idRangeOffset[1] + newCmapTab[43] = 0; + for (i = 0; i < 256; ++i) { + newCmapTab[44 + 2*i] = codeToGID[i] >> 8; + newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; + } + } else { + newCmapLen = 0; + newCmapTab = NULL; + } + + // generate the new hmtx table and the updated hhea table + if (abbrevHMTX) { + i = seekTable("hhea"); + pos = tables[i].offset; + newHHEALen = 36; + newHHEATab = (char *)gmalloc(newHHEALen); + for (i = 0; i < newHHEALen; ++i) { + newHHEATab[i] = getU8(pos++, &ok); + } + newHHEATab[34] = nGlyphs >> 8; + newHHEATab[35] = nGlyphs & 0xff; + i = seekTable("hmtx"); + pos = tables[i].offset; + newHMTXLen = 4 * nGlyphs; + newHMTXTab = (char *)gmalloc(newHMTXLen); + advWidth = 0; + for (i = 0; i < nHMetrics; ++i) { + advWidth = getU16BE(pos, &ok); + lsb = getU16BE(pos + 2, &ok); + pos += 4; + newHMTXTab[4*i ] = advWidth >> 8; + newHMTXTab[4*i + 1] = advWidth & 0xff; + newHMTXTab[4*i + 2] = lsb >> 8; + newHMTXTab[4*i + 3] = lsb & 0xff; + } + for (; i < nGlyphs; ++i) { + lsb = getU16BE(pos, &ok); + pos += 2; + newHMTXTab[4*i ] = advWidth >> 8; + newHMTXTab[4*i + 1] = advWidth & 0xff; + newHMTXTab[4*i + 2] = lsb >> 8; + newHMTXTab[4*i + 3] = lsb & 0xff; + } + } else { + newHHEATab = newHMTXTab = NULL; + newHHEALen = newHMTXLen = 0; // make gcc happy + } + + // construct the new table directory: + // - keep all original tables with non-zero length + // - fix the cmap table's length, if necessary + // - add missing tables + // - sort the table by tag + // - compute new table positions, including 4-byte alignment + // - (re)compute table checksums + nNewTables = nTables - nZeroLengthTables + + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + + (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0); + newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); + j = 0; + for (i = 0; i < nTables; ++i) { + if (tables[i].len > 0) { + newTables[j] = tables[i]; + newTables[j].origOffset = tables[i].offset; + if (checkRegion(tables[i].offset, newTables[i].len)) { + newTables[j].checksum = + computeTableChecksum(file + tables[i].offset, tables[i].len); + if (tables[i].tag == headTag) { + // don't include the file checksum + newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); + } + } + if (newTables[j].tag == cmapTag && codeToGID) { + newTables[j].len = newCmapLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + } else if (newTables[j].tag == cmapTag && badCmapLen) { + newTables[j].len = cmapLen; + } else if (newTables[j].tag == locaTag && unsortedLoca) { + newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); + newTables[j].checksum = locaChecksum; + } else if (newTables[j].tag == glyfTag && unsortedLoca) { + newTables[j].len = glyfLen; + newTables[j].checksum = glyfChecksum; + } else if (newTables[j].tag == nameTag && name) { + newTables[j].len = newNameLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + } else if (newTables[j].tag == hheaTag && abbrevHMTX) { + newTables[j].len = newHHEALen; + newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab, + newHHEALen); + } else if (newTables[j].tag == hmtxTag && abbrevHMTX) { + newTables[j].len = newHMTXLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab, + newHMTXLen); + } + ++j; + } + } + if (missingCmap) { + newTables[j].tag = cmapTag; + if (codeToGID) { + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + newTables[j].len = newCmapLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, + sizeof(cmapTab)); + newTables[j].len = sizeof(cmapTab); + } + ++j; + } + if (missingName) { + newTables[j].tag = nameTag; + if (name) { + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + newTables[j].len = newNameLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, + sizeof(nameTab)); + newTables[j].len = sizeof(nameTab); + } + ++j; + } + if (missingPost) { + newTables[j].tag = postTag; + newTables[j].checksum = computeTableChecksum((Guchar *)postTab, + sizeof(postTab)); + newTables[j].len = sizeof(postTab); + ++j; + } + if (missingOS2) { + newTables[j].tag = os2Tag; + newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab, + sizeof(os2Tab)); + newTables[j].len = sizeof(os2Tab); + ++j; + } + qsort(newTables, nNewTables, sizeof(TrueTypeTable), + &cmpTrueTypeTableTag); + pos = 12 + nNewTables * 16; + for (i = 0; i < nNewTables; ++i) { + newTables[i].offset = pos; + pos += newTables[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + + // write the table directory + tableDir = (char *)gmalloc(12 + nNewTables * 16); + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables + tableDir[5] = (char)(nNewTables & 0xff); + for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ; + t = 1 << (4 + i); + tableDir[6] = (char)((t >> 8) & 0xff); // searchRange + tableDir[7] = (char)(t & 0xff); + tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector + tableDir[9] = (char)(i & 0xff); + t = nNewTables * 16 - t; + tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift + tableDir[11] = (char)(t & 0xff); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = (char)(newTables[i].tag >> 24); + tableDir[pos+ 1] = (char)(newTables[i].tag >> 16); + tableDir[pos+ 2] = (char)(newTables[i].tag >> 8); + tableDir[pos+ 3] = (char) newTables[i].tag; + tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24); + tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16); + tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8); + tableDir[pos+ 7] = (char) newTables[i].checksum; + tableDir[pos+ 8] = (char)(newTables[i].offset >> 24); + tableDir[pos+ 9] = (char)(newTables[i].offset >> 16); + tableDir[pos+10] = (char)(newTables[i].offset >> 8); + tableDir[pos+11] = (char) newTables[i].offset; + tableDir[pos+12] = (char)(newTables[i].len >> 24); + tableDir[pos+13] = (char)(newTables[i].len >> 16); + tableDir[pos+14] = (char)(newTables[i].len >> 8); + tableDir[pos+15] = (char) newTables[i].len; + pos += 16; + } + (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); + + // compute the file checksum + fileChecksum = computeTableChecksum((Guchar *)tableDir, + 12 + nNewTables * 16); + for (i = 0; i < nNewTables; ++i) { + fileChecksum += newTables[i].checksum; + } + fileChecksum = 0xb1b0afba - fileChecksum; + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (newTables[i].tag == headTag) { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); + checksumBuf[0] = fileChecksum >> 24; + checksumBuf[1] = fileChecksum >> 16; + checksumBuf[2] = fileChecksum >> 8; + checksumBuf[3] = fileChecksum; + (*outputFunc)(outputStream, checksumBuf, 4); + (*outputFunc)(outputStream, + (char *)file + newTables[i].origOffset + 12, + newTables[i].len - 12); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } else if (newTables[i].tag == cmapTag && codeToGID) { + (*outputFunc)(outputStream, newCmapTab, newTables[i].len); + } else if (newTables[i].tag == cmapTag && missingCmap) { + (*outputFunc)(outputStream, cmapTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && name) { + (*outputFunc)(outputStream, newNameTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && missingName) { + (*outputFunc)(outputStream, nameTab, newTables[i].len); + } else if (newTables[i].tag == postTag && missingPost) { + (*outputFunc)(outputStream, postTab, newTables[i].len); + } else if (newTables[i].tag == os2Tag && missingOS2) { + (*outputFunc)(outputStream, os2Tab, newTables[i].len); + } else if (newTables[i].tag == hheaTag && abbrevHMTX) { + (*outputFunc)(outputStream, newHHEATab, newTables[i].len); + } else if (newTables[i].tag == hmtxTag && abbrevHMTX) { + (*outputFunc)(outputStream, newHMTXTab, newTables[i].len); + } else if (newTables[i].tag == locaTag && unsortedLoca) { + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + locaBuf[0] = (char)(locaTable[j].newOffset >> 24); + locaBuf[1] = (char)(locaTable[j].newOffset >> 16); + locaBuf[2] = (char)(locaTable[j].newOffset >> 8); + locaBuf[3] = (char) locaTable[j].newOffset; + (*outputFunc)(outputStream, locaBuf, 4); + } else { + locaBuf[0] = (char)(locaTable[j].newOffset >> 9); + locaBuf[1] = (char)(locaTable[j].newOffset >> 1); + (*outputFunc)(outputStream, locaBuf, 2); + } + } + } else if (newTables[i].tag == glyfTag && unsortedLoca) { + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + (*outputFunc)(outputStream, (char *)file + pos + k, n); + } else { + for (k = 0; k < n; ++k) { + (*outputFunc)(outputStream, "\0", 1); + } + } + if ((k = locaTable[j].len & 3)) { + (*outputFunc)(outputStream, "\0\0\0\0", 4 - k); + } + } + } + } else { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, + newTables[i].len); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } + if (newTables[i].len & 3) { + (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3)); + } + } + + gfree(newHMTXTab); + gfree(newHHEATab); + gfree(newCmapTab); + gfree(newNameTab); + gfree(tableDir); + gfree(newTables); + done1: + gfree(locaTable); +} + +void FoFiTrueType::cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + GString *buf; + int i; + + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + if (encoding) { + for (i = 0; i < 256; ++i) { + if (!(name = encoding[i])) { + name = ".notdef"; + } + buf = GString::format("dup {0:d} /", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, name, strlen(name)); + (*outputFunc)(outputStream, " put\n", 5); + } + } else { + for (i = 0; i < 256; ++i) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", i, i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); +} + +void FoFiTrueType::cvtCharStrings(char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + GString *buf; + char buf2[16]; + int i, k; + + // always define '.notdef' + (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + + // if there's no 'cmap' table, punt + if (nCmaps == 0) { + goto err; + } + + // map char name to glyph index: + // 1. use encoding to map name to char code + // 2. use codeToGID to map char code to glyph index + // N.B. We do this in reverse order because font subsets can have + // weird encodings that use the same character name twice, and + // the first definition is probably the one we want. + k = 0; // make gcc happy + for (i = 255; i >= 0; --i) { + if (encoding) { + name = encoding[i]; + } else { + sprintf(buf2, "c%02x", i); + name = buf2; + } + if (name && strcmp(name, ".notdef")) { + k = codeToGID[i]; + // note: Distiller (maybe Adobe's PS interpreter in general) + // doesn't like TrueType fonts that have CharStrings entries + // which point to nonexistent glyphs, hence the (k < nGlyphs) + // test + if (k > 0 && k < nGlyphs) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, name, strlen(name)); + buf = GString::format(" {0:d} def\n", k); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + } + + err: + (*outputFunc)(outputStream, "end readonly def\n", 17); +} + +void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name, + GBool needVerticalMetrics) { + Guchar headData[54]; + TrueTypeLoca *locaTable; + Guchar *locaData; + TrueTypeTable newTables[nT42Tables]; + Guchar tableDir[12 + nT42Tables*16]; + GBool ok; + Guint checksum; + int nNewTables; + int length, pos, glyfPos, i, j, k; + Guchar vheaTab[36] = { + 0, 1, 0, 0, // table version number + 0, 0, // ascent + 0, 0, // descent + 0, 0, // reserved + 0, 0, // max advance height + 0, 0, // min top side bearing + 0, 0, // min bottom side bearing + 0, 0, // y max extent + 0, 0, // caret slope rise + 0, 1, // caret slope run + 0, 0, // caret offset + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // metric data format + 0, 1 // number of advance heights in vmtx table + }; + Guchar *vmtxTab; + GBool needVhea, needVmtx; + int advance; + + // construct the 'head' table, zero out the font checksum + i = seekTable("head"); + pos = tables[i].offset; + if (!checkRegion(pos, 54)) { + return; + } + memcpy(headData, file + pos, 54); + headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0; + + // read the original 'loca' table, pad entries out to 4 bytes, and + // sort it into proper order -- some (non-compliant) fonts have + // out-of-order loca tables; in order to correctly handle the case + // where (compliant) fonts have empty entries in the middle of the + // table, cmpTrueTypeLocaPos uses offset as its primary sort key, + // and idx as its secondary key (ensuring that adjacent entries with + // the same pos value remain in the same order) + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); + i = seekTable("loca"); + pos = tables[i].offset; + ok = gTrue; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].idx = i; + if (locaFmt) { + locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); + } else { + locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); + } + } + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaOffset); + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; + } + locaTable[nGlyphs].len = 0; + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].newOffset = pos; + pos += locaTable[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + + // construct the new 'loca' table + locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); + for (i = 0; i <= nGlyphs; ++i) { + pos = locaTable[i].newOffset; + if (locaFmt) { + locaData[4*i ] = (Guchar)(pos >> 24); + locaData[4*i+1] = (Guchar)(pos >> 16); + locaData[4*i+2] = (Guchar)(pos >> 8); + locaData[4*i+3] = (Guchar) pos; + } else { + locaData[2*i ] = (Guchar)(pos >> 9); + locaData[2*i+1] = (Guchar)(pos >> 1); + } + } + + // count the number of tables + nNewTables = 0; + for (i = 0; i < nT42Tables; ++i) { + if (t42Tables[i].required || + seekTable(t42Tables[i].tag) >= 0) { + ++nNewTables; + } + } + vmtxTab = NULL; // make gcc happy + advance = 0; // make gcc happy + if (needVerticalMetrics) { + needVhea = seekTable("vhea") < 0; + needVmtx = seekTable("vmtx") < 0; + if (needVhea || needVmtx) { + i = seekTable("head"); + advance = getU16BE(tables[i].offset + 18, &ok); // units per em + if (needVhea) { + ++nNewTables; + } + if (needVmtx) { + ++nNewTables; + } + } + } + + // construct the new table headers, including table checksums + // (pad each table out to a multiple of 4 bytes) + pos = 12 + nNewTables*16; + k = 0; + for (i = 0; i < nT42Tables; ++i) { + length = -1; + checksum = 0; // make gcc happy + if (i == t42HeadTable) { + length = 54; + checksum = computeTableChecksum(headData, 54); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + checksum = computeTableChecksum(locaData, length); + } else if (i == t42GlyfTable) { + length = 0; + checksum = 0; + glyfPos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + length += locaTable[j].len; + if (length & 3) { + length += 4 - (length & 3); + } + if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { + checksum += + computeTableChecksum(file + glyfPos + locaTable[j].origOffset, + locaTable[j].len); + } + } + } else { + if ((j = seekTable(t42Tables[i].tag)) >= 0) { + length = tables[j].len; + if (checkRegion(tables[j].offset, length)) { + checksum = computeTableChecksum(file + tables[j].offset, length); + } + } else if (needVerticalMetrics && i == t42VheaTable) { + vheaTab[10] = advance / 256; // max advance height + vheaTab[11] = advance % 256; + length = sizeof(vheaTab); + checksum = computeTableChecksum(vheaTab, length); + } else if (needVerticalMetrics && i == t42VmtxTable) { + length = 4 + (nGlyphs - 1) * 4; + vmtxTab = (Guchar *)gmalloc(length); + vmtxTab[0] = advance / 256; + vmtxTab[1] = advance % 256; + for (j = 2; j < length; j += 2) { + vmtxTab[j] = 0; + vmtxTab[j+1] = 0; + } + checksum = computeTableChecksum(vmtxTab, length); + } else if (t42Tables[i].required) { + //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", + //~ t42Tables[i].tag); + length = 0; + checksum = 0; + } + } + if (length >= 0) { + newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) | + ((t42Tables[i].tag[1] & 0xff) << 16) | + ((t42Tables[i].tag[2] & 0xff) << 8) | + (t42Tables[i].tag[3] & 0xff); + newTables[k].checksum = checksum; + newTables[k].offset = pos; + newTables[k].len = length; + pos += length; + if (pos & 3) { + pos += 4 - (length & 3); + } + ++k; + } + } + + // construct the table directory + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = 0; // numTables + tableDir[5] = nNewTables; + tableDir[6] = 0; // searchRange + tableDir[7] = (Guchar)128; + tableDir[8] = 0; // entrySelector + tableDir[9] = 3; + tableDir[10] = 0; // rangeShift + tableDir[11] = (Guchar)(16 * nNewTables - 128); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = (Guchar)(newTables[i].tag >> 24); + tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16); + tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8); + tableDir[pos+ 3] = (Guchar) newTables[i].tag; + tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24); + tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16); + tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8); + tableDir[pos+ 7] = (Guchar) newTables[i].checksum; + tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24); + tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16); + tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8); + tableDir[pos+11] = (Guchar) newTables[i].offset; + tableDir[pos+12] = (Guchar)(newTables[i].len >> 24); + tableDir[pos+13] = (Guchar)(newTables[i].len >> 16); + tableDir[pos+14] = (Guchar)(newTables[i].len >> 8); + tableDir[pos+15] = (Guchar) newTables[i].len; + pos += 16; + } + + // compute the font checksum and store it in the head table + checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); + for (i = 0; i < nNewTables; ++i) { + checksum += newTables[i].checksum; + } + checksum = 0xb1b0afba - checksum; // because the TrueType spec says so + headData[ 8] = (Guchar)(checksum >> 24); + headData[ 9] = (Guchar)(checksum >> 16); + headData[10] = (Guchar)(checksum >> 8); + headData[11] = (Guchar) checksum; + + // start the sfnts array + if (name) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, name->getCString(), name->getLength()); + (*outputFunc)(outputStream, " [\n", 3); + } else { + (*outputFunc)(outputStream, "/sfnts [\n", 9); + } + + // write the table directory + dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (i == t42HeadTable) { + dumpString(headData, 54, outputFunc, outputStream); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + dumpString(locaData, length, outputFunc, outputStream); + } else if (i == t42GlyfTable) { + glyfPos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + if (locaTable[j].len > 0 && + checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { + dumpString(file + glyfPos + locaTable[j].origOffset, + locaTable[j].len, outputFunc, outputStream); + } + } + } else { + // length == 0 means the table is missing and the error was + // already reported during the construction of the table + // headers + if ((length = newTables[i].len) > 0) { + if ((j = seekTable(t42Tables[i].tag)) >= 0 && + checkRegion(tables[j].offset, tables[j].len)) { + dumpString(file + tables[j].offset, tables[j].len, + outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VheaTable) { + dumpString(vheaTab, length, outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VmtxTable) { + dumpString(vmtxTab, length, outputFunc, outputStream); + gfree(vmtxTab); + } + } + } + } + + // end the sfnts array + (*outputFunc)(outputStream, "] def\n", 6); + + gfree(locaData); + gfree(locaTable); +} + +void FoFiTrueType::dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream) { + GString *buf; + int pad, i, j; + + (*outputFunc)(outputStream, "<", 1); + for (i = 0; i < length; i += 32) { + for (j = 0; j < 32 && i+j < length; ++j) { + buf = GString::format("{0:02x}", s[i+j] & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (i % (65536 - 32) == 65536 - 64) { + (*outputFunc)(outputStream, ">\n<", 3); + } else if (i+32 < length) { + (*outputFunc)(outputStream, "\n", 1); + } + } + if (length & 3) { + pad = 4 - (length & 3); + for (i = 0; i < pad; ++i) { + (*outputFunc)(outputStream, "00", 2); + } + } + // add an extra zero byte because the Adobe Type 42 spec says so + (*outputFunc)(outputStream, "00>\n", 4); +} + +Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { + Guint checksum, word; + int i; + + checksum = 0; + for (i = 0; i+3 < length; i += 4) { + word = ((data[i ] & 0xff) << 24) + + ((data[i+1] & 0xff) << 16) + + ((data[i+2] & 0xff) << 8) + + (data[i+3] & 0xff); + checksum += word; + } + if (length & 3) { + word = 0; + i = length & ~3; + switch (length & 3) { + case 3: + word |= (data[i+2] & 0xff) << 8; + case 2: + word |= (data[i+1] & 0xff) << 16; + case 1: + word |= (data[i ] & 0xff) << 24; + break; + } + checksum += word; + } + return checksum; +} + +void FoFiTrueType::parse() { + Guint topTag; + int pos, ver, i, j; + + parsedOk = gTrue; + + // look for a collection (TTC) + topTag = getU32BE(0, &parsedOk); + if (!parsedOk) { + return; + } + if (topTag == ttcfTag) { + /* TTC font */ + int dircount; + + dircount = getU32BE(8, &parsedOk); + if (!parsedOk) + return; + if (! dircount) { + parsedOk = gFalse; + return; + } + + if (faceIndex >= dircount) + faceIndex = 0; + pos = getU32BE(12 + faceIndex * 4, &parsedOk); + if (! parsedOk) + return; + } else { + pos = 0; + } + + // check the sfnt version + ver = getU32BE(pos, &parsedOk); + if (!parsedOk) { + return; + } + openTypeCFF = ver == 0x4f54544f; // 'OTTO' + + // read the table directory + nTables = getU16BE(pos + 4, &parsedOk); + if (!parsedOk) { + return; + } + tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); + pos += 12; + for (i = 0; i < nTables; ++i) { + tables[i].tag = getU32BE(pos, &parsedOk); + tables[i].checksum = getU32BE(pos + 4, &parsedOk); + tables[i].offset = (int)getU32BE(pos + 8, &parsedOk); + tables[i].len = (int)getU32BE(pos + 12, &parsedOk); + if (tables[i].offset + tables[i].len < tables[i].offset || + tables[i].offset + tables[i].len > len) { + parsedOk = gFalse; + } + pos += 16; + } + if (!parsedOk) { + return; + } + + // check for tables that are required by both the TrueType spec and + // the Type 42 spec + if (seekTable("head") < 0 || + seekTable("hhea") < 0 || + seekTable("maxp") < 0 || + seekTable("hmtx") < 0 || + (!openTypeCFF && seekTable("loca") < 0) || + (!openTypeCFF && seekTable("glyf") < 0) || + (openTypeCFF && seekTable("CFF ") < 0)) { + parsedOk = gFalse; + return; + } + + // read the cmaps + if ((i = seekTable("cmap")) >= 0) { + pos = tables[i].offset + 2; + nCmaps = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + return; + } + cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); + for (j = 0; j < nCmaps; ++j) { + cmaps[j].platform = getU16BE(pos, &parsedOk); + cmaps[j].encoding = getU16BE(pos + 2, &parsedOk); + cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk); + pos += 8; + cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk); + cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk); + } + if (!parsedOk) { + return; + } + } else { + nCmaps = 0; + } + + // get the number of glyphs from the maxp table + i = seekTable("maxp"); + nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk); + if (!parsedOk) { + return; + } + + // get the bbox and loca table format from the head table + i = seekTable("head"); + bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk); + bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk); + bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk); + bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk); + locaFmt = getS16BE(tables[i].offset + 50, &parsedOk); + if (!parsedOk) { + return; + } + + // make sure the loca table is sane (correct length and entries are + // in bounds) + if (!openTypeCFF) { + i = seekTable("loca"); + if (tables[i].len < 0) { + parsedOk = gFalse; + return; + } + if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { + nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1; + } + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk); + } else { + pos = getU16BE(tables[i].offset + j*2, &parsedOk); + } + if (pos < 0 || pos > len) { + parsedOk = gFalse; + } + } + if (!parsedOk) { + return; + } + } + + // read the post table + readPostTable(); +} + +void FoFiTrueType::readPostTable() { + GString *name; + int tablePos, postFmt, stringIdx, stringPos; + GBool ok; + int i, j, n, m; + + ok = gTrue; + if ((i = seekTable("post")) < 0) { + return; + } + tablePos = tables[i].offset; + postFmt = getU32BE(tablePos, &ok); + if (!ok) { + goto err; + } + if (postFmt == 0x00010000) { + nameToGID = new GHash(gTrue); + for (i = 0; i < 258; ++i) { + nameToGID->add(new GString(macGlyphNames[i]), i); + } + } else if (postFmt == 0x00020000) { + nameToGID = new GHash(gTrue); + n = getU16BE(tablePos + 32, &ok); + if (!ok) { + goto err; + } + if (n > nGlyphs) { + n = nGlyphs; + } + stringIdx = 0; + stringPos = tablePos + 34 + 2*n; + for (i = 0; i < n; ++i) { + j = getU16BE(tablePos + 34 + 2*i, &ok); + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } else { + j -= 258; + if (j != stringIdx) { + for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; + stringIdx < j; + ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; + if (!ok) { + goto err; + } + } + m = getU8(stringPos, &ok); + if (!ok || !checkRegion(stringPos + 1, m)) { + goto err; + } + name = new GString((char *)&file[stringPos + 1], m); + nameToGID->removeInt(name); + nameToGID->add(name, i); + ++stringIdx; + stringPos += 1 + m; + } + } + } else if (postFmt == 0x00028000) { + nameToGID = new GHash(gTrue); + for (i = 0; i < nGlyphs; ++i) { + j = getU8(tablePos + 32 + i, &ok); + if (!ok) { + goto err; + } + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } + } + } + + return; + + err: + if (nameToGID) { + delete nameToGID; + nameToGID = NULL; + } +} + +int FoFiTrueType::seekTable(char *tag) { + Guint tagI; + int i; + + tagI = ((tag[0] & 0xff) << 24) | + ((tag[1] & 0xff) << 16) | + ((tag[2] & 0xff) << 8) | + (tag[3] & 0xff); + for (i = 0; i < nTables; ++i) { + if (tables[i].tag == tagI) { + return i; + } + } + return -1; +} diff --git a/kpdf/xpdf/fofi/FoFiType1.cc b/kpdf/xpdf/fofi/FoFiType1.cc deleted file mode 100644 index 88b35ecc..00000000 --- a/kpdf/xpdf/fofi/FoFiType1.cc +++ /dev/null @@ -1,257 +0,0 @@ -//======================================================================== -// -// FoFiType1.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "FoFiEncodings.h" -#include "FoFiType1.h" - -//------------------------------------------------------------------------ -// FoFiType1 -//------------------------------------------------------------------------ - -FoFiType1 *FoFiType1::make(char *fileA, int lenA) { - return new FoFiType1(fileA, lenA, gFalse); -} - -FoFiType1 *FoFiType1::load(char *fileName) { - char *fileA; - int lenA; - - if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { - return NULL; - } - return new FoFiType1(fileA, lenA, gTrue); -} - -FoFiType1::FoFiType1(char *fileA, int lenA, GBool freeFileDataA): - FoFiBase(fileA, lenA, freeFileDataA) -{ - name = NULL; - encoding = NULL; - parsed = gFalse; -} - -FoFiType1::~FoFiType1() { - int i; - - if (name) { - gfree(name); - } - if (encoding && encoding != fofiType1StandardEncoding) { - for (i = 0; i < 256; ++i) { - gfree(encoding[i]); - } - gfree(encoding); - } -} - -char *FoFiType1::getName() { - if (!parsed) { - parse(); - } - return name; -} - -char **FoFiType1::getEncoding() { - if (!parsed) { - parse(); - } - return encoding; -} - -void FoFiType1::writeEncoded(char **newEncoding, - FoFiOutputFunc outputFunc, void *outputStream) { - char buf[512]; - char *line, *line2, *p; - int i; - - // copy everything up to the encoding - for (line = (char *)file; - line && strncmp(line, "/Encoding", 9); - line = getNextLine(line)) ; - if (!line) { - // no encoding - just copy the whole font file - (*outputFunc)(outputStream, (char *)file, len); - return; - } - (*outputFunc)(outputStream, (char *)file, line - (char *)file); - - // write the new encoding - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - (*outputFunc)(outputStream, - "0 1 255 {1 index exch /.notdef put} for\n", 40); - for (i = 0; i < 256; ++i) { - if (newEncoding[i]) { - sprintf(buf, "dup %d /%s put\n", i, newEncoding[i]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - (*outputFunc)(outputStream, "readonly def\n", 13); - - // find the end of the encoding data - //~ this ought to parse PostScript tokens - if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { - line = getNextLine(line); - } else { - // skip "/Encoding" + one whitespace char, - // then look for 'def' preceded by PostScript whitespace - p = line + 10; - line = NULL; - for (; p < (char *)file + len; ++p) { - if ((*p == ' ' || *p == '\t' || *p == '\x0a' || - *p == '\x0d' || *p == '\x0c' || *p == '\0') && - p + 4 <= (char *)file + len && - !strncmp(p + 1, "def", 3)) { - line = p + 4; - break; - } - } - } - - // some fonts have two /Encoding entries in their dictionary, so we - // check for a second one here - if (line) { - for (line2 = line, i = 0; - i < 20 && line2 && strncmp(line2, "/Encoding", 9); - line2 = getNextLine(line2), ++i) ; - if (i < 20 && line2) { - (*outputFunc)(outputStream, line, line2 - line); - if (!strncmp(line2, "/Encoding StandardEncoding def", 30)) { - line = getNextLine(line2); - } else { - // skip "/Encoding" + one whitespace char, - // then look for 'def' preceded by PostScript whitespace - p = line2 + 10; - line = NULL; - for (; p < (char *)file + len; ++p) { - if ((*p == ' ' || *p == '\t' || *p == '\x0a' || - *p == '\x0d' || *p == '\x0c' || *p == '\0') && - p + 4 <= (char *)file + len && - !strncmp(p + 1, "def", 3)) { - line = p + 4; - break; - } - } - } - } - - // copy everything after the encoding - if (line) { - (*outputFunc)(outputStream, line, ((char *)file + len) - line); - } - } -} - -char *FoFiType1::getNextLine(char *line) { - while (line < (char *)file + len && *line != '\x0a' && *line != '\x0d') { - ++line; - } - if (line < (char *)file + len && *line == '\x0d') { - ++line; - } - if (line < (char *)file + len && *line == '\x0a') { - ++line; - } - if (line >= (char *)file + len) { - return NULL; - } - return line; -} - -void FoFiType1::parse() { - char *line, *line1, *p, *p2; - char buf[256]; - char c; - int n, code, i, j; - - for (i = 1, line = (char *)file; - i <= 100 && line && (!name || !encoding); - ++i) { - - // get font name - if (!name && !strncmp(line, "/FontName", 9)) { - strncpy(buf, line, 255); - buf[255] = '\0'; - if ((p = strchr(buf+9, '/')) && - (p = strtok(p+1, " \t\n\r"))) { - name = copyString(p); - } - line = getNextLine(line); - - // get encoding - } else if (!encoding && - !strncmp(line, "/Encoding StandardEncoding def", 30)) { - encoding = fofiType1StandardEncoding; - } else if (!encoding && - !strncmp(line, "/Encoding 256 array", 19)) { - encoding = (char **)gmallocn(256, sizeof(char *)); - for (j = 0; j < 256; ++j) { - encoding[j] = NULL; - } - for (j = 0, line = getNextLine(line); - j < 300 && line && (line1 = getNextLine(line)); - ++j, line = line1) { - if ((n = line1 - line) > 255) { - n = 255; - } - strncpy(buf, line, n); - buf[n] = '\0'; - for (p = buf; *p == ' ' || *p == '\t'; ++p) ; - if (!strncmp(p, "dup", 3)) { - for (p += 3; *p == ' ' || *p == '\t'; ++p) ; - for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ; - if (*p2) { - c = *p2; - *p2 = '\0'; - code = atoi(p); - *p2 = c; - if (code == 8 && *p2 == '#') { - code = 0; - for (++p2; *p2 >= '0' && *p2 <= '7'; ++p2) { - code = code * 8 + (*p2 - '0'); - } - } - if (code >= 0 && code < 256) { - for (p = p2; *p == ' ' || *p == '\t'; ++p) ; - if (*p == '/') { - ++p; - for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; - *p2 = '\0'; - encoding[code] = copyString(p); - } - } - } - } else { - p = strtok(buf, " \t\n\r"); - if (p) - { - if (!strcmp(p, "def")) break; - if (!strcmp(p, "readonly")) break; - // the spec does not says this but i'm mantaining old xpdf behaviour that accepts "foo def" as end of the encoding array - p = strtok(buf, " \t\n\r"); - if (p && !strcmp(p, "def")) break; - } - } - } - //~ check for getinterval/putinterval junk - - } else { - line = getNextLine(line); - } - } - - parsed = gTrue; -} diff --git a/kpdf/xpdf/fofi/FoFiType1.cpp b/kpdf/xpdf/fofi/FoFiType1.cpp new file mode 100644 index 00000000..f6e676a2 --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiType1.cpp @@ -0,0 +1,257 @@ +//======================================================================== +// +// FoFiType1.cpp +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "FoFiEncodings.h" +#include "FoFiType1.h" + +//------------------------------------------------------------------------ +// FoFiType1 +//------------------------------------------------------------------------ + +FoFiType1 *FoFiType1::make(char *fileA, int lenA) { + return new FoFiType1(fileA, lenA, gFalse); +} + +FoFiType1 *FoFiType1::load(char *fileName) { + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + return new FoFiType1(fileA, lenA, gTrue); +} + +FoFiType1::FoFiType1(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + name = NULL; + encoding = NULL; + parsed = gFalse; +} + +FoFiType1::~FoFiType1() { + int i; + + if (name) { + gfree(name); + } + if (encoding && encoding != fofiType1StandardEncoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } +} + +char *FoFiType1::getName() { + if (!parsed) { + parse(); + } + return name; +} + +char **FoFiType1::getEncoding() { + if (!parsed) { + parse(); + } + return encoding; +} + +void FoFiType1::writeEncoded(char **newEncoding, + FoFiOutputFunc outputFunc, void *outputStream) { + char buf[512]; + char *line, *line2, *p; + int i; + + // copy everything up to the encoding + for (line = (char *)file; + line && strncmp(line, "/Encoding", 9); + line = getNextLine(line)) ; + if (!line) { + // no encoding - just copy the whole font file + (*outputFunc)(outputStream, (char *)file, len); + return; + } + (*outputFunc)(outputStream, (char *)file, line - (char *)file); + + // write the new encoding + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + (*outputFunc)(outputStream, + "0 1 255 {1 index exch /.notdef put} for\n", 40); + for (i = 0; i < 256; ++i) { + if (newEncoding[i]) { + sprintf(buf, "dup %d /%s put\n", i, newEncoding[i]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); + + // find the end of the encoding data + //~ this ought to parse PostScript tokens + if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { + line = getNextLine(line); + } else { + // skip "/Encoding" + one whitespace char, + // then look for 'def' preceded by PostScript whitespace + p = line + 10; + line = NULL; + for (; p < (char *)file + len; ++p) { + if ((*p == ' ' || *p == '\t' || *p == '\x0a' || + *p == '\x0d' || *p == '\x0c' || *p == '\0') && + p + 4 <= (char *)file + len && + !strncmp(p + 1, "def", 3)) { + line = p + 4; + break; + } + } + } + + // some fonts have two /Encoding entries in their dictionary, so we + // check for a second one here + if (line) { + for (line2 = line, i = 0; + i < 20 && line2 && strncmp(line2, "/Encoding", 9); + line2 = getNextLine(line2), ++i) ; + if (i < 20 && line2) { + (*outputFunc)(outputStream, line, line2 - line); + if (!strncmp(line2, "/Encoding StandardEncoding def", 30)) { + line = getNextLine(line2); + } else { + // skip "/Encoding" + one whitespace char, + // then look for 'def' preceded by PostScript whitespace + p = line2 + 10; + line = NULL; + for (; p < (char *)file + len; ++p) { + if ((*p == ' ' || *p == '\t' || *p == '\x0a' || + *p == '\x0d' || *p == '\x0c' || *p == '\0') && + p + 4 <= (char *)file + len && + !strncmp(p + 1, "def", 3)) { + line = p + 4; + break; + } + } + } + } + + // copy everything after the encoding + if (line) { + (*outputFunc)(outputStream, line, ((char *)file + len) - line); + } + } +} + +char *FoFiType1::getNextLine(char *line) { + while (line < (char *)file + len && *line != '\x0a' && *line != '\x0d') { + ++line; + } + if (line < (char *)file + len && *line == '\x0d') { + ++line; + } + if (line < (char *)file + len && *line == '\x0a') { + ++line; + } + if (line >= (char *)file + len) { + return NULL; + } + return line; +} + +void FoFiType1::parse() { + char *line, *line1, *p, *p2; + char buf[256]; + char c; + int n, code, i, j; + + for (i = 1, line = (char *)file; + i <= 100 && line && (!name || !encoding); + ++i) { + + // get font name + if (!name && !strncmp(line, "/FontName", 9)) { + strncpy(buf, line, 255); + buf[255] = '\0'; + if ((p = strchr(buf+9, '/')) && + (p = strtok(p+1, " \t\n\r"))) { + name = copyString(p); + } + line = getNextLine(line); + + // get encoding + } else if (!encoding && + !strncmp(line, "/Encoding StandardEncoding def", 30)) { + encoding = fofiType1StandardEncoding; + } else if (!encoding && + !strncmp(line, "/Encoding 256 array", 19)) { + encoding = (char **)gmallocn(256, sizeof(char *)); + for (j = 0; j < 256; ++j) { + encoding[j] = NULL; + } + for (j = 0, line = getNextLine(line); + j < 300 && line && (line1 = getNextLine(line)); + ++j, line = line1) { + if ((n = line1 - line) > 255) { + n = 255; + } + strncpy(buf, line, n); + buf[n] = '\0'; + for (p = buf; *p == ' ' || *p == '\t'; ++p) ; + if (!strncmp(p, "dup", 3)) { + for (p += 3; *p == ' ' || *p == '\t'; ++p) ; + for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ; + if (*p2) { + c = *p2; + *p2 = '\0'; + code = atoi(p); + *p2 = c; + if (code == 8 && *p2 == '#') { + code = 0; + for (++p2; *p2 >= '0' && *p2 <= '7'; ++p2) { + code = code * 8 + (*p2 - '0'); + } + } + if (code >= 0 && code < 256) { + for (p = p2; *p == ' ' || *p == '\t'; ++p) ; + if (*p == '/') { + ++p; + for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; + *p2 = '\0'; + encoding[code] = copyString(p); + } + } + } + } else { + p = strtok(buf, " \t\n\r"); + if (p) + { + if (!strcmp(p, "def")) break; + if (!strcmp(p, "readonly")) break; + // the spec does not says this but i'm mantaining old xpdf behaviour that accepts "foo def" as end of the encoding array + p = strtok(buf, " \t\n\r"); + if (p && !strcmp(p, "def")) break; + } + } + } + //~ check for getinterval/putinterval junk + + } else { + line = getNextLine(line); + } + } + + parsed = gTrue; +} diff --git a/kpdf/xpdf/fofi/FoFiType1C.cc b/kpdf/xpdf/fofi/FoFiType1C.cc deleted file mode 100644 index 3b28f321..00000000 --- a/kpdf/xpdf/fofi/FoFiType1C.cc +++ /dev/null @@ -1,2603 +0,0 @@ -//======================================================================== -// -// FoFiType1C.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include "gmem.h" -#include "GString.h" -#include "FoFiEncodings.h" -#include "FoFiType1C.h" - -//------------------------------------------------------------------------ - -static char hexChars[17] = "0123456789ABCDEF"; - -//------------------------------------------------------------------------ -// FoFiType1C -//------------------------------------------------------------------------ - -FoFiType1C *FoFiType1C::make(char *fileA, int lenA) { - FoFiType1C *ff; - - ff = new FoFiType1C(fileA, lenA, gFalse); - if (!ff->parse()) { - delete ff; - return NULL; - } - return ff; -} - -FoFiType1C *FoFiType1C::load(char *fileName) { - FoFiType1C *ff; - char *fileA; - int lenA; - - if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { - return NULL; - } - ff = new FoFiType1C(fileA, lenA, gTrue); - if (!ff->parse()) { - delete ff; - return NULL; - } - return ff; -} - -FoFiType1C::FoFiType1C(char *fileA, int lenA, GBool freeFileDataA): - FoFiBase(fileA, lenA, freeFileDataA) -{ - name = NULL; - encoding = NULL; - privateDicts = NULL; - fdSelect = NULL; - charset = NULL; -} - -FoFiType1C::~FoFiType1C() { - int i; - - if (name) { - delete name; - } - if (encoding && - encoding != fofiType1StandardEncoding && - encoding != fofiType1ExpertEncoding) { - for (i = 0; i < 256; ++i) { - gfree(encoding[i]); - } - gfree(encoding); - } - if (privateDicts) { - gfree(privateDicts); - } - if (fdSelect) { - gfree(fdSelect); - } - if (charset && - charset != fofiType1CISOAdobeCharset && - charset != fofiType1CExpertCharset && - charset != fofiType1CExpertSubsetCharset) { - gfree(charset); - } -} - -char *FoFiType1C::getName() { - return name ? name->getCString() : (char *)NULL; -} - -char **FoFiType1C::getEncoding() { - return encoding; -} - -Gushort *FoFiType1C::getCIDToGIDMap(int *nCIDs) { - Gushort *map; - int n, i; - - // a CID font's top dict has ROS as the first operator - if (topDict.firstOp != 0x0c1e) { - *nCIDs = 0; - return NULL; - } - - // in a CID font, the charset data is the GID-to-CID mapping, so all - // we have to do is reverse it - n = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] > n) { - n = charset[i]; - } - } - ++n; - map = (Gushort *)gmallocn(n, sizeof(Gushort)); - memset(map, 0, n * sizeof(Gushort)); - for (i = 0; i < nGlyphs; ++i) { - map[charset[i]] = i; - } - *nCIDs = n; - return map; -} - -void FoFiType1C::convertToType1(char *psName, char **newEncoding, GBool ascii, - FoFiOutputFunc outputFunc, - void *outputStream) { - int psNameLen; - Type1CEexecBuf eb; - Type1CIndex subrIdx; - Type1CIndexVal val; - GString *buf; - char buf2[256]; - char **enc; - GBool ok; - int i; - - if (psName) { - psNameLen = strlen(psName); - } else { - psName = name->getCString(); - psNameLen = name->getLength(); - } - - // write header and font dictionary, up to encoding - ok = gTrue; - (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); - (*outputFunc)(outputStream, psName, psNameLen); - if (topDict.versionSID != 0) { - getString(topDict.versionSID, buf2, &ok); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - } - (*outputFunc)(outputStream, "\n", 1); - // the dictionary needs room for 12 entries: the following 9, plus - // Private and CharStrings (in the eexec section) and FID (which is - // added by definefont) - (*outputFunc)(outputStream, "12 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); - if (topDict.versionSID != 0) { - (*outputFunc)(outputStream, "/version (", 10); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.noticeSID != 0) { - getString(topDict.noticeSID, buf2, &ok); - (*outputFunc)(outputStream, "/Notice (", 9); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.copyrightSID != 0) { - getString(topDict.copyrightSID, buf2, &ok); - (*outputFunc)(outputStream, "/Copyright (", 12); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.fullNameSID != 0) { - getString(topDict.fullNameSID, buf2, &ok); - (*outputFunc)(outputStream, "/FullName (", 11); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.familyNameSID != 0) { - getString(topDict.familyNameSID, buf2, &ok); - (*outputFunc)(outputStream, "/FamilyName (", 13); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.weightSID != 0) { - getString(topDict.weightSID, buf2, &ok); - (*outputFunc)(outputStream, "/Weight (", 9); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (topDict.isFixedPitch) { - (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); - } else { - (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); - } - buf = GString::format("/ItalicAngle {0:.4g} def\n", topDict.italicAngle); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format("/UnderlinePosition {0:.4g} def\n", - topDict.underlinePosition); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format("/UnderlineThickness {0:.4g} def\n", - topDict.underlineThickness); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "end readonly def\n", 17); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, psNameLen); - (*outputFunc)(outputStream, " def\n", 5); - buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] readonly def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], - topDict.fontMatrix[2], topDict.fontMatrix[3], - topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] readonly def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - if (topDict.uniqueID != 0) { - buf = GString::format("/UniqueID {0:d} def\n", topDict.uniqueID); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - - // write the encoding - (*outputFunc)(outputStream, "/Encoding ", 10); - if (!newEncoding && encoding == fofiType1StandardEncoding) { - (*outputFunc)(outputStream, "StandardEncoding def\n", 21); - } else { - (*outputFunc)(outputStream, "256 array\n", 10); - (*outputFunc)(outputStream, - "0 1 255 {1 index exch /.notdef put} for\n", 40); - enc = newEncoding ? newEncoding : encoding; - for (i = 0; i < 256; ++i) { - if (enc[i]) { - buf = GString::format("dup {0:d} /{1:s} put\n", i, enc[i]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - } - (*outputFunc)(outputStream, "readonly def\n", 13); - } - (*outputFunc)(outputStream, "currentdict end\n", 16); - - // start the binary section - (*outputFunc)(outputStream, "currentfile eexec\n", 18); - eb.outputFunc = outputFunc; - eb.outputStream = outputStream; - eb.ascii = ascii; - eb.r1 = 55665; - eb.line = 0; - - // write the private dictionary - eexecWrite(&eb, "\x83\xca\x73\xd5"); - eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); - eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" - " executeonly def\n"); - eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); - eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); - eexecWrite(&eb, "/MinFeature {16 16} def\n"); - eexecWrite(&eb, "/password 5839 def\n"); - if (privateDicts[0].nBlueValues) { - eexecWrite(&eb, "/BlueValues ["); - for (i = 0; i < privateDicts[0].nBlueValues; ++i) { - buf = GString::format("{0:s}{1:d}", - i > 0 ? " " : "", privateDicts[0].blueValues[i]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].nOtherBlues) { - eexecWrite(&eb, "/OtherBlues ["); - for (i = 0; i < privateDicts[0].nOtherBlues; ++i) { - buf = GString::format("{0:s}{1:d}", - i > 0 ? " " : "", privateDicts[0].otherBlues[i]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].nFamilyBlues) { - eexecWrite(&eb, "/FamilyBlues ["); - for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) { - buf = GString::format("{0:s}{1:d}", - i > 0 ? " " : "", privateDicts[0].familyBlues[i]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].nFamilyOtherBlues) { - eexecWrite(&eb, "/FamilyOtherBlues ["); - for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) { - buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "", - privateDicts[0].familyOtherBlues[i]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].blueScale != 0.039625) { - buf = GString::format("/BlueScale {0:.4g} def\n", - privateDicts[0].blueScale); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[0].blueShift != 7) { - buf = GString::format("/BlueShift {0:d} def\n", privateDicts[0].blueShift); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[0].blueFuzz != 1) { - buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[0].blueFuzz); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[0].hasStdHW) { - buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[0].stdHW); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[0].hasStdVW) { - buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[0].stdVW); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[0].nStemSnapH) { - eexecWrite(&eb, "/StemSnapH ["); - for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { - buf = GString::format("{0:s}{1:.4g}", - i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].nStemSnapV) { - eexecWrite(&eb, "/StemSnapV ["); - for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { - buf = GString::format("{0:s}{1:.4g}", - i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[0].hasForceBold) { - buf = GString::format("/ForceBold {0:s} def\n", - privateDicts[0].forceBold ? "true" : "false"); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[0].forceBoldThreshold != 0) { - buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", - privateDicts[0].forceBoldThreshold); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[0].languageGroup != 0) { - buf = GString::format("/LanguageGroup {0:d} def\n", - privateDicts[0].languageGroup); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[0].expansionFactor != 0.06) { - buf = GString::format("/ExpansionFactor {0:.4g} def\n", - privateDicts[0].expansionFactor); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - - // set up subroutines - ok = gTrue; - getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok); - if (!ok) { - subrIdx.pos = -1; - } - - // write the CharStrings - buf = GString::format("2 index /CharStrings {0:d} dict dup begin\n", - nGlyphs); - eexecWrite(&eb, buf->getCString()); - delete buf; - for (i = 0; i < nGlyphs; ++i) { - ok = gTrue; - getIndexVal(&charStringsIdx, i, &val, &ok); - if (ok) { - getString(charset[i], buf2, &ok); - if (ok) { - eexecCvtGlyph(&eb, buf2, val.pos, val.len, &subrIdx, &privateDicts[0]); - } - } - } - eexecWrite(&eb, "end\n"); - eexecWrite(&eb, "end\n"); - eexecWrite(&eb, "readonly put\n"); - eexecWrite(&eb, "noaccess put\n"); - eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); - eexecWrite(&eb, "mark currentfile closefile\n"); - - // trailer - if (ascii && eb.line > 0) { - (*outputFunc)(outputStream, "\n", 1); - } - for (i = 0; i < 8; ++i) { - (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); - } - (*outputFunc)(outputStream, "cleartomark\n", 12); -} - -void FoFiType1C::convertToCIDType0(char *psName, - FoFiOutputFunc outputFunc, - void *outputStream) { - int *cidMap; - GString *charStrings; - int *charStringOffsets; - Type1CIndex subrIdx; - Type1CIndexVal val; - int nCIDs, gdBytes; - GString *buf; - char buf2[256]; - GBool ok; - int gid, offset, n, i, j, k; - - // compute the CID count and build the CID-to-GID mapping - nCIDs = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] >= nCIDs) { - nCIDs = charset[i] + 1; - } - } - cidMap = (int *)gmallocn(nCIDs, sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - cidMap[i] = -1; - } - for (i = 0; i < nGlyphs; ++i) { - cidMap[charset[i]] = i; - } - - // build the charstrings - charStrings = new GString(); - charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - charStringOffsets[i] = charStrings->getLength(); - if ((gid = cidMap[i]) >= 0) { - ok = gTrue; - getIndexVal(&charStringsIdx, gid, &val, &ok); - if (ok) { - getIndex(privateDicts[fdSelect[gid]].subrsOffset, &subrIdx, &ok); - if (!ok) { - subrIdx.pos = -1; - } - cvtGlyph(val.pos, val.len, charStrings, - &subrIdx, &privateDicts[fdSelect[gid]], gTrue); - } - } - } - charStringOffsets[nCIDs] = charStrings->getLength(); - - // compute gdBytes = number of bytes needed for charstring offsets - // (offset size needs to account for the charstring offset table, - // with a worst case of five bytes per entry, plus the charstrings - // themselves) - i = (nCIDs + 1) * 5 + charStrings->getLength(); - if (i < 0x100) { - gdBytes = 1; - } else if (i < 0x10000) { - gdBytes = 2; - } else if (i < 0x1000000) { - gdBytes = 3; - } else { - gdBytes = 4; - } - - // begin the font dictionary - (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); - (*outputFunc)(outputStream, "20 dict begin\n", 14); - (*outputFunc)(outputStream, "/CIDFontName /", 14); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); - (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); - if (topDict.registrySID > 0 && topDict.orderingSID > 0) { - ok = gTrue; - getString(topDict.registrySID, buf2, &ok); - if (ok) { - (*outputFunc)(outputStream, " /Registry (", 13); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - (*outputFunc)(outputStream, ") def\n", 6); - } - ok = gTrue; - getString(topDict.orderingSID, buf2, &ok); - if (ok) { - (*outputFunc)(outputStream, " /Ordering (", 13); - (*outputFunc)(outputStream, buf2, strlen(buf2)); - (*outputFunc)(outputStream, ") def\n", 6); - } - } else { - (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); - (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); - } - buf = GString::format(" /Supplement {0:d} def\n", topDict.supplement); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "end def\n", 8); - if (topDict.hasFontMatrix) { - buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], - topDict.fontMatrix[2], topDict.fontMatrix[3], - topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } else if (privateDicts[0].hasFontMatrix) { - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - } else { - (*outputFunc)(outputStream, - "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); - } - buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); - (*outputFunc)(outputStream, " /FSType 8 def\n", 16); - (*outputFunc)(outputStream, "end def\n", 8); - - // CIDFont-specific entries - buf = GString::format("/CIDCount {0:d} def\n", nCIDs); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); - buf = GString::format("/GDBytes {0:d} def\n", gdBytes); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); - if (topDict.paintType != 0) { - buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - - // FDArray entry - buf = GString::format("/FDArray {0:d} array\n", nFDs); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - for (i = 0; i < nFDs; ++i) { - buf = GString::format("dup {0:d} 10 dict begin\n", i); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - if (privateDicts[i].hasFontMatrix) { - buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", - privateDicts[i].fontMatrix[0], - privateDicts[i].fontMatrix[1], - privateDicts[i].fontMatrix[2], - privateDicts[i].fontMatrix[3], - privateDicts[i].fontMatrix[4], - privateDicts[i].fontMatrix[5]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } else { - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - } - buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); - if (privateDicts[i].nBlueValues) { - (*outputFunc)(outputStream, "/BlueValues [", 13); - for (j = 0; j < privateDicts[i].nBlueValues; ++j) { - buf = GString::format("{0:s}{1:d}", - j > 0 ? " " : "", privateDicts[i].blueValues[j]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].nOtherBlues) { - (*outputFunc)(outputStream, "/OtherBlues [", 13); - for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { - buf = GString::format("{0:s}{1:d}", - j > 0 ? " " : "", privateDicts[i].otherBlues[j]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].nFamilyBlues) { - (*outputFunc)(outputStream, "/FamilyBlues [", 14); - for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { - buf = GString::format("{0:s}{1:d}", - j > 0 ? " " : "", - privateDicts[i].familyBlues[j]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].nFamilyOtherBlues) { - (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19); - for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { - buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "", - privateDicts[i].familyOtherBlues[j]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].blueScale != 0.039625) { - buf = GString::format("/BlueScale {0:.4g} def\n", - privateDicts[i].blueScale); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (privateDicts[i].blueShift != 7) { - buf = GString::format("/BlueShift {0:d} def\n", - privateDicts[i].blueShift); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (privateDicts[i].blueFuzz != 1) { - buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[i].blueFuzz); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (privateDicts[i].hasStdHW) { - buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[i].stdHW); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (privateDicts[i].hasStdVW) { - buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[i].stdVW); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (privateDicts[i].nStemSnapH) { - (*outputFunc)(outputStream, "/StemSnapH [", 12); - for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { - buf = GString::format("{0:s}{1:.4g}", - j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].nStemSnapV) { - (*outputFunc)(outputStream, "/StemSnapV [", 12); - for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { - buf = GString::format("{0:s}{1:.4g}", - j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - } - if (privateDicts[i].hasForceBold) { - buf = GString::format("/ForceBold {0:s} def\n", - privateDicts[i].forceBold ? "true" : "false"); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (privateDicts[i].forceBoldThreshold != 0) { - buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", - privateDicts[i].forceBoldThreshold); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (privateDicts[i].languageGroup != 0) { - buf = GString::format("/LanguageGroup {0:d} def\n", - privateDicts[i].languageGroup); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (privateDicts[i].expansionFactor != 0.06) { - buf = GString::format("/ExpansionFactor {0:.4g} def\n", - privateDicts[i].expansionFactor); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "currentdict end def\n", 20); - (*outputFunc)(outputStream, "currentdict end put\n", 20); - } - (*outputFunc)(outputStream, "def\n", 4); - - // start the binary section - offset = (nCIDs + 1) * (1 + gdBytes); - buf = GString::format("(Hex) {0:d} StartData\n", - offset + charStrings->getLength()); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - - // write the charstring offset (CIDMap) table - for (i = 0; i <= nCIDs; i += 6) { - for (j = 0; j < 6 && i+j <= nCIDs; ++j) { - if (i+j < nCIDs && cidMap[i+j] >= 0) { - buf2[0] = (char)fdSelect[cidMap[i+j]]; - } else { - buf2[0] = (char)0; - } - n = offset + charStringOffsets[i+j]; - for (k = gdBytes; k >= 1; --k) { - buf2[k] = (char)(n & 0xff); - n >>= 8; - } - for (k = 0; k <= gdBytes; ++k) { - buf = GString::format("{0:02x}", buf2[k] & 0xff); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - } - (*outputFunc)(outputStream, "\n", 1); - } - - // write the charstring data - n = charStrings->getLength(); - for (i = 0; i < n; i += 32) { - for (j = 0; j < 32 && i+j < n; ++j) { - buf = GString::format("{0:02x}", charStrings->getChar(i+j) & 0xff); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (i + 32 >= n) { - (*outputFunc)(outputStream, ">", 1); - } - (*outputFunc)(outputStream, "\n", 1); - } - - gfree(charStringOffsets); - delete charStrings; - gfree(cidMap); -} - -void FoFiType1C::convertToType0(char *psName, - FoFiOutputFunc outputFunc, - void *outputStream) { - int *cidMap; - Type1CIndex subrIdx; - Type1CIndexVal val; - int nCIDs; - GString *buf; - Type1CEexecBuf eb; - GBool ok; - int fd, i, j, k; - - // compute the CID count and build the CID-to-GID mapping - nCIDs = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] >= nCIDs) { - nCIDs = charset[i] + 1; - } - } - cidMap = (int *)gmallocn(nCIDs, sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - cidMap[i] = -1; - } - for (i = 0; i < nGlyphs; ++i) { - cidMap[charset[i]] = i; - } - - // write the descendant Type 1 fonts - for (i = 0; i < nCIDs; i += 256) { - - //~ this assumes that all CIDs in this block have the same FD -- - //~ to handle multiple FDs correctly, need to somehow divide the - //~ font up by FD; as a kludge we ignore CID 0, which is .notdef - fd = 0; - for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) { - if (cidMap[i+j] >= 0) { - fd = fdSelect[cidMap[i+j]]; - break; - } - } - - // font dictionary (unencrypted section) - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - buf = GString::format("_{0:02x} def\n", i >> 8); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - if (privateDicts[fd].hasFontMatrix) { - buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", - privateDicts[fd].fontMatrix[0], - privateDicts[fd].fontMatrix[1], - privateDicts[fd].fontMatrix[2], - privateDicts[fd].fontMatrix[3], - privateDicts[fd].fontMatrix[4], - privateDicts[fd].fontMatrix[5]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } else if (topDict.hasFontMatrix) { - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - } else { - (*outputFunc)(outputStream, - "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); - } - buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - if (topDict.paintType != 0) { - buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - if (j < 256) { - buf = GString::format("{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n", - j); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "readonly def\n", 13); - (*outputFunc)(outputStream, "currentdict end\n", 16); - - // start the binary section - (*outputFunc)(outputStream, "currentfile eexec\n", 18); - eb.outputFunc = outputFunc; - eb.outputStream = outputStream; - eb.ascii = gTrue; - eb.r1 = 55665; - eb.line = 0; - - // start the private dictionary - eexecWrite(&eb, "\x83\xca\x73\xd5"); - eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); - eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" - " executeonly def\n"); - eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); - eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); - eexecWrite(&eb, "/MinFeature {16 16} def\n"); - eexecWrite(&eb, "/password 5839 def\n"); - if (privateDicts[fd].nBlueValues) { - eexecWrite(&eb, "/BlueValues ["); - for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { - buf = GString::format("{0:s}{1:d}", - k > 0 ? " " : "", - privateDicts[fd].blueValues[k]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].nOtherBlues) { - eexecWrite(&eb, "/OtherBlues ["); - for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { - buf = GString::format("{0:s}{1:d}", - k > 0 ? " " : "", - privateDicts[fd].otherBlues[k]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].nFamilyBlues) { - eexecWrite(&eb, "/FamilyBlues ["); - for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { - buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", - privateDicts[fd].familyBlues[k]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].nFamilyOtherBlues) { - eexecWrite(&eb, "/FamilyOtherBlues ["); - for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { - buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", - privateDicts[fd].familyOtherBlues[k]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].blueScale != 0.039625) { - buf = GString::format("/BlueScale {0:.4g} def\n", - privateDicts[fd].blueScale); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[fd].blueShift != 7) { - buf = GString::format("/BlueShift {0:d} def\n", - privateDicts[fd].blueShift); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[fd].blueFuzz != 1) { - buf = GString::format("/BlueFuzz {0:d} def\n", - privateDicts[fd].blueFuzz); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[fd].hasStdHW) { - buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[fd].hasStdVW) { - buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[fd].stdVW); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[fd].nStemSnapH) { - eexecWrite(&eb, "/StemSnapH ["); - for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { - buf = GString::format("{0:s}{1:.4g}", - k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].nStemSnapV) { - eexecWrite(&eb, "/StemSnapV ["); - for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { - buf = GString::format("{0:s}{1:.4g}", - k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - eexecWrite(&eb, "] def\n"); - } - if (privateDicts[fd].hasForceBold) { - buf = GString::format("/ForceBold {0:s} def\n", - privateDicts[fd].forceBold ? "true" : "false"); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[fd].forceBoldThreshold != 0) { - buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", - privateDicts[fd].forceBoldThreshold); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[fd].languageGroup != 0) { - buf = GString::format("/LanguageGroup {0:d} def\n", - privateDicts[fd].languageGroup); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - if (privateDicts[fd].expansionFactor != 0.06) { - buf = GString::format("/ExpansionFactor {0:.4g} def\n", - privateDicts[fd].expansionFactor); - eexecWrite(&eb, buf->getCString()); - delete buf; - } - - // set up the subroutines - ok = gTrue; - getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok); - if (!ok) { - subrIdx.pos = -1; - } - - // start the CharStrings - eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n"); - - // write the .notdef CharString - ok = gTrue; - getIndexVal(&charStringsIdx, 0, &val, &ok); - if (ok) { - eexecCvtGlyph(&eb, ".notdef", val.pos, val.len, - &subrIdx, &privateDicts[fd]); - } - - // write the CharStrings - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - if (cidMap[i+j] >= 0) { - ok = gTrue; - getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok); - if (ok) { - buf = GString::format("c{0:02x}", j); - eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len, - &subrIdx, &privateDicts[fd]); - delete buf; - } - } - } - eexecWrite(&eb, "end\n"); - eexecWrite(&eb, "end\n"); - eexecWrite(&eb, "readonly put\n"); - eexecWrite(&eb, "noaccess put\n"); - eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); - eexecWrite(&eb, "mark currentfile closefile\n"); - - // trailer - if (eb.line > 0) { - (*outputFunc)(outputStream, "\n", 1); - } - for (j = 0; j < 8; ++j) { - (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); - } - (*outputFunc)(outputStream, "cleartomark\n", 12); - } - - // write the Type 0 parent font - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 0 def\n", 16); - if (topDict.hasFontMatrix) { - buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], - topDict.fontMatrix[2], topDict.fontMatrix[3], - topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } else { - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - } - (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); - (*outputFunc)(outputStream, "/Encoding [\n", 12); - for (i = 0; i < nCIDs; i += 256) { - buf = GString::format("{0:d}\n", i >> 8); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "/FDepVector [\n", 14); - for (i = 0; i < nCIDs; i += 256) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, psName, strlen(psName)); - buf = GString::format("_{0:02x} findfont\n", i >> 8); - (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); - delete buf; - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); - - gfree(cidMap); -} - -void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName, - int offset, int nBytes, - Type1CIndex *subrIdx, - Type1CPrivateDict *pDict) { - GString *buf; - GString *charBuf; - - // generate the charstring - charBuf = new GString(); - cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue); - - buf = GString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength()); - eexecWrite(eb, buf->getCString()); - delete buf; - eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(), - charBuf->getLength()); - eexecWrite(eb, " ND\n"); - - delete charBuf; -} - -void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, - Type1CIndex *subrIdx, Type1CPrivateDict *pDict, - GBool top) { - Type1CIndexVal val; - GBool ok, dFP; - double d, dx, dy; - Gushort r2; - Guchar byte; - int pos, subrBias, start, i, k; - - start = charBuf->getLength(); - if (top) { - charBuf->append((char)73); - charBuf->append((char)58); - charBuf->append((char)147); - charBuf->append((char)134); - nOps = 0; - nHints = 0; - firstOp = gTrue; - openPath = gFalse; - } - - pos = offset; - while (pos < offset + nBytes) { - ok = gTrue; - pos = getOp(pos, gTrue, &ok); - if (!ok) { - break; - } - if (!ops[nOps - 1].isNum) { - --nOps; // drop the operator - switch (ops[nOps].op) { - case 0x0001: // hstem - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints - if (ops[k+1].num < 0) { - d += ops[k].num + ops[k+1].num; - dFP |= ops[k].isFP | ops[k+1].isFP; - cvtNum(d, dFP, charBuf); - cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); - } else { - d += ops[k].num; - dFP |= ops[k].isFP; - cvtNum(d, dFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - d += ops[k+1].num; - dFP |= ops[k+1].isFP; - } - charBuf->append((char)1); - } - nHints += nOps / 2; - nOps = 0; - break; - case 0x0003: // vstem - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints - if (ops[k+1].num < 0) { - d += ops[k].num + ops[k+1].num; - dFP |= ops[k].isFP | ops[k+1].isFP; - cvtNum(d, dFP, charBuf); - cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); - } else { - d += ops[k].num; - dFP |= ops[k].isFP; - cvtNum(d, dFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - d += ops[k+1].num; - dFP |= ops[k+1].isFP; - } - charBuf->append((char)3); - } - nHints += nOps / 2; - nOps = 0; - break; - case 0x0004: // vmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 2, charBuf, pDict); - firstOp = gFalse; - } - if (openPath) { - charBuf->append((char)9); - openPath = gFalse; - } - if (nOps != 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - charBuf->append((char)4); - nOps = 0; - break; - case 0x0005: // rlineto - if (nOps < 2 || nOps % 2 != 0) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); - } - for (k = 0; k < nOps; k += 2) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - charBuf->append((char)5); - } - nOps = 0; - openPath = gTrue; - break; - case 0x0006: // hlineto - if (nOps < 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); - } - for (k = 0; k < nOps; ++k) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - charBuf->append((char)((k & 1) ? 7 : 6)); - } - nOps = 0; - openPath = gTrue; - break; - case 0x0007: // vlineto - if (nOps < 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); - } - for (k = 0; k < nOps; ++k) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - charBuf->append((char)((k & 1) ? 6 : 7)); - } - nOps = 0; - openPath = gTrue; - break; - case 0x0008: // rrcurveto - if (nOps < 6 || nOps % 6 != 0) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); - } - for (k = 0; k < nOps; k += 6) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x000a: // callsubr - if (nOps >= 1) { - subrBias = (subrIdx->len < 1240) - ? 107 : (subrIdx->len < 33900) ? 1131 : 32768; - k = subrBias + (int)ops[nOps - 1].num; - --nOps; - ok = gTrue; - getIndexVal(subrIdx, k, &val, &ok); - if (ok) { - cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); - } - } else { - //~ error(-1, "Too few args to Type 2 callsubr"); - } - // don't clear the stack - break; - case 0x000b: // return - // don't clear the stack - break; - case 0x000e: // endchar / seac - if (firstOp) { - cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict); - firstOp = gFalse; - } - if (openPath) { - charBuf->append((char)9); - openPath = gFalse; - } - if (nOps == 4) { - cvtNum(0, gFalse, charBuf); - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - charBuf->append((char)12)->append((char)6); - } else if (nOps == 0) { - charBuf->append((char)14); - } else { - //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); - } - nOps = 0; - break; - case 0x000f: // (obsolete) - // this op is ignored, but we need the glyph width - if (firstOp) { - cvtGlyphWidth(nOps > 0, charBuf, pDict); - firstOp = gFalse; - } - nOps = 0; - break; - case 0x0010: // blend - //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); - nOps = 0; - break; - case 0x0012: // hstemhm - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); - } - nHints += nOps / 2; - nOps = 0; - break; - case 0x0013: // hintmask - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", - //~ nOps); - } - nHints += nOps / 2; - } - pos += (nHints + 7) >> 3; - nOps = 0; - break; - case 0x0014: // cntrmask - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", - //~ nOps); - } - nHints += nOps / 2; - } - pos += (nHints + 7) >> 3; - nOps = 0; - break; - case 0x0015: // rmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 3, charBuf, pDict); - firstOp = gFalse; - } - if (openPath) { - charBuf->append((char)9); - openPath = gFalse; - } - if (nOps != 2) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - charBuf->append((char)21); - nOps = 0; - break; - case 0x0016: // hmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 2, charBuf, pDict); - firstOp = gFalse; - } - if (openPath) { - charBuf->append((char)9); - openPath = gFalse; - } - if (nOps != 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - charBuf->append((char)22); - nOps = 0; - break; - case 0x0017: // vstemhm - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1, charBuf, pDict); - firstOp = gFalse; - } - if (nOps & 1) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); - } - nHints += nOps / 2; - nOps = 0; - break; - case 0x0018: // rcurveline - if (nOps < 8 || (nOps - 2) % 6 != 0) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); - } - for (k = 0; k < nOps - 2; k += 6) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); - charBuf->append((char)8); - } - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k].isFP, charBuf); - charBuf->append((char)5); - nOps = 0; - openPath = gTrue; - break; - case 0x0019: // rlinecurve - if (nOps < 8 || (nOps - 6) % 2 != 0) { - //~ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); - } - for (k = 0; k < nOps - 6; k += 2) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k].isFP, charBuf); - charBuf->append((char)5); - } - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - case 0x001a: // vvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); - } - if (nOps % 2 == 1) { - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - charBuf->append((char)8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x001b: // hhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); - } - if (nOps % 2 == 1) { - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x001d: // callgsubr - if (nOps >= 1) { - k = gsubrBias + (int)ops[nOps - 1].num; - --nOps; - ok = gTrue; - getIndexVal(&gsubrIdx, k, &val, &ok); - if (ok) { - cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); - } - } else { - //~ error(-1, "Too few args to Type 2 callgsubr"); - } - // don't clear the stack - break; - case 0x001e: // vhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - //~ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); - } - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)30); - } else { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)31); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - } else { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - } - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x001f: // hvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); - } - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)31); - } else { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - charBuf->append((char)30); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - } else { - cvtNum(0, gFalse, charBuf); - cvtNum(ops[k].num, ops[k].isFP, charBuf); - cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); - cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); - cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); - cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); - } - charBuf->append((char)8); - } - nOps = 0; - openPath = gTrue; - break; - case 0x0c00: // dotsection (should be Type 1 only?) - // ignored - nOps = 0; - break; - case 0x0c03: // and - case 0x0c04: // or - case 0x0c05: // not - case 0x0c08: // store - case 0x0c09: // abs - case 0x0c0a: // add - case 0x0c0b: // sub - case 0x0c0c: // div - case 0x0c0d: // load - case 0x0c0e: // neg - case 0x0c0f: // eq - case 0x0c12: // drop - case 0x0c14: // put - case 0x0c15: // get - case 0x0c16: // ifelse - case 0x0c17: // random - case 0x0c18: // mul - case 0x0c1a: // sqrt - case 0x0c1b: // dup - case 0x0c1c: // exch - case 0x0c1d: // index - case 0x0c1e: // roll - //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); - nOps = 0; - break; - case 0x0c22: // hflex - if (nOps != 7) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[5].num, ops[5].isFP, charBuf); - cvtNum(-ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[6].num, ops[6].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - case 0x0c23: // flex - if (nOps != 13) { - //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(ops[5].num, ops[5].isFP, charBuf); - charBuf->append((char)8); - cvtNum(ops[6].num, ops[6].isFP, charBuf); - cvtNum(ops[7].num, ops[7].isFP, charBuf); - cvtNum(ops[8].num, ops[8].isFP, charBuf); - cvtNum(ops[9].num, ops[9].isFP, charBuf); - cvtNum(ops[10].num, ops[10].isFP, charBuf); - cvtNum(ops[11].num, ops[11].isFP, charBuf); - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - case 0x0c24: // hflex1 - if (nOps != 9) { - //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - charBuf->append((char)8); - cvtNum(ops[5].num, ops[5].isFP, charBuf); - cvtNum(0, gFalse, charBuf); - cvtNum(ops[6].num, ops[6].isFP, charBuf); - cvtNum(ops[7].num, ops[7].isFP, charBuf); - cvtNum(ops[8].num, ops[8].isFP, charBuf); - cvtNum(-(ops[1].num + ops[3].num + ops[7].num), - ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf); - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - case 0x0c25: // flex1 - if (nOps != 11) { - //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); - } - cvtNum(ops[0].num, ops[0].isFP, charBuf); - cvtNum(ops[1].num, ops[1].isFP, charBuf); - cvtNum(ops[2].num, ops[2].isFP, charBuf); - cvtNum(ops[3].num, ops[3].isFP, charBuf); - cvtNum(ops[4].num, ops[4].isFP, charBuf); - cvtNum(ops[5].num, ops[5].isFP, charBuf); - charBuf->append((char)8); - cvtNum(ops[6].num, ops[6].isFP, charBuf); - cvtNum(ops[7].num, ops[7].isFP, charBuf); - cvtNum(ops[8].num, ops[8].isFP, charBuf); - cvtNum(ops[9].num, ops[9].isFP, charBuf); - dx = ops[0].num + ops[2].num + ops[4].num + ops[6].num + ops[8].num; - dy = ops[1].num + ops[3].num + ops[5].num + ops[7].num + ops[9].num; - if (fabs(dx) > fabs(dy)) { - cvtNum(ops[10].num, ops[10].isFP, charBuf); - cvtNum(-dy, ops[1].isFP | ops[3].isFP | ops[5].isFP | - ops[7].isFP | ops[9].isFP, charBuf); - } else { - cvtNum(-dx, ops[0].isFP | ops[2].isFP | ops[4].isFP | - ops[6].isFP | ops[8].isFP, charBuf); - cvtNum(ops[10].num, ops[10].isFP, charBuf); - } - charBuf->append((char)8); - nOps = 0; - openPath = gTrue; - break; - default: - //~ error(-1, "Illegal Type 2 charstring op: %04x", - //~ ops[nOps].op); - nOps = 0; - break; - } - } - } - - // charstring encryption - if (top) { - r2 = 4330; - for (i = start; i < charBuf->getLength(); ++i) { - byte = charBuf->getChar(i) ^ (r2 >> 8); - charBuf->setChar(i, byte); - r2 = (byte + r2) * 52845 + 22719; - } - } -} - -void FoFiType1C::cvtGlyphWidth(GBool useOp, GString *charBuf, - Type1CPrivateDict *pDict) { - double w; - GBool wFP; - int i; - - if (useOp) { - w = pDict->nominalWidthX + ops[0].num; - wFP = pDict->nominalWidthXFP | ops[0].isFP; - for (i = 1; i < nOps; ++i) { - ops[i-1] = ops[i]; - } - --nOps; - } else { - w = pDict->defaultWidthX; - wFP = pDict->defaultWidthXFP; - } - cvtNum(0, gFalse, charBuf); - cvtNum(w, wFP, charBuf); - charBuf->append((char)13); -} - -void FoFiType1C::cvtNum(double x, GBool isFP, GString *charBuf) { - Guchar buf[12]; - int y, n; - - n = 0; - if (isFP) { - if (x >= -32768 && x < 32768) { - y = (int)(x * 256.0); - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - buf[5] = 255; - buf[6] = 0; - buf[7] = 0; - buf[8] = 1; - buf[9] = 0; - buf[10] = 12; - buf[11] = 12; - n = 12; - } else { - //~ error(-1, "Type 2 fixed point constant out of range"); - } - } else { - y = (int)x; - if (y >= -107 && y <= 107) { - buf[0] = (Guchar)(y + 139); - n = 1; - } else if (y > 107 && y <= 1131) { - y -= 108; - buf[0] = (Guchar)((y >> 8) + 247); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else if (y < -107 && y >= -1131) { - y = -y - 108; - buf[0] = (Guchar)((y >> 8) + 251); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else { - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - n = 5; - } - } - charBuf->append((char *)buf, n); -} - -void FoFiType1C::eexecWrite(Type1CEexecBuf *eb, char *s) { - Guchar *p; - Guchar x; - - for (p = (Guchar *)s; *p; ++p) { - x = *p ^ (eb->r1 >> 8); - eb->r1 = (x + eb->r1) * 52845 + 22719; - if (eb->ascii) { - (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); - (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); - eb->line += 2; - if (eb->line == 64) { - (*eb->outputFunc)(eb->outputStream, "\n", 1); - eb->line = 0; - } - } else { - (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); - } - } -} - -void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb, - Guchar *s, int n) { - Guchar x; - int i; - - // eexec encryption - for (i = 0; i < n; ++i) { - x = s[i] ^ (eb->r1 >> 8); - eb->r1 = (x + eb->r1) * 52845 + 22719; - if (eb->ascii) { - (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); - (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); - eb->line += 2; - if (eb->line == 64) { - (*eb->outputFunc)(eb->outputStream, "\n", 1); - eb->line = 0; - } - } else { - (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); - } - } -} - -GBool FoFiType1C::parse() { - Type1CIndex fdIdx; - Type1CIndexVal val; - int i; - - parsedOk = gTrue; - - // some tools embed Type 1C fonts with an extra whitespace char at - // the beginning - if (len > 0 && file[0] != '\x01') { - ++file; - --len; - } - - // find the indexes - getIndex(getU8(2, &parsedOk), &nameIdx, &parsedOk); - getIndex(nameIdx.endPos, &topDictIdx, &parsedOk); - getIndex(topDictIdx.endPos, &stringIdx, &parsedOk); - getIndex(stringIdx.endPos, &gsubrIdx, &parsedOk); - if (!parsedOk) { - return gFalse; - } - gsubrBias = (gsubrIdx.len < 1240) ? 107 - : (gsubrIdx.len < 33900) ? 1131 : 32768; - - // read the first font name - getIndexVal(&nameIdx, 0, &val, &parsedOk); - if (!parsedOk) { - return gFalse; - } - name = new GString((char *)&file[val.pos], val.len); - - // read the top dict for the first font - readTopDict(); - - // for CID fonts: read the FDArray dicts and private dicts - if (topDict.firstOp == 0x0c1e) { - if (topDict.fdArrayOffset == 0) { - nFDs = 1; - privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); - readPrivateDict(0, 0, &privateDicts[0]); - } else { - getIndex(topDict.fdArrayOffset, &fdIdx, &parsedOk); - if (!parsedOk) { - return gFalse; - } - nFDs = fdIdx.len; - privateDicts = (Type1CPrivateDict *) - gmallocn(nFDs, sizeof(Type1CPrivateDict)); - for (i = 0; i < nFDs; ++i) { - getIndexVal(&fdIdx, i, &val, &parsedOk); - if (!parsedOk) { - return gFalse; - } - readFD(val.pos, val.len, &privateDicts[i]); - } - } - - // for 8-bit fonts: read the private dict - } else { - privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); - readPrivateDict(topDict.privateOffset, topDict.privateSize, - &privateDicts[0]); - } - - // check for parse errors in the private dict(s) - if (!parsedOk) { - return gFalse; - } - - // get the charstrings index - if (topDict.charStringsOffset <= 0) { - parsedOk = gFalse; - return gFalse; - } - getIndex(topDict.charStringsOffset, &charStringsIdx, &parsedOk); - if (!parsedOk) { - return gFalse; - } - nGlyphs = charStringsIdx.len; - - // for CID fonts: read the FDSelect table - if (topDict.firstOp == 0x0c1e) { - readFDSelect(); - if (!parsedOk) { - return gFalse; - } - } - - // read the charset - if (!readCharset()) { - parsedOk = gFalse; - return gFalse; - } - - // for 8-bit fonts: build the encoding - if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) { - buildEncoding(); - if (!parsedOk) { - return gFalse; - } - } - - return parsedOk; -} - -void FoFiType1C::readTopDict() { - Type1CIndexVal topDictPtr; - int pos; - - topDict.firstOp = -1; - topDict.versionSID = 0; - topDict.noticeSID = 0; - topDict.copyrightSID = 0; - topDict.fullNameSID = 0; - topDict.familyNameSID = 0; - topDict.weightSID = 0; - topDict.isFixedPitch = 0; - topDict.italicAngle = 0; - topDict.underlinePosition = -100; - topDict.underlineThickness = 50; - topDict.paintType = 0; - topDict.charstringType = 2; - topDict.fontMatrix[0] = 0.001; - topDict.fontMatrix[1] = 0; - topDict.fontMatrix[2] = 0; - topDict.fontMatrix[3] = 0.001; - topDict.fontMatrix[4] = 0; - topDict.fontMatrix[5] = 0; - topDict.hasFontMatrix = gFalse; - topDict.uniqueID = 0; - topDict.fontBBox[0] = 0; - topDict.fontBBox[1] = 0; - topDict.fontBBox[2] = 0; - topDict.fontBBox[3] = 0; - topDict.strokeWidth = 0; - topDict.charsetOffset = 0; - topDict.encodingOffset = 0; - topDict.charStringsOffset = 0; - topDict.privateSize = 0; - topDict.privateOffset = 0; - topDict.registrySID = 0; - topDict.orderingSID = 0; - topDict.supplement = 0; - topDict.fdArrayOffset = 0; - topDict.fdSelectOffset = 0; - - getIndexVal(&topDictIdx, 0, &topDictPtr, &parsedOk); - pos = topDictPtr.pos; - nOps = 0; - while (pos < topDictPtr.pos + topDictPtr.len) { - pos = getOp(pos, gFalse, &parsedOk); - if (!parsedOk) { - break; - } - if (!ops[nOps - 1].isNum) { - --nOps; // drop the operator - if (topDict.firstOp < 0) { - topDict.firstOp = ops[nOps].op; - } - switch (ops[nOps].op) { - case 0x0000: topDict.versionSID = (int)ops[0].num; break; - case 0x0001: topDict.noticeSID = (int)ops[0].num; break; - case 0x0c00: topDict.copyrightSID = (int)ops[0].num; break; - case 0x0002: topDict.fullNameSID = (int)ops[0].num; break; - case 0x0003: topDict.familyNameSID = (int)ops[0].num; break; - case 0x0004: topDict.weightSID = (int)ops[0].num; break; - case 0x0c01: topDict.isFixedPitch = (int)ops[0].num; break; - case 0x0c02: topDict.italicAngle = ops[0].num; break; - case 0x0c03: topDict.underlinePosition = ops[0].num; break; - case 0x0c04: topDict.underlineThickness = ops[0].num; break; - case 0x0c05: topDict.paintType = (int)ops[0].num; break; - case 0x0c06: topDict.charstringType = (int)ops[0].num; break; - case 0x0c07: topDict.fontMatrix[0] = ops[0].num; - topDict.fontMatrix[1] = ops[1].num; - topDict.fontMatrix[2] = ops[2].num; - topDict.fontMatrix[3] = ops[3].num; - topDict.fontMatrix[4] = ops[4].num; - topDict.fontMatrix[5] = ops[5].num; - topDict.hasFontMatrix = gTrue; break; - case 0x000d: topDict.uniqueID = (int)ops[0].num; break; - case 0x0005: topDict.fontBBox[0] = ops[0].num; - topDict.fontBBox[1] = ops[1].num; - topDict.fontBBox[2] = ops[2].num; - topDict.fontBBox[3] = ops[3].num; break; - case 0x0c08: topDict.strokeWidth = ops[0].num; break; - case 0x000f: topDict.charsetOffset = (int)ops[0].num; break; - case 0x0010: topDict.encodingOffset = (int)ops[0].num; break; - case 0x0011: topDict.charStringsOffset = (int)ops[0].num; break; - case 0x0012: topDict.privateSize = (int)ops[0].num; - topDict.privateOffset = (int)ops[1].num; break; - case 0x0c1e: topDict.registrySID = (int)ops[0].num; - topDict.orderingSID = (int)ops[1].num; - topDict.supplement = (int)ops[2].num; break; - case 0x0c24: topDict.fdArrayOffset = (int)ops[0].num; break; - case 0x0c25: topDict.fdSelectOffset = (int)ops[0].num; break; - } - nOps = 0; - } - } -} - -// Read a CID font dict (FD) - this pulls out the private dict -// pointer, and reads the private dict. It also pulls the FontMatrix -// (if any) out of the FD. -void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { - int pos, pSize, pOffset; - double fontMatrix[6]; - GBool hasFontMatrix; - - hasFontMatrix = gFalse; - pSize = pOffset = 0; - pos = offset; - nOps = 0; - while (pos < offset + length) { - pos = getOp(pos, gFalse, &parsedOk); - if (!parsedOk) { - return; - } - if (!ops[nOps - 1].isNum) { - if (ops[nOps - 1].op == 0x0012) { - if (nOps < 3) { - parsedOk = gFalse; - return; - } - pSize = (int)ops[0].num; - pOffset = (int)ops[1].num; - break; - } else if (ops[nOps - 1].op == 0x0c07) { - fontMatrix[0] = ops[0].num; - fontMatrix[1] = ops[1].num; - fontMatrix[2] = ops[2].num; - fontMatrix[3] = ops[3].num; - fontMatrix[4] = ops[4].num; - fontMatrix[5] = ops[5].num; - hasFontMatrix = gTrue; - } - nOps = 0; - } - } - readPrivateDict(pOffset, pSize, pDict); - if (hasFontMatrix) { - pDict->fontMatrix[0] = fontMatrix[0]; - pDict->fontMatrix[1] = fontMatrix[1]; - pDict->fontMatrix[2] = fontMatrix[2]; - pDict->fontMatrix[3] = fontMatrix[3]; - pDict->fontMatrix[4] = fontMatrix[4]; - pDict->fontMatrix[5] = fontMatrix[5]; - pDict->hasFontMatrix = gTrue; - } -} - -void FoFiType1C::readPrivateDict(int offset, int length, - Type1CPrivateDict *pDict) { - int pos; - - pDict->hasFontMatrix = gFalse; - pDict->nBlueValues = 0; - pDict->nOtherBlues = 0; - pDict->nFamilyBlues = 0; - pDict->nFamilyOtherBlues = 0; - pDict->blueScale = 0.039625; - pDict->blueShift = 7; - pDict->blueFuzz = 1; - pDict->hasStdHW = gFalse; - pDict->hasStdVW = gFalse; - pDict->nStemSnapH = 0; - pDict->nStemSnapV = 0; - pDict->hasForceBold = gFalse; - pDict->forceBoldThreshold = 0; - pDict->languageGroup = 0; - pDict->expansionFactor = 0.06; - pDict->initialRandomSeed = 0; - pDict->subrsOffset = 0; - pDict->defaultWidthX = 0; - pDict->defaultWidthXFP = gFalse; - pDict->nominalWidthX = 0; - pDict->nominalWidthXFP = gFalse; - - // no dictionary - if (offset == 0 || length == 0) { - return; - } - - pos = offset; - nOps = 0; - while (pos < offset + length) { - pos = getOp(pos, gFalse, &parsedOk); - if (!parsedOk) { - break; - } - if (!ops[nOps - 1].isNum) { - --nOps; // drop the operator - switch (ops[nOps].op) { - case 0x0006: - pDict->nBlueValues = getDeltaIntArray(pDict->blueValues, - type1CMaxBlueValues); - break; - case 0x0007: - pDict->nOtherBlues = getDeltaIntArray(pDict->otherBlues, - type1CMaxOtherBlues); - break; - case 0x0008: - pDict->nFamilyBlues = getDeltaIntArray(pDict->familyBlues, - type1CMaxBlueValues); - break; - case 0x0009: - pDict->nFamilyOtherBlues = getDeltaIntArray(pDict->familyOtherBlues, - type1CMaxOtherBlues); - break; - case 0x0c09: - pDict->blueScale = ops[0].num; - break; - case 0x0c0a: - pDict->blueShift = (int)ops[0].num; - break; - case 0x0c0b: - pDict->blueFuzz = (int)ops[0].num; - break; - case 0x000a: - pDict->stdHW = ops[0].num; - pDict->hasStdHW = gTrue; - break; - case 0x000b: - pDict->stdVW = ops[0].num; - pDict->hasStdVW = gTrue; - break; - case 0x0c0c: - pDict->nStemSnapH = getDeltaFPArray(pDict->stemSnapH, - type1CMaxStemSnap); - break; - case 0x0c0d: - pDict->nStemSnapV = getDeltaFPArray(pDict->stemSnapV, - type1CMaxStemSnap); - break; - case 0x0c0e: - pDict->forceBold = ops[0].num != 0; - pDict->hasForceBold = gTrue; - break; - case 0x0c0f: - pDict->forceBoldThreshold = ops[0].num; - break; - case 0x0c11: - pDict->languageGroup = (int)ops[0].num; - break; - case 0x0c12: - pDict->expansionFactor = ops[0].num; - break; - case 0x0c13: - pDict->initialRandomSeed = (int)ops[0].num; - break; - case 0x0013: - pDict->subrsOffset = offset + (int)ops[0].num; - break; - case 0x0014: - pDict->defaultWidthX = ops[0].num; - pDict->defaultWidthXFP = ops[0].isFP; - break; - case 0x0015: - pDict->nominalWidthX = ops[0].num; - pDict->nominalWidthXFP = ops[0].isFP; - break; - } - nOps = 0; - } - } -} - -void FoFiType1C::readFDSelect() { - int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j; - - fdSelect = (Guchar *)gmalloc(nGlyphs); - if (topDict.fdSelectOffset == 0) { - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } else { - pos = topDict.fdSelectOffset; - fdSelectFmt = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - if (fdSelectFmt == 0) { - if (!checkRegion(pos, nGlyphs)) { - parsedOk = gFalse; - return; - } - memcpy(fdSelect, file + pos, nGlyphs); - } else if (fdSelectFmt == 3) { - nRanges = getU16BE(pos, &parsedOk); - pos += 2; - gid0 = getU16BE(pos, &parsedOk); - pos += 2; - for (i = 1; i <= nRanges; ++i) { - fd = getU8(pos++, &parsedOk); - gid1 = getU16BE(pos, &parsedOk); - if (!parsedOk) { - return; - } - pos += 2; - if (gid0 > gid1 || gid1 > nGlyphs) { - //~ error(-1, "Bad FDSelect table in CID font"); - parsedOk = gFalse; - return; - } - for (j = gid0; j < gid1; ++j) { - fdSelect[j] = fd; - } - gid0 = gid1; - } - } else { - //~ error(-1, "Unknown FDSelect table format in CID font"); - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } - } -} - -void FoFiType1C::buildEncoding() { - char buf[256]; - int nCodes, nRanges, encFormat; - int pos, c, sid, nLeft, nSups, i, j; - - if (topDict.encodingOffset == 0) { - encoding = fofiType1StandardEncoding; - - } else if (topDict.encodingOffset == 1) { - encoding = fofiType1ExpertEncoding; - - } else { - encoding = (char **)gmallocn(256, sizeof(char *)); - for (i = 0; i < 256; ++i) { - encoding[i] = NULL; - } - pos = topDict.encodingOffset; - encFormat = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - if ((encFormat & 0x7f) == 0) { - nCodes = 1 + getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - if (nCodes > nGlyphs) { - nCodes = nGlyphs; - } - for (i = 1; i < nCodes; ++i) { - c = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(charset[i], buf, &parsedOk)); - } - } else if ((encFormat & 0x7f) == 1) { - nRanges = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - nCodes = 1; - for (i = 0; i < nRanges; ++i) { - c = getU8(pos++, &parsedOk); - nLeft = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { - if (c < 256) { - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(charset[nCodes], buf, - &parsedOk)); - } - ++nCodes; - ++c; - } - } - } - if (encFormat & 0x80) { - nSups = getU8(pos++, &parsedOk); - if (!parsedOk) { - return; - } - for (i = 0; i < nSups; ++i) { - c = getU8(pos++, &parsedOk);; - if (!parsedOk) { - return;; - } - sid = getU16BE(pos, &parsedOk); - pos += 2; - if (!parsedOk) { - return; - } - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(sid, buf, &parsedOk)); - } - } - } -} - -GBool FoFiType1C::readCharset() { - int charsetFormat, c, pos; - int nLeft, i, j; - - if (topDict.charsetOffset == 0) { - charset = fofiType1CISOAdobeCharset; - } else if (topDict.charsetOffset == 1) { - charset = fofiType1CExpertCharset; - } else if (topDict.charsetOffset == 2) { - charset = fofiType1CExpertSubsetCharset; - } else { - charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); - for (i = 0; i < nGlyphs; ++i) { - charset[i] = 0; - } - pos = topDict.charsetOffset; - charsetFormat = getU8(pos++, &parsedOk); - if (charsetFormat == 0) { - for (i = 1; i < nGlyphs; ++i) { - charset[i] = (Gushort)getU16BE(pos, &parsedOk); - pos += 2; - if (!parsedOk) { - break; - } - } - } else if (charsetFormat == 1) { - i = 1; - while (i < nGlyphs) { - c = getU16BE(pos, &parsedOk); - pos += 2; - nLeft = getU8(pos++, &parsedOk); - if (!parsedOk) { - break; - } - for (j = 0; j <= nLeft && i < nGlyphs; ++j) { - charset[i++] = (Gushort)c++; - } - } - } else if (charsetFormat == 2) { - i = 1; - while (i < nGlyphs) { - c = getU16BE(pos, &parsedOk); - pos += 2; - nLeft = getU16BE(pos, &parsedOk); - pos += 2; - if (!parsedOk) { - break; - } - for (j = 0; j <= nLeft && i < nGlyphs; ++j) { - charset[i++] = (Gushort)c++; - } - } - } - if (!parsedOk) { - gfree(charset); - charset = NULL; - return gFalse; - } - } - return gTrue; -} - -int FoFiType1C::getOp(int pos, GBool charstring, GBool *ok) { - static char nybChars[16] = "0123456789.ee -"; - Type1COp op; - char buf[65]; - int b0, b1, nyb0, nyb1, x, i; - - b0 = getU8(pos++, ok); - op.isNum = gTrue; - op.isFP = gFalse; - - if (b0 == 28) { - x = getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - if (x & 0x8000) { - x |= ~0xffff; - } - op.num = x; - - } else if (!charstring && b0 == 29) { - x = getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - if (x & 0x80000000) { - x |= ~0xffffffff; - } - op.num = x; - - } else if (!charstring && b0 == 30) { - i = 0; - do { - b1 = getU8(pos++, ok); - nyb0 = b1 >> 4; - nyb1 = b1 & 0x0f; - if (nyb0 == 0xf) { - break; - } - buf[i++] = nybChars[nyb0]; - if (i == 64) { - break; - } - if (nyb0 == 0xc) { - buf[i++] = '-'; - } - if (i == 64) { - break; - } - if (nyb1 == 0xf) { - break; - } - buf[i++] = nybChars[nyb1]; - if (i == 64) { - break; - } - if (nyb1 == 0xc) { - buf[i++] = '-'; - } - } while (i < 64); - buf[i] = '\0'; - op.num = atof(buf); - op.isFP = gTrue; - - } else if (b0 >= 32 && b0 <= 246) { - op.num = b0 - 139; - - } else if (b0 >= 247 && b0 <= 250) { - op.num = ((b0 - 247) << 8) + getU8(pos++, ok) + 108; - - } else if (b0 >= 251 && b0 <= 254) { - op.num = -((b0 - 251) << 8) - getU8(pos++, ok) - 108; - - } else if (charstring && b0 == 255) { - x = getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - x = (x << 8) | getU8(pos++, ok); - if (x & 0x80000000) { - x |= ~0xffffffff; - } - op.num = (double)x / 65536.0; - op.isFP = gTrue; - - } else if (b0 == 12) { - op.isNum = gFalse; - op.op = 0x0c00 + getU8(pos++, ok); - - } else { - op.isNum = gFalse; - op.op = b0; - } - - if (nOps < 49) { - ops[nOps++] = op; - } - - return pos; -} - -// Convert the delta-encoded ops array to an array of ints. -int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) { - int x; - int n, i; - - if ((n = nOps) > maxLen) { - n = maxLen; - } - x = 0; - for (i = 0; i < n; ++i) { - x += (int)ops[i].num; - arr[i] = x; - } - return n; -} - -// Convert the delta-encoded ops array to an array of doubles. -int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) { - double x; - int n, i; - - if ((n = nOps) > maxLen) { - n = maxLen; - } - x = 0; - for (i = 0; i < n; ++i) { - x += ops[i].num; - arr[i] = x; - } - return n; -} - -void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) { - idx->pos = pos; - idx->len = getU16BE(pos, ok); - if (idx->len == 0) { - // empty indexes are legal and contain just the length field - idx->offSize = 0; - idx->startPos = idx->endPos = pos + 2; - } else { - idx->offSize = getU8(pos + 2, ok); - if (idx->offSize < 1 || idx->offSize > 4) { - *ok = gFalse; - } - idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1; - if (idx->startPos < 0 || idx->startPos >= len) { - *ok = gFalse; - } - idx->endPos = idx->startPos + getUVarBE(pos + 3 + idx->len * idx->offSize, - idx->offSize, ok); - if (idx->endPos < idx->startPos || idx->endPos > len) { - *ok = gFalse; - } - } -} - -void FoFiType1C::getIndexVal(Type1CIndex *idx, int i, - Type1CIndexVal *val, GBool *ok) { - int pos0, pos1; - - if (i < 0 || i >= idx->len) { - *ok = gFalse; - return; - } - pos0 = idx->startPos + getUVarBE(idx->pos + 3 + i * idx->offSize, - idx->offSize, ok); - pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize, - idx->offSize, ok); - if (pos0 < idx->startPos || pos0 > idx->endPos || - pos1 <= idx->startPos || pos1 > idx->endPos || - pos1 < pos0) { - *ok = gFalse; - } - val->pos = pos0; - val->len = pos1 - pos0; -} - -char *FoFiType1C::getString(int sid, char *buf, GBool *ok) { - Type1CIndexVal val; - int n; - - if (sid < 391) { - strcpy(buf, fofiType1CStdStrings[sid]); - } else { - sid -= 391; - getIndexVal(&stringIdx, sid, &val, ok); - if (*ok) { - if ((n = val.len) > 255) { - n = 255; - } - strncpy(buf, (char *)&file[val.pos], n); - buf[n] = '\0'; - } else { - buf[0] = '\0'; - } - } - return buf; -} diff --git a/kpdf/xpdf/fofi/FoFiType1C.cpp b/kpdf/xpdf/fofi/FoFiType1C.cpp new file mode 100644 index 00000000..f2ca88dc --- /dev/null +++ b/kpdf/xpdf/fofi/FoFiType1C.cpp @@ -0,0 +1,2603 @@ +//======================================================================== +// +// FoFiType1C.cpp +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include "gmem.h" +#include "GString.h" +#include "FoFiEncodings.h" +#include "FoFiType1C.h" + +//------------------------------------------------------------------------ + +static char hexChars[17] = "0123456789ABCDEF"; + +//------------------------------------------------------------------------ +// FoFiType1C +//------------------------------------------------------------------------ + +FoFiType1C *FoFiType1C::make(char *fileA, int lenA) { + FoFiType1C *ff; + + ff = new FoFiType1C(fileA, lenA, gFalse); + if (!ff->parse()) { + delete ff; + return NULL; + } + return ff; +} + +FoFiType1C *FoFiType1C::load(char *fileName) { + FoFiType1C *ff; + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + ff = new FoFiType1C(fileA, lenA, gTrue); + if (!ff->parse()) { + delete ff; + return NULL; + } + return ff; +} + +FoFiType1C::FoFiType1C(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + name = NULL; + encoding = NULL; + privateDicts = NULL; + fdSelect = NULL; + charset = NULL; +} + +FoFiType1C::~FoFiType1C() { + int i; + + if (name) { + delete name; + } + if (encoding && + encoding != fofiType1StandardEncoding && + encoding != fofiType1ExpertEncoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } + if (privateDicts) { + gfree(privateDicts); + } + if (fdSelect) { + gfree(fdSelect); + } + if (charset && + charset != fofiType1CISOAdobeCharset && + charset != fofiType1CExpertCharset && + charset != fofiType1CExpertSubsetCharset) { + gfree(charset); + } +} + +char *FoFiType1C::getName() { + return name ? name->getCString() : (char *)NULL; +} + +char **FoFiType1C::getEncoding() { + return encoding; +} + +Gushort *FoFiType1C::getCIDToGIDMap(int *nCIDs) { + Gushort *map; + int n, i; + + // a CID font's top dict has ROS as the first operator + if (topDict.firstOp != 0x0c1e) { + *nCIDs = 0; + return NULL; + } + + // in a CID font, the charset data is the GID-to-CID mapping, so all + // we have to do is reverse it + n = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] > n) { + n = charset[i]; + } + } + ++n; + map = (Gushort *)gmallocn(n, sizeof(Gushort)); + memset(map, 0, n * sizeof(Gushort)); + for (i = 0; i < nGlyphs; ++i) { + map[charset[i]] = i; + } + *nCIDs = n; + return map; +} + +void FoFiType1C::convertToType1(char *psName, char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, + void *outputStream) { + int psNameLen; + Type1CEexecBuf eb; + Type1CIndex subrIdx; + Type1CIndexVal val; + GString *buf; + char buf2[256]; + char **enc; + GBool ok; + int i; + + if (psName) { + psNameLen = strlen(psName); + } else { + psName = name->getCString(); + psNameLen = name->getLength(); + } + + // write header and font dictionary, up to encoding + ok = gTrue; + (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); + (*outputFunc)(outputStream, psName, psNameLen); + if (topDict.versionSID != 0) { + getString(topDict.versionSID, buf2, &ok); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + } + (*outputFunc)(outputStream, "\n", 1); + // the dictionary needs room for 12 entries: the following 9, plus + // Private and CharStrings (in the eexec section) and FID (which is + // added by definefont) + (*outputFunc)(outputStream, "12 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); + if (topDict.versionSID != 0) { + (*outputFunc)(outputStream, "/version (", 10); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.noticeSID != 0) { + getString(topDict.noticeSID, buf2, &ok); + (*outputFunc)(outputStream, "/Notice (", 9); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.copyrightSID != 0) { + getString(topDict.copyrightSID, buf2, &ok); + (*outputFunc)(outputStream, "/Copyright (", 12); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.fullNameSID != 0) { + getString(topDict.fullNameSID, buf2, &ok); + (*outputFunc)(outputStream, "/FullName (", 11); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.familyNameSID != 0) { + getString(topDict.familyNameSID, buf2, &ok); + (*outputFunc)(outputStream, "/FamilyName (", 13); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.weightSID != 0) { + getString(topDict.weightSID, buf2, &ok); + (*outputFunc)(outputStream, "/Weight (", 9); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.isFixedPitch) { + (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); + } else { + (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); + } + buf = GString::format("/ItalicAngle {0:.4g} def\n", topDict.italicAngle); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/UnderlinePosition {0:.4g} def\n", + topDict.underlinePosition); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/UnderlineThickness {0:.4g} def\n", + topDict.underlineThickness); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, psNameLen); + (*outputFunc)(outputStream, " def\n", 5); + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] readonly def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] readonly def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (topDict.uniqueID != 0) { + buf = GString::format("/UniqueID {0:d} def\n", topDict.uniqueID); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + + // write the encoding + (*outputFunc)(outputStream, "/Encoding ", 10); + if (!newEncoding && encoding == fofiType1StandardEncoding) { + (*outputFunc)(outputStream, "StandardEncoding def\n", 21); + } else { + (*outputFunc)(outputStream, "256 array\n", 10); + (*outputFunc)(outputStream, + "0 1 255 {1 index exch /.notdef put} for\n", 40); + enc = newEncoding ? newEncoding : encoding; + for (i = 0; i < 256; ++i) { + if (enc[i]) { + buf = GString::format("dup {0:d} /{1:s} put\n", i, enc[i]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); + } + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + eb.outputFunc = outputFunc; + eb.outputStream = outputStream; + eb.ascii = ascii; + eb.r1 = 55665; + eb.line = 0; + + // write the private dictionary + eexecWrite(&eb, "\x83\xca\x73\xd5"); + eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); + eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" + " executeonly def\n"); + eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); + eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); + eexecWrite(&eb, "/MinFeature {16 16} def\n"); + eexecWrite(&eb, "/password 5839 def\n"); + if (privateDicts[0].nBlueValues) { + eexecWrite(&eb, "/BlueValues ["); + for (i = 0; i < privateDicts[0].nBlueValues; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].blueValues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (i = 0; i < privateDicts[0].nOtherBlues; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].otherBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) { + buf = GString::format("{0:s}{1:d}", + i > 0 ? " " : "", privateDicts[0].familyBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) { + buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "", + privateDicts[0].familyOtherBlues[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[0].blueScale); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", privateDicts[0].blueShift); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[0].blueFuzz); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[0].stdHW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[0].stdVW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { + buf = GString::format("{0:s}{1:.4g}", + i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { + buf = GString::format("{0:s}{1:.4g}", + i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[0].forceBold ? "true" : "false"); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[0].forceBoldThreshold); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[0].languageGroup); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[0].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[0].expansionFactor); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + + // set up subroutines + ok = gTrue; + getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // write the CharStrings + buf = GString::format("2 index /CharStrings {0:d} dict dup begin\n", + nGlyphs); + eexecWrite(&eb, buf->getCString()); + delete buf; + for (i = 0; i < nGlyphs; ++i) { + ok = gTrue; + getIndexVal(&charStringsIdx, i, &val, &ok); + if (ok) { + getString(charset[i], buf2, &ok); + if (ok) { + eexecCvtGlyph(&eb, buf2, val.pos, val.len, &subrIdx, &privateDicts[0]); + } + } + } + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "readonly put\n"); + eexecWrite(&eb, "noaccess put\n"); + eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); + eexecWrite(&eb, "mark currentfile closefile\n"); + + // trailer + if (ascii && eb.line > 0) { + (*outputFunc)(outputStream, "\n", 1); + } + for (i = 0; i < 8; ++i) { + (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); + } + (*outputFunc)(outputStream, "cleartomark\n", 12); +} + +void FoFiType1C::convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + int *cidMap; + GString *charStrings; + int *charStringOffsets; + Type1CIndex subrIdx; + Type1CIndexVal val; + int nCIDs, gdBytes; + GString *buf; + char buf2[256]; + GBool ok; + int gid, offset, n, i, j, k; + + // compute the CID count and build the CID-to-GID mapping + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + + // build the charstrings + charStrings = new GString(); + charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + charStringOffsets[i] = charStrings->getLength(); + if ((gid = cidMap[i]) >= 0) { + ok = gTrue; + getIndexVal(&charStringsIdx, gid, &val, &ok); + if (ok) { + getIndex(privateDicts[fdSelect[gid]].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + cvtGlyph(val.pos, val.len, charStrings, + &subrIdx, &privateDicts[fdSelect[gid]], gTrue); + } + } + } + charStringOffsets[nCIDs] = charStrings->getLength(); + + // compute gdBytes = number of bytes needed for charstring offsets + // (offset size needs to account for the charstring offset table, + // with a worst case of five bytes per entry, plus the charstrings + // themselves) + i = (nCIDs + 1) * 5 + charStrings->getLength(); + if (i < 0x100) { + gdBytes = 1; + } else if (i < 0x10000) { + gdBytes = 2; + } else if (i < 0x1000000) { + gdBytes = 3; + } else { + gdBytes = 4; + } + + // begin the font dictionary + (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); + (*outputFunc)(outputStream, "20 dict begin\n", 14); + (*outputFunc)(outputStream, "/CIDFontName /", 14); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); + (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); + if (topDict.registrySID > 0 && topDict.orderingSID > 0) { + ok = gTrue; + getString(topDict.registrySID, buf2, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Registry (", 13); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") def\n", 6); + } + ok = gTrue; + getString(topDict.orderingSID, buf2, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Ordering (", 13); + (*outputFunc)(outputStream, buf2, strlen(buf2)); + (*outputFunc)(outputStream, ") def\n", 6); + } + } else { + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + } + buf = GString::format(" /Supplement {0:d} def\n", topDict.supplement); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "end def\n", 8); + if (topDict.hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else if (privateDicts[0].hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); + (*outputFunc)(outputStream, " /FSType 8 def\n", 16); + (*outputFunc)(outputStream, "end def\n", 8); + + // CIDFont-specific entries + buf = GString::format("/CIDCount {0:d} def\n", nCIDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); + buf = GString::format("/GDBytes {0:d} def\n", gdBytes); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); + if (topDict.paintType != 0) { + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + + // FDArray entry + buf = GString::format("/FDArray {0:d} array\n", nFDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + for (i = 0; i < nFDs; ++i) { + buf = GString::format("dup {0:d} 10 dict begin\n", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[i].hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + privateDicts[i].fontMatrix[0], + privateDicts[i].fontMatrix[1], + privateDicts[i].fontMatrix[2], + privateDicts[i].fontMatrix[3], + privateDicts[i].fontMatrix[4], + privateDicts[i].fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); + if (privateDicts[i].nBlueValues) { + (*outputFunc)(outputStream, "/BlueValues [", 13); + for (j = 0; j < privateDicts[i].nBlueValues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", privateDicts[i].blueValues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nOtherBlues) { + (*outputFunc)(outputStream, "/OtherBlues [", 13); + for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", privateDicts[i].otherBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyBlues) { + (*outputFunc)(outputStream, "/FamilyBlues [", 14); + for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { + buf = GString::format("{0:s}{1:d}", + j > 0 ? " " : "", + privateDicts[i].familyBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyOtherBlues) { + (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19); + for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { + buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "", + privateDicts[i].familyOtherBlues[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[i].blueScale); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", + privateDicts[i].blueShift); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[i].blueFuzz); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[i].stdHW); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[i].stdVW); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].nStemSnapH) { + (*outputFunc)(outputStream, "/StemSnapH [", 12); + for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { + buf = GString::format("{0:s}{1:.4g}", + j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nStemSnapV) { + (*outputFunc)(outputStream, "/StemSnapV [", 12); + for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { + buf = GString::format("{0:s}{1:.4g}", + j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[i].forceBold ? "true" : "false"); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[i].forceBoldThreshold); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[i].languageGroup); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (privateDicts[i].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[i].expansionFactor); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "currentdict end def\n", 20); + (*outputFunc)(outputStream, "currentdict end put\n", 20); + } + (*outputFunc)(outputStream, "def\n", 4); + + // start the binary section + offset = (nCIDs + 1) * (1 + gdBytes); + buf = GString::format("(Hex) {0:d} StartData\n", + offset + charStrings->getLength()); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + + // write the charstring offset (CIDMap) table + for (i = 0; i <= nCIDs; i += 6) { + for (j = 0; j < 6 && i+j <= nCIDs; ++j) { + if (i+j < nCIDs && cidMap[i+j] >= 0) { + buf2[0] = (char)fdSelect[cidMap[i+j]]; + } else { + buf2[0] = (char)0; + } + n = offset + charStringOffsets[i+j]; + for (k = gdBytes; k >= 1; --k) { + buf2[k] = (char)(n & 0xff); + n >>= 8; + } + for (k = 0; k <= gdBytes; ++k) { + buf = GString::format("{0:02x}", buf2[k] & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + } + (*outputFunc)(outputStream, "\n", 1); + } + + // write the charstring data + n = charStrings->getLength(); + for (i = 0; i < n; i += 32) { + for (j = 0; j < 32 && i+j < n; ++j) { + buf = GString::format("{0:02x}", charStrings->getChar(i+j) & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (i + 32 >= n) { + (*outputFunc)(outputStream, ">", 1); + } + (*outputFunc)(outputStream, "\n", 1); + } + + gfree(charStringOffsets); + delete charStrings; + gfree(cidMap); +} + +void FoFiType1C::convertToType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + int *cidMap; + Type1CIndex subrIdx; + Type1CIndexVal val; + int nCIDs; + GString *buf; + Type1CEexecBuf eb; + GBool ok; + int fd, i, j, k; + + // compute the CID count and build the CID-to-GID mapping + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + + // write the descendant Type 1 fonts + for (i = 0; i < nCIDs; i += 256) { + + //~ this assumes that all CIDs in this block have the same FD -- + //~ to handle multiple FDs correctly, need to somehow divide the + //~ font up by FD; as a kludge we ignore CID 0, which is .notdef + fd = 0; + for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + fd = fdSelect[cidMap[i+j]]; + break; + } + } + + // font dictionary (unencrypted section) + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + buf = GString::format("_{0:02x} def\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[fd].hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + privateDicts[fd].fontMatrix[0], + privateDicts[fd].fontMatrix[1], + privateDicts[fd].fontMatrix[2], + privateDicts[fd].fontMatrix[3], + privateDicts[fd].fontMatrix[4], + privateDicts[fd].fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else if (topDict.hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } + buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + if (topDict.paintType != 0) { + buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + if (j < 256) { + buf = GString::format("{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n", + j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + eb.outputFunc = outputFunc; + eb.outputStream = outputStream; + eb.ascii = gTrue; + eb.r1 = 55665; + eb.line = 0; + + // start the private dictionary + eexecWrite(&eb, "\x83\xca\x73\xd5"); + eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); + eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" + " executeonly def\n"); + eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); + eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); + eexecWrite(&eb, "/MinFeature {16 16} def\n"); + eexecWrite(&eb, "/password 5839 def\n"); + if (privateDicts[fd].nBlueValues) { + eexecWrite(&eb, "/BlueValues ["); + for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { + buf = GString::format("{0:s}{1:d}", + k > 0 ? " " : "", + privateDicts[fd].blueValues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { + buf = GString::format("{0:s}{1:d}", + k > 0 ? " " : "", + privateDicts[fd].otherBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { + buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", + privateDicts[fd].familyBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { + buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", + privateDicts[fd].familyOtherBlues[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].blueScale != 0.039625) { + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[fd].blueScale); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].blueShift != 7) { + buf = GString::format("/BlueShift {0:d} def\n", + privateDicts[fd].blueShift); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].blueFuzz != 1) { + buf = GString::format("/BlueFuzz {0:d} def\n", + privateDicts[fd].blueFuzz); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].hasStdHW) { + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].hasStdVW) { + buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[fd].stdVW); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { + buf = GString::format("{0:s}{1:.4g}", + k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { + buf = GString::format("{0:s}{1:.4g}", + k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].hasForceBold) { + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[fd].forceBold ? "true" : "false"); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].forceBoldThreshold != 0) { + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[fd].forceBoldThreshold); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].languageGroup != 0) { + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[fd].languageGroup); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + if (privateDicts[fd].expansionFactor != 0.06) { + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[fd].expansionFactor); + eexecWrite(&eb, buf->getCString()); + delete buf; + } + + // set up the subroutines + ok = gTrue; + getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // start the CharStrings + eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n"); + + // write the .notdef CharString + ok = gTrue; + getIndexVal(&charStringsIdx, 0, &val, &ok); + if (ok) { + eexecCvtGlyph(&eb, ".notdef", val.pos, val.len, + &subrIdx, &privateDicts[fd]); + } + + // write the CharStrings + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + ok = gTrue; + getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok); + if (ok) { + buf = GString::format("c{0:02x}", j); + eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len, + &subrIdx, &privateDicts[fd]); + delete buf; + } + } + } + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "readonly put\n"); + eexecWrite(&eb, "noaccess put\n"); + eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); + eexecWrite(&eb, "mark currentfile closefile\n"); + + // trailer + if (eb.line > 0) { + (*outputFunc)(outputStream, "\n", 1); + } + for (j = 0; j < 8; ++j) { + (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); + } + (*outputFunc)(outputStream, "cleartomark\n", 12); + } + + // write the Type 0 parent font + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + if (topDict.hasFontMatrix) { + buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } else { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < nCIDs; i += 256) { + buf = GString::format("{0:d}\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < nCIDs; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, strlen(psName)); + buf = GString::format("_{0:02x} findfont\n", i >> 8); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); + + gfree(cidMap); +} + +void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName, + int offset, int nBytes, + Type1CIndex *subrIdx, + Type1CPrivateDict *pDict) { + GString *buf; + GString *charBuf; + + // generate the charstring + charBuf = new GString(); + cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue); + + buf = GString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength()); + eexecWrite(eb, buf->getCString()); + delete buf; + eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(), + charBuf->getLength()); + eexecWrite(eb, " ND\n"); + + delete charBuf; +} + +void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, + Type1CIndex *subrIdx, Type1CPrivateDict *pDict, + GBool top) { + Type1CIndexVal val; + GBool ok, dFP; + double d, dx, dy; + Gushort r2; + Guchar byte; + int pos, subrBias, start, i, k; + + start = charBuf->getLength(); + if (top) { + charBuf->append((char)73); + charBuf->append((char)58); + charBuf->append((char)147); + charBuf->append((char)134); + nOps = 0; + nHints = 0; + firstOp = gTrue; + openPath = gFalse; + } + + pos = offset; + while (pos < offset + nBytes) { + ok = gTrue; + pos = getOp(pos, gTrue, &ok); + if (!ok) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + switch (ops[nOps].op) { + case 0x0001: // hstem + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); + } + d = 0; + dFP = gFalse; + for (k = 0; k < nOps; k += 2) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints + if (ops[k+1].num < 0) { + d += ops[k].num + ops[k+1].num; + dFP |= ops[k].isFP | ops[k+1].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); + } else { + d += ops[k].num; + dFP |= ops[k].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + d += ops[k+1].num; + dFP |= ops[k+1].isFP; + } + charBuf->append((char)1); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0003: // vstem + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); + } + d = 0; + dFP = gFalse; + for (k = 0; k < nOps; k += 2) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints + if (ops[k+1].num < 0) { + d += ops[k].num + ops[k+1].num; + dFP |= ops[k].isFP | ops[k+1].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); + } else { + d += ops[k].num; + dFP |= ops[k].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + d += ops[k+1].num; + dFP |= ops[k+1].isFP; + } + charBuf->append((char)3); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0004: // vmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 2, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + charBuf->append((char)4); + nOps = 0; + break; + case 0x0005: // rlineto + if (nOps < 2 || nOps % 2 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); + } + for (k = 0; k < nOps; k += 2) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + charBuf->append((char)5); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0006: // hlineto + if (nOps < 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + charBuf->append((char)((k & 1) ? 7 : 6)); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0007: // vlineto + if (nOps < 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + charBuf->append((char)((k & 1) ? 6 : 7)); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0008: // rrcurveto + if (nOps < 6 || nOps % 6 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); + } + for (k = 0; k < nOps; k += 6) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x000a: // callsubr + if (nOps >= 1) { + subrBias = (subrIdx->len < 1240) + ? 107 : (subrIdx->len < 33900) ? 1131 : 32768; + k = subrBias + (int)ops[nOps - 1].num; + --nOps; + ok = gTrue; + getIndexVal(subrIdx, k, &val, &ok); + if (ok) { + cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); + } + } else { + //~ error(-1, "Too few args to Type 2 callsubr"); + } + // don't clear the stack + break; + case 0x000b: // return + // don't clear the stack + break; + case 0x000e: // endchar / seac + if (firstOp) { + cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps == 4) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + charBuf->append((char)12)->append((char)6); + } else if (nOps == 0) { + charBuf->append((char)14); + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); + } + nOps = 0; + break; + case 0x000f: // (obsolete) + // this op is ignored, but we need the glyph width + if (firstOp) { + cvtGlyphWidth(nOps > 0, charBuf, pDict); + firstOp = gFalse; + } + nOps = 0; + break; + case 0x0010: // blend + //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); + nOps = 0; + break; + case 0x0012: // hstemhm + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0013: // hintmask + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps > 0) { + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", + //~ nOps); + } + nHints += nOps / 2; + } + pos += (nHints + 7) >> 3; + nOps = 0; + break; + case 0x0014: // cntrmask + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps > 0) { + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", + //~ nOps); + } + nHints += nOps / 2; + } + pos += (nHints + 7) >> 3; + nOps = 0; + break; + case 0x0015: // rmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 3, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 2) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + charBuf->append((char)21); + nOps = 0; + break; + case 0x0016: // hmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 2, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + charBuf->append((char)22); + nOps = 0; + break; + case 0x0017: // vstemhm + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0018: // rcurveline + if (nOps < 8 || (nOps - 2) % 6 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); + } + for (k = 0; k < nOps - 2; k += 6) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + } + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k].isFP, charBuf); + charBuf->append((char)5); + nOps = 0; + openPath = gTrue; + break; + case 0x0019: // rlinecurve + if (nOps < 8 || (nOps - 6) % 2 != 0) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); + } + for (k = 0; k < nOps - 6; k += 2) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k].isFP, charBuf); + charBuf->append((char)5); + } + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x001a: // vvcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); + } + if (nOps % 2 == 1) { + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + charBuf->append((char)8); + k = 5; + } else { + k = 0; + } + for (; k < nOps; k += 4) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001b: // hhcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); + } + if (nOps % 2 == 1) { + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + k = 5; + } else { + k = 0; + } + for (; k < nOps; k += 4) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001d: // callgsubr + if (nOps >= 1) { + k = gsubrBias + (int)ops[nOps - 1].num; + --nOps; + ok = gTrue; + getIndexVal(&gsubrIdx, k, &val, &ok); + if (ok) { + cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); + } + } else { + //~ error(-1, "Too few args to Type 2 callgsubr"); + } + // don't clear the stack + break; + case 0x001e: // vhcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); + } + for (k = 0; k < nOps && k != nOps-5; k += 4) { + if (k % 8 == 0) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)30); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)31); + } + } + if (k == nOps-5) { + if (k % 8 == 0) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + } + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001f: // hvcurveto + if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); + } + for (k = 0; k < nOps && k != nOps-5; k += 4) { + if (k % 8 == 0) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)31); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)30); + } + } + if (k == nOps-5) { + if (k % 8 == 0) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + } else { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + } + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0c00: // dotsection (should be Type 1 only?) + // ignored + nOps = 0; + break; + case 0x0c03: // and + case 0x0c04: // or + case 0x0c05: // not + case 0x0c08: // store + case 0x0c09: // abs + case 0x0c0a: // add + case 0x0c0b: // sub + case 0x0c0c: // div + case 0x0c0d: // load + case 0x0c0e: // neg + case 0x0c0f: // eq + case 0x0c12: // drop + case 0x0c14: // put + case 0x0c15: // get + case 0x0c16: // ifelse + case 0x0c17: // random + case 0x0c18: // mul + case 0x0c1a: // sqrt + case 0x0c1b: // dup + case 0x0c1c: // exch + case 0x0c1d: // index + case 0x0c1e: // roll + //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); + nOps = 0; + break; + case 0x0c22: // hflex + if (nOps != 7) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + cvtNum(-ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c23: // flex + if (nOps != 13) { + //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + charBuf->append((char)8); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(ops[9].num, ops[9].isFP, charBuf); + cvtNum(ops[10].num, ops[10].isFP, charBuf); + cvtNum(ops[11].num, ops[11].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c24: // hflex1 + if (nOps != 9) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(-(ops[1].num + ops[3].num + ops[7].num), + ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c25: // flex1 + if (nOps != 11) { + //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + charBuf->append((char)8); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(ops[9].num, ops[9].isFP, charBuf); + dx = ops[0].num + ops[2].num + ops[4].num + ops[6].num + ops[8].num; + dy = ops[1].num + ops[3].num + ops[5].num + ops[7].num + ops[9].num; + if (fabs(dx) > fabs(dy)) { + cvtNum(ops[10].num, ops[10].isFP, charBuf); + cvtNum(-dy, ops[1].isFP | ops[3].isFP | ops[5].isFP | + ops[7].isFP | ops[9].isFP, charBuf); + } else { + cvtNum(-dx, ops[0].isFP | ops[2].isFP | ops[4].isFP | + ops[6].isFP | ops[8].isFP, charBuf); + cvtNum(ops[10].num, ops[10].isFP, charBuf); + } + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + default: + //~ error(-1, "Illegal Type 2 charstring op: %04x", + //~ ops[nOps].op); + nOps = 0; + break; + } + } + } + + // charstring encryption + if (top) { + r2 = 4330; + for (i = start; i < charBuf->getLength(); ++i) { + byte = charBuf->getChar(i) ^ (r2 >> 8); + charBuf->setChar(i, byte); + r2 = (byte + r2) * 52845 + 22719; + } + } +} + +void FoFiType1C::cvtGlyphWidth(GBool useOp, GString *charBuf, + Type1CPrivateDict *pDict) { + double w; + GBool wFP; + int i; + + if (useOp) { + w = pDict->nominalWidthX + ops[0].num; + wFP = pDict->nominalWidthXFP | ops[0].isFP; + for (i = 1; i < nOps; ++i) { + ops[i-1] = ops[i]; + } + --nOps; + } else { + w = pDict->defaultWidthX; + wFP = pDict->defaultWidthXFP; + } + cvtNum(0, gFalse, charBuf); + cvtNum(w, wFP, charBuf); + charBuf->append((char)13); +} + +void FoFiType1C::cvtNum(double x, GBool isFP, GString *charBuf) { + Guchar buf[12]; + int y, n; + + n = 0; + if (isFP) { + if (x >= -32768 && x < 32768) { + y = (int)(x * 256.0); + buf[0] = 255; + buf[1] = (Guchar)(y >> 24); + buf[2] = (Guchar)(y >> 16); + buf[3] = (Guchar)(y >> 8); + buf[4] = (Guchar)y; + buf[5] = 255; + buf[6] = 0; + buf[7] = 0; + buf[8] = 1; + buf[9] = 0; + buf[10] = 12; + buf[11] = 12; + n = 12; + } else { + //~ error(-1, "Type 2 fixed point constant out of range"); + } + } else { + y = (int)x; + if (y >= -107 && y <= 107) { + buf[0] = (Guchar)(y + 139); + n = 1; + } else if (y > 107 && y <= 1131) { + y -= 108; + buf[0] = (Guchar)((y >> 8) + 247); + buf[1] = (Guchar)(y & 0xff); + n = 2; + } else if (y < -107 && y >= -1131) { + y = -y - 108; + buf[0] = (Guchar)((y >> 8) + 251); + buf[1] = (Guchar)(y & 0xff); + n = 2; + } else { + buf[0] = 255; + buf[1] = (Guchar)(y >> 24); + buf[2] = (Guchar)(y >> 16); + buf[3] = (Guchar)(y >> 8); + buf[4] = (Guchar)y; + n = 5; + } + } + charBuf->append((char *)buf, n); +} + +void FoFiType1C::eexecWrite(Type1CEexecBuf *eb, char *s) { + Guchar *p; + Guchar x; + + for (p = (Guchar *)s; *p; ++p) { + x = *p ^ (eb->r1 >> 8); + eb->r1 = (x + eb->r1) * 52845 + 22719; + if (eb->ascii) { + (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); + (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); + eb->line += 2; + if (eb->line == 64) { + (*eb->outputFunc)(eb->outputStream, "\n", 1); + eb->line = 0; + } + } else { + (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); + } + } +} + +void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb, + Guchar *s, int n) { + Guchar x; + int i; + + // eexec encryption + for (i = 0; i < n; ++i) { + x = s[i] ^ (eb->r1 >> 8); + eb->r1 = (x + eb->r1) * 52845 + 22719; + if (eb->ascii) { + (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); + (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); + eb->line += 2; + if (eb->line == 64) { + (*eb->outputFunc)(eb->outputStream, "\n", 1); + eb->line = 0; + } + } else { + (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); + } + } +} + +GBool FoFiType1C::parse() { + Type1CIndex fdIdx; + Type1CIndexVal val; + int i; + + parsedOk = gTrue; + + // some tools embed Type 1C fonts with an extra whitespace char at + // the beginning + if (len > 0 && file[0] != '\x01') { + ++file; + --len; + } + + // find the indexes + getIndex(getU8(2, &parsedOk), &nameIdx, &parsedOk); + getIndex(nameIdx.endPos, &topDictIdx, &parsedOk); + getIndex(topDictIdx.endPos, &stringIdx, &parsedOk); + getIndex(stringIdx.endPos, &gsubrIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + gsubrBias = (gsubrIdx.len < 1240) ? 107 + : (gsubrIdx.len < 33900) ? 1131 : 32768; + + // read the first font name + getIndexVal(&nameIdx, 0, &val, &parsedOk); + if (!parsedOk) { + return gFalse; + } + name = new GString((char *)&file[val.pos], val.len); + + // read the top dict for the first font + readTopDict(); + + // for CID fonts: read the FDArray dicts and private dicts + if (topDict.firstOp == 0x0c1e) { + if (topDict.fdArrayOffset == 0) { + nFDs = 1; + privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); + readPrivateDict(0, 0, &privateDicts[0]); + } else { + getIndex(topDict.fdArrayOffset, &fdIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + nFDs = fdIdx.len; + privateDicts = (Type1CPrivateDict *) + gmallocn(nFDs, sizeof(Type1CPrivateDict)); + for (i = 0; i < nFDs; ++i) { + getIndexVal(&fdIdx, i, &val, &parsedOk); + if (!parsedOk) { + return gFalse; + } + readFD(val.pos, val.len, &privateDicts[i]); + } + } + + // for 8-bit fonts: read the private dict + } else { + privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); + readPrivateDict(topDict.privateOffset, topDict.privateSize, + &privateDicts[0]); + } + + // check for parse errors in the private dict(s) + if (!parsedOk) { + return gFalse; + } + + // get the charstrings index + if (topDict.charStringsOffset <= 0) { + parsedOk = gFalse; + return gFalse; + } + getIndex(topDict.charStringsOffset, &charStringsIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + nGlyphs = charStringsIdx.len; + + // for CID fonts: read the FDSelect table + if (topDict.firstOp == 0x0c1e) { + readFDSelect(); + if (!parsedOk) { + return gFalse; + } + } + + // read the charset + if (!readCharset()) { + parsedOk = gFalse; + return gFalse; + } + + // for 8-bit fonts: build the encoding + if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) { + buildEncoding(); + if (!parsedOk) { + return gFalse; + } + } + + return parsedOk; +} + +void FoFiType1C::readTopDict() { + Type1CIndexVal topDictPtr; + int pos; + + topDict.firstOp = -1; + topDict.versionSID = 0; + topDict.noticeSID = 0; + topDict.copyrightSID = 0; + topDict.fullNameSID = 0; + topDict.familyNameSID = 0; + topDict.weightSID = 0; + topDict.isFixedPitch = 0; + topDict.italicAngle = 0; + topDict.underlinePosition = -100; + topDict.underlineThickness = 50; + topDict.paintType = 0; + topDict.charstringType = 2; + topDict.fontMatrix[0] = 0.001; + topDict.fontMatrix[1] = 0; + topDict.fontMatrix[2] = 0; + topDict.fontMatrix[3] = 0.001; + topDict.fontMatrix[4] = 0; + topDict.fontMatrix[5] = 0; + topDict.hasFontMatrix = gFalse; + topDict.uniqueID = 0; + topDict.fontBBox[0] = 0; + topDict.fontBBox[1] = 0; + topDict.fontBBox[2] = 0; + topDict.fontBBox[3] = 0; + topDict.strokeWidth = 0; + topDict.charsetOffset = 0; + topDict.encodingOffset = 0; + topDict.charStringsOffset = 0; + topDict.privateSize = 0; + topDict.privateOffset = 0; + topDict.registrySID = 0; + topDict.orderingSID = 0; + topDict.supplement = 0; + topDict.fdArrayOffset = 0; + topDict.fdSelectOffset = 0; + + getIndexVal(&topDictIdx, 0, &topDictPtr, &parsedOk); + pos = topDictPtr.pos; + nOps = 0; + while (pos < topDictPtr.pos + topDictPtr.len) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + if (topDict.firstOp < 0) { + topDict.firstOp = ops[nOps].op; + } + switch (ops[nOps].op) { + case 0x0000: topDict.versionSID = (int)ops[0].num; break; + case 0x0001: topDict.noticeSID = (int)ops[0].num; break; + case 0x0c00: topDict.copyrightSID = (int)ops[0].num; break; + case 0x0002: topDict.fullNameSID = (int)ops[0].num; break; + case 0x0003: topDict.familyNameSID = (int)ops[0].num; break; + case 0x0004: topDict.weightSID = (int)ops[0].num; break; + case 0x0c01: topDict.isFixedPitch = (int)ops[0].num; break; + case 0x0c02: topDict.italicAngle = ops[0].num; break; + case 0x0c03: topDict.underlinePosition = ops[0].num; break; + case 0x0c04: topDict.underlineThickness = ops[0].num; break; + case 0x0c05: topDict.paintType = (int)ops[0].num; break; + case 0x0c06: topDict.charstringType = (int)ops[0].num; break; + case 0x0c07: topDict.fontMatrix[0] = ops[0].num; + topDict.fontMatrix[1] = ops[1].num; + topDict.fontMatrix[2] = ops[2].num; + topDict.fontMatrix[3] = ops[3].num; + topDict.fontMatrix[4] = ops[4].num; + topDict.fontMatrix[5] = ops[5].num; + topDict.hasFontMatrix = gTrue; break; + case 0x000d: topDict.uniqueID = (int)ops[0].num; break; + case 0x0005: topDict.fontBBox[0] = ops[0].num; + topDict.fontBBox[1] = ops[1].num; + topDict.fontBBox[2] = ops[2].num; + topDict.fontBBox[3] = ops[3].num; break; + case 0x0c08: topDict.strokeWidth = ops[0].num; break; + case 0x000f: topDict.charsetOffset = (int)ops[0].num; break; + case 0x0010: topDict.encodingOffset = (int)ops[0].num; break; + case 0x0011: topDict.charStringsOffset = (int)ops[0].num; break; + case 0x0012: topDict.privateSize = (int)ops[0].num; + topDict.privateOffset = (int)ops[1].num; break; + case 0x0c1e: topDict.registrySID = (int)ops[0].num; + topDict.orderingSID = (int)ops[1].num; + topDict.supplement = (int)ops[2].num; break; + case 0x0c24: topDict.fdArrayOffset = (int)ops[0].num; break; + case 0x0c25: topDict.fdSelectOffset = (int)ops[0].num; break; + } + nOps = 0; + } + } +} + +// Read a CID font dict (FD) - this pulls out the private dict +// pointer, and reads the private dict. It also pulls the FontMatrix +// (if any) out of the FD. +void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { + int pos, pSize, pOffset; + double fontMatrix[6]; + GBool hasFontMatrix; + + hasFontMatrix = gFalse; + pSize = pOffset = 0; + pos = offset; + nOps = 0; + while (pos < offset + length) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + return; + } + if (!ops[nOps - 1].isNum) { + if (ops[nOps - 1].op == 0x0012) { + if (nOps < 3) { + parsedOk = gFalse; + return; + } + pSize = (int)ops[0].num; + pOffset = (int)ops[1].num; + break; + } else if (ops[nOps - 1].op == 0x0c07) { + fontMatrix[0] = ops[0].num; + fontMatrix[1] = ops[1].num; + fontMatrix[2] = ops[2].num; + fontMatrix[3] = ops[3].num; + fontMatrix[4] = ops[4].num; + fontMatrix[5] = ops[5].num; + hasFontMatrix = gTrue; + } + nOps = 0; + } + } + readPrivateDict(pOffset, pSize, pDict); + if (hasFontMatrix) { + pDict->fontMatrix[0] = fontMatrix[0]; + pDict->fontMatrix[1] = fontMatrix[1]; + pDict->fontMatrix[2] = fontMatrix[2]; + pDict->fontMatrix[3] = fontMatrix[3]; + pDict->fontMatrix[4] = fontMatrix[4]; + pDict->fontMatrix[5] = fontMatrix[5]; + pDict->hasFontMatrix = gTrue; + } +} + +void FoFiType1C::readPrivateDict(int offset, int length, + Type1CPrivateDict *pDict) { + int pos; + + pDict->hasFontMatrix = gFalse; + pDict->nBlueValues = 0; + pDict->nOtherBlues = 0; + pDict->nFamilyBlues = 0; + pDict->nFamilyOtherBlues = 0; + pDict->blueScale = 0.039625; + pDict->blueShift = 7; + pDict->blueFuzz = 1; + pDict->hasStdHW = gFalse; + pDict->hasStdVW = gFalse; + pDict->nStemSnapH = 0; + pDict->nStemSnapV = 0; + pDict->hasForceBold = gFalse; + pDict->forceBoldThreshold = 0; + pDict->languageGroup = 0; + pDict->expansionFactor = 0.06; + pDict->initialRandomSeed = 0; + pDict->subrsOffset = 0; + pDict->defaultWidthX = 0; + pDict->defaultWidthXFP = gFalse; + pDict->nominalWidthX = 0; + pDict->nominalWidthXFP = gFalse; + + // no dictionary + if (offset == 0 || length == 0) { + return; + } + + pos = offset; + nOps = 0; + while (pos < offset + length) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + switch (ops[nOps].op) { + case 0x0006: + pDict->nBlueValues = getDeltaIntArray(pDict->blueValues, + type1CMaxBlueValues); + break; + case 0x0007: + pDict->nOtherBlues = getDeltaIntArray(pDict->otherBlues, + type1CMaxOtherBlues); + break; + case 0x0008: + pDict->nFamilyBlues = getDeltaIntArray(pDict->familyBlues, + type1CMaxBlueValues); + break; + case 0x0009: + pDict->nFamilyOtherBlues = getDeltaIntArray(pDict->familyOtherBlues, + type1CMaxOtherBlues); + break; + case 0x0c09: + pDict->blueScale = ops[0].num; + break; + case 0x0c0a: + pDict->blueShift = (int)ops[0].num; + break; + case 0x0c0b: + pDict->blueFuzz = (int)ops[0].num; + break; + case 0x000a: + pDict->stdHW = ops[0].num; + pDict->hasStdHW = gTrue; + break; + case 0x000b: + pDict->stdVW = ops[0].num; + pDict->hasStdVW = gTrue; + break; + case 0x0c0c: + pDict->nStemSnapH = getDeltaFPArray(pDict->stemSnapH, + type1CMaxStemSnap); + break; + case 0x0c0d: + pDict->nStemSnapV = getDeltaFPArray(pDict->stemSnapV, + type1CMaxStemSnap); + break; + case 0x0c0e: + pDict->forceBold = ops[0].num != 0; + pDict->hasForceBold = gTrue; + break; + case 0x0c0f: + pDict->forceBoldThreshold = ops[0].num; + break; + case 0x0c11: + pDict->languageGroup = (int)ops[0].num; + break; + case 0x0c12: + pDict->expansionFactor = ops[0].num; + break; + case 0x0c13: + pDict->initialRandomSeed = (int)ops[0].num; + break; + case 0x0013: + pDict->subrsOffset = offset + (int)ops[0].num; + break; + case 0x0014: + pDict->defaultWidthX = ops[0].num; + pDict->defaultWidthXFP = ops[0].isFP; + break; + case 0x0015: + pDict->nominalWidthX = ops[0].num; + pDict->nominalWidthXFP = ops[0].isFP; + break; + } + nOps = 0; + } + } +} + +void FoFiType1C::readFDSelect() { + int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j; + + fdSelect = (Guchar *)gmalloc(nGlyphs); + if (topDict.fdSelectOffset == 0) { + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } else { + pos = topDict.fdSelectOffset; + fdSelectFmt = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (fdSelectFmt == 0) { + if (!checkRegion(pos, nGlyphs)) { + parsedOk = gFalse; + return; + } + memcpy(fdSelect, file + pos, nGlyphs); + } else if (fdSelectFmt == 3) { + nRanges = getU16BE(pos, &parsedOk); + pos += 2; + gid0 = getU16BE(pos, &parsedOk); + pos += 2; + for (i = 1; i <= nRanges; ++i) { + fd = getU8(pos++, &parsedOk); + gid1 = getU16BE(pos, &parsedOk); + if (!parsedOk) { + return; + } + pos += 2; + if (gid0 > gid1 || gid1 > nGlyphs) { + //~ error(-1, "Bad FDSelect table in CID font"); + parsedOk = gFalse; + return; + } + for (j = gid0; j < gid1; ++j) { + fdSelect[j] = fd; + } + gid0 = gid1; + } + } else { + //~ error(-1, "Unknown FDSelect table format in CID font"); + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } + } +} + +void FoFiType1C::buildEncoding() { + char buf[256]; + int nCodes, nRanges, encFormat; + int pos, c, sid, nLeft, nSups, i, j; + + if (topDict.encodingOffset == 0) { + encoding = fofiType1StandardEncoding; + + } else if (topDict.encodingOffset == 1) { + encoding = fofiType1ExpertEncoding; + + } else { + encoding = (char **)gmallocn(256, sizeof(char *)); + for (i = 0; i < 256; ++i) { + encoding[i] = NULL; + } + pos = topDict.encodingOffset; + encFormat = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if ((encFormat & 0x7f) == 0) { + nCodes = 1 + getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (nCodes > nGlyphs) { + nCodes = nGlyphs; + } + for (i = 1; i < nCodes; ++i) { + c = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(charset[i], buf, &parsedOk)); + } + } else if ((encFormat & 0x7f) == 1) { + nRanges = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + nCodes = 1; + for (i = 0; i < nRanges; ++i) { + c = getU8(pos++, &parsedOk); + nLeft = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { + if (c < 256) { + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(charset[nCodes], buf, + &parsedOk)); + } + ++nCodes; + ++c; + } + } + } + if (encFormat & 0x80) { + nSups = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + for (i = 0; i < nSups; ++i) { + c = getU8(pos++, &parsedOk);; + if (!parsedOk) { + return;; + } + sid = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + return; + } + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(sid, buf, &parsedOk)); + } + } + } +} + +GBool FoFiType1C::readCharset() { + int charsetFormat, c, pos; + int nLeft, i, j; + + if (topDict.charsetOffset == 0) { + charset = fofiType1CISOAdobeCharset; + } else if (topDict.charsetOffset == 1) { + charset = fofiType1CExpertCharset; + } else if (topDict.charsetOffset == 2) { + charset = fofiType1CExpertSubsetCharset; + } else { + charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); + for (i = 0; i < nGlyphs; ++i) { + charset[i] = 0; + } + pos = topDict.charsetOffset; + charsetFormat = getU8(pos++, &parsedOk); + if (charsetFormat == 0) { + for (i = 1; i < nGlyphs; ++i) { + charset[i] = (Gushort)getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + break; + } + } + } else if (charsetFormat == 1) { + i = 1; + while (i < nGlyphs) { + c = getU16BE(pos, &parsedOk); + pos += 2; + nLeft = getU8(pos++, &parsedOk); + if (!parsedOk) { + break; + } + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + charset[i++] = (Gushort)c++; + } + } + } else if (charsetFormat == 2) { + i = 1; + while (i < nGlyphs) { + c = getU16BE(pos, &parsedOk); + pos += 2; + nLeft = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + break; + } + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + charset[i++] = (Gushort)c++; + } + } + } + if (!parsedOk) { + gfree(charset); + charset = NULL; + return gFalse; + } + } + return gTrue; +} + +int FoFiType1C::getOp(int pos, GBool charstring, GBool *ok) { + static char nybChars[16] = "0123456789.ee -"; + Type1COp op; + char buf[65]; + int b0, b1, nyb0, nyb1, x, i; + + b0 = getU8(pos++, ok); + op.isNum = gTrue; + op.isFP = gFalse; + + if (b0 == 28) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x8000) { + x |= ~0xffff; + } + op.num = x; + + } else if (!charstring && b0 == 29) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x80000000) { + x |= ~0xffffffff; + } + op.num = x; + + } else if (!charstring && b0 == 30) { + i = 0; + do { + b1 = getU8(pos++, ok); + nyb0 = b1 >> 4; + nyb1 = b1 & 0x0f; + if (nyb0 == 0xf) { + break; + } + buf[i++] = nybChars[nyb0]; + if (i == 64) { + break; + } + if (nyb0 == 0xc) { + buf[i++] = '-'; + } + if (i == 64) { + break; + } + if (nyb1 == 0xf) { + break; + } + buf[i++] = nybChars[nyb1]; + if (i == 64) { + break; + } + if (nyb1 == 0xc) { + buf[i++] = '-'; + } + } while (i < 64); + buf[i] = '\0'; + op.num = atof(buf); + op.isFP = gTrue; + + } else if (b0 >= 32 && b0 <= 246) { + op.num = b0 - 139; + + } else if (b0 >= 247 && b0 <= 250) { + op.num = ((b0 - 247) << 8) + getU8(pos++, ok) + 108; + + } else if (b0 >= 251 && b0 <= 254) { + op.num = -((b0 - 251) << 8) - getU8(pos++, ok) - 108; + + } else if (charstring && b0 == 255) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x80000000) { + x |= ~0xffffffff; + } + op.num = (double)x / 65536.0; + op.isFP = gTrue; + + } else if (b0 == 12) { + op.isNum = gFalse; + op.op = 0x0c00 + getU8(pos++, ok); + + } else { + op.isNum = gFalse; + op.op = b0; + } + + if (nOps < 49) { + ops[nOps++] = op; + } + + return pos; +} + +// Convert the delta-encoded ops array to an array of ints. +int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) { + int x; + int n, i; + + if ((n = nOps) > maxLen) { + n = maxLen; + } + x = 0; + for (i = 0; i < n; ++i) { + x += (int)ops[i].num; + arr[i] = x; + } + return n; +} + +// Convert the delta-encoded ops array to an array of doubles. +int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) { + double x; + int n, i; + + if ((n = nOps) > maxLen) { + n = maxLen; + } + x = 0; + for (i = 0; i < n; ++i) { + x += ops[i].num; + arr[i] = x; + } + return n; +} + +void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) { + idx->pos = pos; + idx->len = getU16BE(pos, ok); + if (idx->len == 0) { + // empty indexes are legal and contain just the length field + idx->offSize = 0; + idx->startPos = idx->endPos = pos + 2; + } else { + idx->offSize = getU8(pos + 2, ok); + if (idx->offSize < 1 || idx->offSize > 4) { + *ok = gFalse; + } + idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1; + if (idx->startPos < 0 || idx->startPos >= len) { + *ok = gFalse; + } + idx->endPos = idx->startPos + getUVarBE(pos + 3 + idx->len * idx->offSize, + idx->offSize, ok); + if (idx->endPos < idx->startPos || idx->endPos > len) { + *ok = gFalse; + } + } +} + +void FoFiType1C::getIndexVal(Type1CIndex *idx, int i, + Type1CIndexVal *val, GBool *ok) { + int pos0, pos1; + + if (i < 0 || i >= idx->len) { + *ok = gFalse; + return; + } + pos0 = idx->startPos + getUVarBE(idx->pos + 3 + i * idx->offSize, + idx->offSize, ok); + pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize, + idx->offSize, ok); + if (pos0 < idx->startPos || pos0 > idx->endPos || + pos1 <= idx->startPos || pos1 > idx->endPos || + pos1 < pos0) { + *ok = gFalse; + } + val->pos = pos0; + val->len = pos1 - pos0; +} + +char *FoFiType1C::getString(int sid, char *buf, GBool *ok) { + Type1CIndexVal val; + int n; + + if (sid < 391) { + strcpy(buf, fofiType1CStdStrings[sid]); + } else { + sid -= 391; + getIndexVal(&stringIdx, sid, &val, ok); + if (*ok) { + if ((n = val.len) > 255) { + n = 255; + } + strncpy(buf, (char *)&file[val.pos], n); + buf[n] = '\0'; + } else { + buf[0] = '\0'; + } + } + return buf; +} diff --git a/kpdf/xpdf/fofi/Makefile.am b/kpdf/xpdf/fofi/Makefile.am index 7ca93922..9a1ec4aa 100644 --- a/kpdf/xpdf/fofi/Makefile.am +++ b/kpdf/xpdf/fofi/Makefile.am @@ -1,8 +1,8 @@ INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../goo $(all_includes) libfofi_la_LDFLAGS = $(all_libraries) -libfofi_la_SOURCES = FoFiBase.cc FoFiEncodings.cc FoFiTrueType.cc \ - FoFiType1.cc FoFiType1C.cc +libfofi_la_SOURCES = FoFiBase.cpp FoFiEncodings.cpp FoFiTrueType.cpp \ + FoFiType1.cpp FoFiType1C.cpp METASOURCES = AUTO -- cgit v1.2.1