From: kramm Date: Fri, 17 Sep 2004 16:24:55 +0000 (+0000) Subject: upgrade to xpdf 3.00. X-Git-Tag: xpdf-3-00 X-Git-Url: http://git.asbjorn.it/?a=commitdiff_plain;h=c7432833fe3a6469d63fad135151a92e12877b94;p=swftools.git upgrade to xpdf 3.00. --- diff --git a/pdf2swf/xpdf/Annot.cc b/pdf2swf/xpdf/Annot.cc index b9c606f..245780d 100644 --- a/pdf2swf/xpdf/Annot.cc +++ b/pdf2swf/xpdf/Annot.cc @@ -2,15 +2,16 @@ // // Annot.cc // -// Copyright 2000-2002 Glyph & Cog, LLC +// Copyright 2000-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include "gmem.h" #include "Object.h" #include "Gfx.h" @@ -96,7 +97,7 @@ void Annot::draw(Gfx *gfx) { Annots::Annots(XRef *xref, Object *annotsObj) { Annot *annot; - Object obj1, obj2; + Object obj1; int size; int i; @@ -107,21 +108,16 @@ Annots::Annots(XRef *xref, Object *annotsObj) { if (annotsObj->isArray()) { for (i = 0; i < annotsObj->arrayGetLength(); ++i) { if (annotsObj->arrayGet(i, &obj1)->isDict()) { - obj1.dictLookup("Subtype", &obj2); - if (obj2.isName("Widget") || - obj2.isName("Stamp")) { - annot = new Annot(xref, obj1.getDict()); - if (annot->isOk()) { - if (nAnnots >= size) { - size += 16; - annots = (Annot **)grealloc(annots, size * sizeof(Annot *)); - } - annots[nAnnots++] = annot; - } else { - delete annot; + annot = new Annot(xref, obj1.getDict()); + if (annot->isOk()) { + if (nAnnots >= size) { + size += 16; + annots = (Annot **)grealloc(annots, size * sizeof(Annot *)); } + annots[nAnnots++] = annot; + } else { + delete annot; } - obj2.free(); } obj1.free(); } diff --git a/pdf2swf/xpdf/Annot.h b/pdf2swf/xpdf/Annot.h index 4113a0b..89dde0f 100644 --- a/pdf2swf/xpdf/Annot.h +++ b/pdf2swf/xpdf/Annot.h @@ -2,14 +2,16 @@ // // Annot.h // -// Copyright 2000-2002 Glyph & Cog, LLC +// Copyright 2000-2003 Glyph & Cog, LLC // //======================================================================== #ifndef ANNOT_H #define ANNOT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/Array.cc b/pdf2swf/xpdf/Array.cc index fbdde49..a6c6db1 100644 --- a/pdf2swf/xpdf/Array.cc +++ b/pdf2swf/xpdf/Array.cc @@ -2,15 +2,17 @@ // // Array.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include +#include #include #include "gmem.h" #include "Object.h" @@ -36,8 +38,12 @@ Array::~Array() { } void Array::add(Object *elem) { - if (length + 1 > size) { - size += 8; + if (length == size) { + if (length == 0) { + size = 8; + } else { + size *= 2; + } elems = (Object *)grealloc(elems, size * sizeof(Object)); } elems[length] = *elem; @@ -45,9 +51,23 @@ void Array::add(Object *elem) { } Object *Array::get(int i, Object *obj) { + if (i < 0 || i >= length) { +#ifdef DEBUG_MEM + abort(); +#else + return obj->initNull(); +#endif + } return elems[i].fetch(xref, obj); } Object *Array::getNF(int i, Object *obj) { + if (i < 0 || i >= length) { +#ifdef DEBUG_MEM + abort(); +#else + return obj->initNull(); +#endif + } return elems[i].copy(obj); } diff --git a/pdf2swf/xpdf/Array.h b/pdf2swf/xpdf/Array.h index a118f68..20ae05f 100644 --- a/pdf2swf/xpdf/Array.h +++ b/pdf2swf/xpdf/Array.h @@ -2,14 +2,16 @@ // // Array.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef ARRAY_H #define ARRAY_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/BuiltinFont.cc b/pdf2swf/xpdf/BuiltinFont.cc index 1b07064..a687e73 100644 --- a/pdf2swf/xpdf/BuiltinFont.cc +++ b/pdf2swf/xpdf/BuiltinFont.cc @@ -2,15 +2,16 @@ // // BuiltinFont.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include "gmem.h" diff --git a/pdf2swf/xpdf/BuiltinFont.h b/pdf2swf/xpdf/BuiltinFont.h index a795311..903ed19 100644 --- a/pdf2swf/xpdf/BuiltinFont.h +++ b/pdf2swf/xpdf/BuiltinFont.h @@ -2,14 +2,16 @@ // // BuiltinFont.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef BUILTINFONT_H #define BUILTINFONT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/BuiltinFontTables.cc b/pdf2swf/xpdf/BuiltinFontTables.cc index 845abcd..9c36238 100644 --- a/pdf2swf/xpdf/BuiltinFontTables.cc +++ b/pdf2swf/xpdf/BuiltinFontTables.cc @@ -2,7 +2,7 @@ // // BuiltinFontTables.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -13,30 +13,40 @@ static BuiltinFontWidth courierWidthsTab[] = { { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, - { "arrowup", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, - { "LL", 600, NULL }, + { "edotaccent", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, { "ntilde", 600, NULL }, - { "left", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, { "yen", 600, NULL }, { "space", 600, NULL }, + { "Omacron", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, + { "aogonek", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, @@ -46,14 +56,18 @@ static BuiltinFontWidth courierWidthsTab[] = { { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, + { "iogonek", 600, NULL }, { "L", 600, NULL }, { "backslash", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, @@ -62,9 +76,7 @@ static BuiltinFontWidth courierWidthsTab[] = { { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, - { "tab", 600, NULL }, { "W", 600, NULL }, - { "ll", 600, NULL }, { "equal", 600, NULL }, { "question", 600, NULL }, { "X", 600, NULL }, @@ -72,6 +84,7 @@ static BuiltinFontWidth courierWidthsTab[] = { { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, @@ -88,44 +101,57 @@ static BuiltinFontWidth courierWidthsTab[] = { { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, - { "largebullet", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 600, NULL }, { "t", 600, NULL }, { "divide", 600, NULL }, { "u", 600, NULL }, + { "Ccaron", 600, NULL }, { "v", 600, NULL }, { "w", 600, NULL }, { "x", 600, NULL }, { "y", 600, NULL }, { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, { "Scaron", 600, NULL }, { "Lslash", 600, NULL }, { "semicolon", 600, NULL }, { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, { "trademark", 600, NULL }, { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, { "macron", 600, NULL }, { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, { "ellipsis", 600, NULL }, { "scaron", 600, NULL }, { "AE", 600, NULL }, { "Ucircumflex", 600, NULL }, { "lslash", 600, NULL }, - { "lira", 600, NULL }, { "quotedblleft", 600, NULL }, { "hyphen", 600, NULL }, { "guilsinglright", 600, NULL }, @@ -134,9 +160,11 @@ static BuiltinFontWidth courierWidthsTab[] = { { "exclamdown", 600, NULL }, { "endash", 600, NULL }, { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, { "ecircumflex", 600, NULL }, - { "copyright", 600, NULL }, { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, { "Egrave", 600, NULL }, { "slash", 600, NULL }, { "Edieresis", 600, NULL }, @@ -144,14 +172,17 @@ static BuiltinFontWidth courierWidthsTab[] = { { "Idieresis", 600, NULL }, { "parenleft", 600, NULL }, { "one", 600, NULL }, - { "ucircumflex", 600, NULL }, + { "emacron", 600, NULL }, { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, { "bracketleft", 600, NULL }, { "Ugrave", 600, NULL }, { "quoteright", 600, NULL }, { "Udieresis", 600, NULL }, { "perthousand", 600, NULL }, { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, { "Eacute", 600, NULL }, { "adieresis", 600, NULL }, { "egrave", 600, NULL }, @@ -167,139 +198,173 @@ static BuiltinFontWidth courierWidthsTab[] = { { "nine", 600, NULL }, { "udieresis", 600, NULL }, { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, { "threequarters", 600, NULL }, { "guillemotright", 600, NULL }, - { "ydieresis", 600, NULL }, { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, { "tilde", 600, NULL }, { "at", 600, NULL }, { "eacute", 600, NULL }, - { "Gcaron", 600, NULL }, { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, { "zero", 600, NULL }, { "multiply", 600, NULL }, - { "Scedilla", 600, NULL }, { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Racute", 600, NULL }, { "Ograve", 600, NULL }, + { "partialdiff", 600, NULL }, { "uacute", 600, NULL }, { "braceleft", 600, NULL }, { "Thorn", 600, NULL }, { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, { "ccedilla", 600, NULL }, - { "gcaron", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "scedilla", 600, NULL }, { "Oacute", 600, NULL }, { "Ocircumflex", 600, NULL }, - { "scedilla", 600, NULL }, { "ogonek", 600, NULL }, - { "arrowdown", 600, NULL }, { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, { "thorn", 600, NULL }, { "degree", 600, NULL }, { "registered", 600, NULL }, - { "percent", 600, NULL }, + { "radical", 600, NULL }, { "Aring", 600, NULL }, + { "percent", 600, NULL }, { "six", 600, NULL }, { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, { "two", 600, NULL }, + { "summation", 600, NULL }, { "Igrave", 600, NULL }, - { "oacute", 600, NULL }, + { "Lacute", 600, NULL }, { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, { "asciicircum", 600, NULL }, { "aring", 600, NULL }, - { "square", 600, NULL }, { "grave", 600, NULL }, + { "uogonek", 600, NULL }, { "bracketright", 600, NULL }, { "ampersand", 600, NULL }, { "Iacute", 600, NULL }, + { "lacute", 600, NULL }, { "igrave", 600, NULL }, - { "return", 600, NULL }, + { "Ncaron", 600, NULL }, { "plus", 600, NULL }, + { "uring", 600, NULL }, { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, { "threesuperior", 600, NULL }, { "acute", 600, NULL }, - { "notegraphic", 600, NULL }, { "section", 600, NULL }, - { "arrowleft", 600, NULL }, { "dieresis", 600, NULL }, { "quotedblbase", 600, NULL }, { "iacute", 600, NULL }, - { "up", 600, NULL }, + { "ncaron", 600, NULL }, { "florin", 600, NULL }, { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, { "fi", 600, NULL }, { "fl", 600, NULL }, { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, { "Icircumflex", 600, NULL }, { "guillemotleft", 600, NULL }, { "germandbls", 600, NULL }, { "seven", 600, NULL }, - { "indent", 600, NULL }, - { "prescription", 600, NULL }, - { "dectab", 600, NULL }, + { "Amacron", 600, NULL }, + { "Sacute", 600, NULL }, { "ordmasculine", 600, NULL }, { "dotlessi", 600, NULL }, { "sterling", 600, NULL }, - { "IJ", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, { "acircumflex", 600, NULL }, - { "overscore", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, { "braceright", 600, NULL }, { "icircumflex", 600, NULL }, - { "graybox", 600, NULL }, { "quotedblright", 600, NULL }, - { "center", 600, NULL }, - { "stop", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, { "cent", 600, NULL }, { "currency", 600, NULL }, { "logicalnot", 600, NULL }, - { "Idot", 600, NULL }, - { "merge", 600, NULL }, + { "zdotaccent", 600, NULL }, { "Atilde", 600, NULL }, { "breve", 600, NULL }, { "bar", 600, NULL }, { "fraction", 600, NULL }, { "less", 600, NULL }, - { "down", 600, NULL }, + { "ecaron", 600, NULL }, { "guilsinglleft", 600, NULL }, { "exclam", 600, NULL }, { "period", 600, NULL }, - { "arrowright", 600, NULL }, - { "format", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, { "greater", 600, NULL }, { "atilde", 600, NULL }, - { "ij", 600, NULL }, { "brokenbar", 600, NULL }, - { "arrowboth", 600, NULL }, { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, { "onesuperior", 600, NULL } }; static BuiltinFontWidth courierBoldWidthsTab[] = { { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, - { "arrowup", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, - { "LL", 600, NULL }, + { "edotaccent", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, { "ntilde", 600, NULL }, - { "left", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, { "yen", 600, NULL }, { "space", 600, NULL }, + { "Omacron", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, + { "aogonek", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, @@ -309,14 +374,18 @@ static BuiltinFontWidth courierBoldWidthsTab[] = { { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, + { "iogonek", 600, NULL }, { "backslash", 600, NULL }, { "L", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, @@ -325,9 +394,7 @@ static BuiltinFontWidth courierBoldWidthsTab[] = { { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, - { "tab", 600, NULL }, { "W", 600, NULL }, - { "ll", 600, NULL }, { "X", 600, NULL }, { "question", 600, NULL }, { "equal", 600, NULL }, @@ -335,6 +402,7 @@ static BuiltinFontWidth courierBoldWidthsTab[] = { { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, @@ -351,44 +419,57 @@ static BuiltinFontWidth courierBoldWidthsTab[] = { { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, - { "largebullet", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 600, NULL }, { "t", 600, NULL }, { "divide", 600, NULL }, { "u", 600, NULL }, + { "Ccaron", 600, NULL }, { "v", 600, NULL }, { "w", 600, NULL }, { "x", 600, NULL }, { "y", 600, NULL }, { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, { "Scaron", 600, NULL }, { "Lslash", 600, NULL }, { "semicolon", 600, NULL }, { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, { "trademark", 600, NULL }, { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, { "macron", 600, NULL }, { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, { "ellipsis", 600, NULL }, { "scaron", 600, NULL }, { "AE", 600, NULL }, { "Ucircumflex", 600, NULL }, { "lslash", 600, NULL }, - { "lira", 600, NULL }, { "quotedblleft", 600, NULL }, { "guilsinglright", 600, NULL }, { "hyphen", 600, NULL }, @@ -397,9 +478,11 @@ static BuiltinFontWidth courierBoldWidthsTab[] = { { "exclamdown", 600, NULL }, { "endash", 600, NULL }, { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, { "ecircumflex", 600, NULL }, - { "copyright", 600, NULL }, { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, { "Egrave", 600, NULL }, { "slash", 600, NULL }, { "Edieresis", 600, NULL }, @@ -407,14 +490,17 @@ static BuiltinFontWidth courierBoldWidthsTab[] = { { "Idieresis", 600, NULL }, { "parenleft", 600, NULL }, { "one", 600, NULL }, - { "ucircumflex", 600, NULL }, + { "emacron", 600, NULL }, { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, { "bracketleft", 600, NULL }, { "Ugrave", 600, NULL }, { "quoteright", 600, NULL }, { "Udieresis", 600, NULL }, { "perthousand", 600, NULL }, { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, { "Eacute", 600, NULL }, { "adieresis", 600, NULL }, { "egrave", 600, NULL }, @@ -430,139 +516,173 @@ static BuiltinFontWidth courierBoldWidthsTab[] = { { "five", 600, NULL }, { "udieresis", 600, NULL }, { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, { "threequarters", 600, NULL }, { "guillemotright", 600, NULL }, - { "ydieresis", 600, NULL }, { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, { "tilde", 600, NULL }, { "at", 600, NULL }, { "eacute", 600, NULL }, - { "Gcaron", 600, NULL }, { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, { "multiply", 600, NULL }, { "zero", 600, NULL }, { "eth", 600, NULL }, { "Scedilla", 600, NULL }, { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, { "uacute", 600, NULL }, { "braceleft", 600, NULL }, { "Thorn", 600, NULL }, { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, { "ccedilla", 600, NULL }, - { "gcaron", 600, NULL }, - { "scedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, { "Ocircumflex", 600, NULL }, { "Oacute", 600, NULL }, - { "arrowdown", 600, NULL }, + { "scedilla", 600, NULL }, { "ogonek", 600, NULL }, { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, { "thorn", 600, NULL }, { "degree", 600, NULL }, { "registered", 600, NULL }, + { "radical", 600, NULL }, { "Aring", 600, NULL }, { "percent", 600, NULL }, { "six", 600, NULL }, { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, { "two", 600, NULL }, + { "summation", 600, NULL }, { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, { "ocircumflex", 600, NULL }, { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, { "asciicircum", 600, NULL }, - { "square", 600, NULL }, { "aring", 600, NULL }, { "grave", 600, NULL }, + { "uogonek", 600, NULL }, { "bracketright", 600, NULL }, { "Iacute", 600, NULL }, { "ampersand", 600, NULL }, { "igrave", 600, NULL }, - { "return", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, { "plus", 600, NULL }, + { "uring", 600, NULL }, { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, { "threesuperior", 600, NULL }, { "acute", 600, NULL }, - { "notegraphic", 600, NULL }, { "section", 600, NULL }, - { "arrowleft", 600, NULL }, { "dieresis", 600, NULL }, { "iacute", 600, NULL }, { "quotedblbase", 600, NULL }, - { "up", 600, NULL }, + { "ncaron", 600, NULL }, { "florin", 600, NULL }, { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, { "fi", 600, NULL }, { "fl", 600, NULL }, { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, { "Icircumflex", 600, NULL }, { "guillemotleft", 600, NULL }, { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, { "seven", 600, NULL }, - { "prescription", 600, NULL }, - { "indent", 600, NULL }, - { "dectab", 600, NULL }, + { "Sacute", 600, NULL }, { "ordmasculine", 600, NULL }, { "dotlessi", 600, NULL }, { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, { "acircumflex", 600, NULL }, - { "IJ", 600, NULL }, - { "overscore", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, { "icircumflex", 600, NULL }, { "braceright", 600, NULL }, - { "graybox", 600, NULL }, { "quotedblright", 600, NULL }, - { "center", 600, NULL }, - { "stop", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, { "cent", 600, NULL }, { "currency", 600, NULL }, { "logicalnot", 600, NULL }, - { "merge", 600, NULL }, - { "Idot", 600, NULL }, + { "zdotaccent", 600, NULL }, { "Atilde", 600, NULL }, { "breve", 600, NULL }, { "bar", 600, NULL }, { "fraction", 600, NULL }, { "less", 600, NULL }, - { "down", 600, NULL }, + { "ecaron", 600, NULL }, { "guilsinglleft", 600, NULL }, { "exclam", 600, NULL }, { "period", 600, NULL }, - { "format", 600, NULL }, - { "arrowright", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, { "greater", 600, NULL }, - { "ij", 600, NULL }, { "atilde", 600, NULL }, { "brokenbar", 600, NULL }, - { "arrowboth", 600, NULL }, { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, { "onesuperior", 600, NULL } }; static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, - { "arrowup", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, - { "LL", 600, NULL }, + { "edotaccent", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, { "ntilde", 600, NULL }, - { "left", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, { "yen", 600, NULL }, { "space", 600, NULL }, + { "Omacron", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, + { "aogonek", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, @@ -572,14 +692,18 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, + { "iogonek", 600, NULL }, { "backslash", 600, NULL }, { "L", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, @@ -588,9 +712,7 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, - { "tab", 600, NULL }, { "W", 600, NULL }, - { "ll", 600, NULL }, { "X", 600, NULL }, { "question", 600, NULL }, { "equal", 600, NULL }, @@ -598,6 +720,7 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, @@ -614,44 +737,57 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, - { "largebullet", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 600, NULL }, { "t", 600, NULL }, { "divide", 600, NULL }, { "u", 600, NULL }, + { "Ccaron", 600, NULL }, { "v", 600, NULL }, { "w", 600, NULL }, { "x", 600, NULL }, { "y", 600, NULL }, { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, { "Scaron", 600, NULL }, { "Lslash", 600, NULL }, { "semicolon", 600, NULL }, { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, { "trademark", 600, NULL }, { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, { "macron", 600, NULL }, { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, { "ellipsis", 600, NULL }, { "scaron", 600, NULL }, { "AE", 600, NULL }, { "Ucircumflex", 600, NULL }, { "lslash", 600, NULL }, - { "lira", 600, NULL }, { "quotedblleft", 600, NULL }, { "guilsinglright", 600, NULL }, { "hyphen", 600, NULL }, @@ -660,9 +796,11 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "exclamdown", 600, NULL }, { "endash", 600, NULL }, { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, { "ecircumflex", 600, NULL }, - { "copyright", 600, NULL }, { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, { "Egrave", 600, NULL }, { "slash", 600, NULL }, { "Edieresis", 600, NULL }, @@ -670,14 +808,17 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "Idieresis", 600, NULL }, { "parenleft", 600, NULL }, { "one", 600, NULL }, - { "ucircumflex", 600, NULL }, + { "emacron", 600, NULL }, { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, { "bracketleft", 600, NULL }, { "Ugrave", 600, NULL }, { "quoteright", 600, NULL }, { "Udieresis", 600, NULL }, { "perthousand", 600, NULL }, { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, { "Eacute", 600, NULL }, { "adieresis", 600, NULL }, { "egrave", 600, NULL }, @@ -693,139 +834,173 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "five", 600, NULL }, { "udieresis", 600, NULL }, { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, { "threequarters", 600, NULL }, { "guillemotright", 600, NULL }, - { "ydieresis", 600, NULL }, { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, { "tilde", 600, NULL }, { "at", 600, NULL }, { "eacute", 600, NULL }, - { "Gcaron", 600, NULL }, { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, { "multiply", 600, NULL }, { "zero", 600, NULL }, { "eth", 600, NULL }, { "Scedilla", 600, NULL }, { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, { "uacute", 600, NULL }, { "braceleft", 600, NULL }, { "Thorn", 600, NULL }, { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, { "ccedilla", 600, NULL }, - { "gcaron", 600, NULL }, - { "scedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, { "Ocircumflex", 600, NULL }, { "Oacute", 600, NULL }, - { "arrowdown", 600, NULL }, + { "scedilla", 600, NULL }, { "ogonek", 600, NULL }, { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, { "thorn", 600, NULL }, { "degree", 600, NULL }, { "registered", 600, NULL }, + { "radical", 600, NULL }, { "Aring", 600, NULL }, { "percent", 600, NULL }, { "six", 600, NULL }, { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, { "two", 600, NULL }, + { "summation", 600, NULL }, { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, { "ocircumflex", 600, NULL }, { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, { "asciicircum", 600, NULL }, - { "square", 600, NULL }, { "aring", 600, NULL }, { "grave", 600, NULL }, + { "uogonek", 600, NULL }, { "bracketright", 600, NULL }, { "Iacute", 600, NULL }, { "ampersand", 600, NULL }, { "igrave", 600, NULL }, - { "return", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, { "plus", 600, NULL }, + { "uring", 600, NULL }, { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, { "threesuperior", 600, NULL }, { "acute", 600, NULL }, - { "notegraphic", 600, NULL }, { "section", 600, NULL }, - { "arrowleft", 600, NULL }, { "dieresis", 600, NULL }, { "iacute", 600, NULL }, { "quotedblbase", 600, NULL }, - { "up", 600, NULL }, + { "ncaron", 600, NULL }, { "florin", 600, NULL }, { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, { "fi", 600, NULL }, { "fl", 600, NULL }, { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, { "Icircumflex", 600, NULL }, { "guillemotleft", 600, NULL }, { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, { "seven", 600, NULL }, - { "prescription", 600, NULL }, - { "indent", 600, NULL }, - { "dectab", 600, NULL }, + { "Sacute", 600, NULL }, { "ordmasculine", 600, NULL }, { "dotlessi", 600, NULL }, { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, { "acircumflex", 600, NULL }, - { "IJ", 600, NULL }, - { "overscore", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, { "icircumflex", 600, NULL }, { "braceright", 600, NULL }, - { "graybox", 600, NULL }, { "quotedblright", 600, NULL }, - { "center", 600, NULL }, - { "stop", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, { "cent", 600, NULL }, { "currency", 600, NULL }, { "logicalnot", 600, NULL }, - { "merge", 600, NULL }, - { "Idot", 600, NULL }, + { "zdotaccent", 600, NULL }, { "Atilde", 600, NULL }, { "breve", 600, NULL }, { "bar", 600, NULL }, { "fraction", 600, NULL }, { "less", 600, NULL }, - { "down", 600, NULL }, + { "ecaron", 600, NULL }, { "guilsinglleft", 600, NULL }, { "exclam", 600, NULL }, { "period", 600, NULL }, - { "format", 600, NULL }, - { "arrowright", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, { "greater", 600, NULL }, - { "ij", 600, NULL }, { "atilde", 600, NULL }, { "brokenbar", 600, NULL }, - { "arrowboth", 600, NULL }, { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, { "onesuperior", 600, NULL } }; static BuiltinFontWidth courierObliqueWidthsTab[] = { { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, - { "arrowup", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, - { "LL", 600, NULL }, + { "edotaccent", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, { "ntilde", 600, NULL }, - { "left", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, { "yen", 600, NULL }, { "space", 600, NULL }, + { "Omacron", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, + { "aogonek", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, @@ -835,14 +1010,18 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = { { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, + { "iogonek", 600, NULL }, { "backslash", 600, NULL }, { "L", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, @@ -851,9 +1030,7 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = { { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, - { "tab", 600, NULL }, { "W", 600, NULL }, - { "ll", 600, NULL }, { "X", 600, NULL }, { "question", 600, NULL }, { "equal", 600, NULL }, @@ -861,6 +1038,7 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = { { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, @@ -877,44 +1055,57 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = { { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, - { "largebullet", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 600, NULL }, { "t", 600, NULL }, { "divide", 600, NULL }, { "u", 600, NULL }, + { "Ccaron", 600, NULL }, { "v", 600, NULL }, { "w", 600, NULL }, { "x", 600, NULL }, { "y", 600, NULL }, { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, { "Scaron", 600, NULL }, { "Lslash", 600, NULL }, { "semicolon", 600, NULL }, { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, { "trademark", 600, NULL }, { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, { "macron", 600, NULL }, { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, { "ellipsis", 600, NULL }, { "scaron", 600, NULL }, { "AE", 600, NULL }, { "Ucircumflex", 600, NULL }, { "lslash", 600, NULL }, - { "lira", 600, NULL }, { "quotedblleft", 600, NULL }, { "guilsinglright", 600, NULL }, { "hyphen", 600, NULL }, @@ -923,9 +1114,11 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = { { "exclamdown", 600, NULL }, { "endash", 600, NULL }, { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, { "ecircumflex", 600, NULL }, - { "copyright", 600, NULL }, { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, { "Egrave", 600, NULL }, { "slash", 600, NULL }, { "Edieresis", 600, NULL }, @@ -933,14 +1126,17 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = { { "Idieresis", 600, NULL }, { "parenleft", 600, NULL }, { "one", 600, NULL }, - { "ucircumflex", 600, NULL }, + { "emacron", 600, NULL }, { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, { "bracketleft", 600, NULL }, { "Ugrave", 600, NULL }, { "quoteright", 600, NULL }, { "Udieresis", 600, NULL }, { "perthousand", 600, NULL }, { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, { "Eacute", 600, NULL }, { "adieresis", 600, NULL }, { "egrave", 600, NULL }, @@ -956,136 +1152,173 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = { { "five", 600, NULL }, { "udieresis", 600, NULL }, { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, { "threequarters", 600, NULL }, { "guillemotright", 600, NULL }, - { "ydieresis", 600, NULL }, { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, { "tilde", 600, NULL }, { "at", 600, NULL }, { "eacute", 600, NULL }, - { "Gcaron", 600, NULL }, { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, { "multiply", 600, NULL }, { "zero", 600, NULL }, { "eth", 600, NULL }, { "Scedilla", 600, NULL }, { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, { "uacute", 600, NULL }, { "braceleft", 600, NULL }, { "Thorn", 600, NULL }, { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, { "ccedilla", 600, NULL }, - { "gcaron", 600, NULL }, - { "scedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, { "Ocircumflex", 600, NULL }, { "Oacute", 600, NULL }, - { "arrowdown", 600, NULL }, + { "scedilla", 600, NULL }, { "ogonek", 600, NULL }, { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, { "thorn", 600, NULL }, { "degree", 600, NULL }, { "registered", 600, NULL }, + { "radical", 600, NULL }, { "Aring", 600, NULL }, { "percent", 600, NULL }, { "six", 600, NULL }, { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, { "two", 600, NULL }, + { "summation", 600, NULL }, { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, { "ocircumflex", 600, NULL }, { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, { "asciicircum", 600, NULL }, - { "square", 600, NULL }, { "aring", 600, NULL }, { "grave", 600, NULL }, + { "uogonek", 600, NULL }, { "bracketright", 600, NULL }, { "Iacute", 600, NULL }, { "ampersand", 600, NULL }, { "igrave", 600, NULL }, - { "return", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, { "plus", 600, NULL }, + { "uring", 600, NULL }, { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, { "threesuperior", 600, NULL }, { "acute", 600, NULL }, - { "notegraphic", 600, NULL }, { "section", 600, NULL }, - { "arrowleft", 600, NULL }, { "dieresis", 600, NULL }, { "iacute", 600, NULL }, { "quotedblbase", 600, NULL }, - { "up", 600, NULL }, + { "ncaron", 600, NULL }, { "florin", 600, NULL }, { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, { "fi", 600, NULL }, { "fl", 600, NULL }, { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, { "Icircumflex", 600, NULL }, { "guillemotleft", 600, NULL }, { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, { "seven", 600, NULL }, - { "prescription", 600, NULL }, - { "indent", 600, NULL }, - { "dectab", 600, NULL }, + { "Sacute", 600, NULL }, { "ordmasculine", 600, NULL }, { "dotlessi", 600, NULL }, { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, { "acircumflex", 600, NULL }, - { "IJ", 600, NULL }, - { "overscore", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, { "icircumflex", 600, NULL }, { "braceright", 600, NULL }, - { "graybox", 600, NULL }, { "quotedblright", 600, NULL }, - { "center", 600, NULL }, - { "stop", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, { "cent", 600, NULL }, { "currency", 600, NULL }, { "logicalnot", 600, NULL }, - { "merge", 600, NULL }, - { "Idot", 600, NULL }, + { "zdotaccent", 600, NULL }, { "Atilde", 600, NULL }, { "breve", 600, NULL }, { "bar", 600, NULL }, { "fraction", 600, NULL }, { "less", 600, NULL }, - { "down", 600, NULL }, + { "ecaron", 600, NULL }, { "guilsinglleft", 600, NULL }, { "exclam", 600, NULL }, { "period", 600, NULL }, - { "format", 600, NULL }, - { "arrowright", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, { "greater", 600, NULL }, - { "ij", 600, NULL }, { "atilde", 600, NULL }, { "brokenbar", 600, NULL }, - { "arrowboth", 600, NULL }, { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, { "onesuperior", 600, NULL } }; static BuiltinFontWidth helveticaWidthsTab[] = { { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, { "comma", 278, NULL }, { "cedilla", 333, NULL }, { "plusminus", 584, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, { "asciitilde", 584, NULL }, { "colon", 278, NULL }, { "onehalf", 834, NULL }, { "dollar", 556, NULL }, + { "Lcaron", 556, NULL }, { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, { "yen", 556, NULL }, { "space", 278, NULL }, + { "Omacron", 778, NULL }, { "questiondown", 611, NULL }, { "emdash", 1000, NULL }, { "Agrave", 667, NULL }, { "three", 556, NULL }, { "numbersign", 556, NULL }, + { "lcaron", 299, NULL }, { "A", 667, NULL }, { "B", 667, NULL }, { "C", 722, NULL }, + { "aogonek", 556, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 834, NULL }, @@ -1095,14 +1328,18 @@ static BuiltinFontWidth helveticaWidthsTab[] = { { "I", 278, NULL }, { "J", 500, NULL }, { "K", 667, NULL }, + { "iogonek", 222, NULL }, { "backslash", 278, NULL }, { "L", 556, NULL }, { "periodcentered", 278, NULL }, { "M", 833, NULL }, { "N", 722, NULL }, + { "omacron", 556, NULL }, + { "Tcommaaccent", 611, NULL }, { "O", 778, NULL }, { "P", 667, NULL }, { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 667, NULL }, { "caron", 333, NULL }, @@ -1119,6 +1356,7 @@ static BuiltinFontWidth helveticaWidthsTab[] = { { "Z", 611, NULL }, { "four", 556, NULL }, { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, { "b", 556, NULL }, { "c", 500, NULL }, { "d", 556, NULL }, @@ -1135,11 +1373,13 @@ static BuiltinFontWidth helveticaWidthsTab[] = { { "l", 222, NULL }, { "m", 833, NULL }, { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, { "o", 556, NULL }, { "ordfeminine", 370, NULL }, { "ring", 333, NULL }, { "p", 556, NULL }, { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, { "r", 333, NULL }, { "twosuperior", 333, NULL }, { "aacute", 556, NULL }, @@ -1148,24 +1388,37 @@ static BuiltinFontWidth helveticaWidthsTab[] = { { "t", 278, NULL }, { "divide", 584, NULL }, { "u", 556, NULL }, + { "Ccaron", 722, NULL }, { "v", 500, NULL }, { "w", 722, NULL }, { "x", 500, NULL }, { "y", 500, NULL }, { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, { "quotedbl", 355, NULL }, + { "gcommaaccent", 556, NULL }, { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, { "Scaron", 667, NULL }, { "Lslash", 556, NULL }, { "semicolon", 278, NULL }, { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, { "parenright", 333, NULL }, + { "ccaron", 500, NULL }, { "Ecircumflex", 667, NULL }, + { "gbreve", 556, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 556, NULL }, + { "nacute", 556, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 500, NULL }, { "AE", 1000, NULL }, @@ -1179,9 +1432,11 @@ static BuiltinFontWidth helveticaWidthsTab[] = { { "exclamdown", 333, NULL }, { "endash", 556, NULL }, { "oe", 944, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, { "ecircumflex", 556, NULL }, - { "copyright", 737, NULL }, { "Adieresis", 667, NULL }, + { "copyright", 737, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, @@ -1189,14 +1444,17 @@ static BuiltinFontWidth helveticaWidthsTab[] = { { "Idieresis", 278, NULL }, { "parenleft", 333, NULL }, { "one", 556, NULL }, - { "ucircumflex", 556, NULL }, + { "emacron", 556, NULL }, { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, { "bracketleft", 278, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 222, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 667, NULL }, + { "umacron", 556, NULL }, + { "abreve", 556, NULL }, { "Eacute", 667, NULL }, { "adieresis", 556, NULL }, { "egrave", 556, NULL }, @@ -1212,111 +1470,173 @@ static BuiltinFontWidth helveticaWidthsTab[] = { { "five", 556, NULL }, { "udieresis", 556, NULL }, { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, { "threequarters", 834, NULL }, { "guillemotright", 556, NULL }, - { "ydieresis", 500, NULL }, { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, { "tilde", 333, NULL }, { "at", 1015, NULL }, { "eacute", 556, NULL }, { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, { "multiply", 584, NULL }, { "zero", 556, NULL }, { "eth", 556, NULL }, + { "Scedilla", 667, NULL }, { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 476, NULL }, { "uacute", 556, NULL }, { "braceleft", 334, NULL }, { "Thorn", 667, NULL }, { "zcaron", 500, NULL }, + { "scommaaccent", 500, NULL }, { "ccedilla", 500, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, + { "scedilla", 500, NULL }, { "ogonek", 333, NULL }, { "ograve", 556, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, { "thorn", 556, NULL }, { "degree", 400, NULL }, { "registered", 737, NULL }, + { "radical", 453, NULL }, { "Aring", 667, NULL }, { "percent", 889, NULL }, { "six", 556, NULL }, { "paragraph", 537, NULL }, + { "dcaron", 643, NULL }, + { "Uogonek", 722, NULL }, { "two", 556, NULL }, + { "summation", 600, NULL }, { "Igrave", 278, NULL }, + { "Lacute", 556, NULL }, { "ocircumflex", 556, NULL }, { "oacute", 556, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 317, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, { "asciicircum", 469, NULL }, { "aring", 556, NULL }, { "grave", 333, NULL }, + { "uogonek", 556, NULL }, { "bracketright", 278, NULL }, { "Iacute", 278, NULL }, { "ampersand", 667, NULL }, { "igrave", 278, NULL }, + { "lacute", 222, NULL }, + { "Ncaron", 722, NULL }, { "plus", 584, NULL }, + { "uring", 556, NULL }, { "quotesinglbase", 222, NULL }, + { "lcommaaccent", 222, NULL }, { "Yacute", 667, NULL }, + { "ohungarumlaut", 556, NULL }, { "threesuperior", 333, NULL }, { "acute", 333, NULL }, { "section", 556, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 333, NULL }, + { "ncaron", 556, NULL }, { "florin", 556, NULL }, { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, { "fi", 500, NULL }, { "fl", 500, NULL }, { "Acircumflex", 667, NULL }, + { "Cacute", 722, NULL }, { "Icircumflex", 278, NULL }, { "guillemotleft", 556, NULL }, { "germandbls", 611, NULL }, + { "Amacron", 667, NULL }, { "seven", 556, NULL }, + { "Sacute", 667, NULL }, { "ordmasculine", 365, NULL }, { "dotlessi", 278, NULL }, { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, { "acircumflex", 556, NULL }, + { "cacute", 500, NULL }, + { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 334, NULL }, { "quotedblright", 333, NULL }, + { "amacron", 556, NULL }, + { "sacute", 500, NULL }, + { "imacron", 278, NULL }, { "cent", 556, NULL }, { "currency", 556, NULL }, { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, { "Atilde", 667, NULL }, { "breve", 333, NULL }, { "bar", 260, NULL }, { "fraction", 167, NULL }, { "less", 584, NULL }, + { "ecaron", 556, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 278, NULL }, { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 667, NULL }, { "greater", 584, NULL }, { "atilde", 556, NULL }, { "brokenbar", 260, NULL }, { "quoteleft", 222, NULL }, + { "Edotaccent", 667, NULL }, { "onesuperior", 333, NULL } }; static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, { "comma", 278, NULL }, { "cedilla", 333, NULL }, { "plusminus", 584, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, { "asciitilde", 584, NULL }, { "colon", 333, NULL }, { "onehalf", 834, NULL }, { "dollar", 556, NULL }, + { "Lcaron", 611, NULL }, { "ntilde", 611, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 611, NULL }, { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, { "yen", 556, NULL }, { "space", 278, NULL }, + { "Omacron", 778, NULL }, { "questiondown", 611, NULL }, { "emdash", 1000, NULL }, { "Agrave", 722, NULL }, { "three", 556, NULL }, { "numbersign", 556, NULL }, + { "lcaron", 400, NULL }, { "A", 722, NULL }, { "B", 722, NULL }, { "C", 722, NULL }, + { "aogonek", 556, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 834, NULL }, @@ -1326,14 +1646,18 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "I", 278, NULL }, { "J", 556, NULL }, { "K", 722, NULL }, + { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 611, NULL }, { "periodcentered", 278, NULL }, { "M", 833, NULL }, { "N", 722, NULL }, + { "omacron", 611, NULL }, + { "Tcommaaccent", 611, NULL }, { "O", 778, NULL }, { "P", 667, NULL }, { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 722, NULL }, { "caron", 333, NULL }, @@ -1350,6 +1674,7 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "Z", 611, NULL }, { "four", 556, NULL }, { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, { "b", 611, NULL }, { "c", 556, NULL }, { "d", 611, NULL }, @@ -1366,11 +1691,13 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "l", 278, NULL }, { "m", 889, NULL }, { "n", 611, NULL }, + { "tcommaaccent", 333, NULL }, { "o", 611, NULL }, { "ordfeminine", 370, NULL }, { "ring", 333, NULL }, { "p", 611, NULL }, { "q", 611, NULL }, + { "uhungarumlaut", 611, NULL }, { "r", 389, NULL }, { "twosuperior", 333, NULL }, { "aacute", 556, NULL }, @@ -1379,24 +1706,37 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "t", 333, NULL }, { "divide", 584, NULL }, { "u", 611, NULL }, + { "Ccaron", 722, NULL }, { "v", 556, NULL }, { "w", 778, NULL }, { "x", 556, NULL }, { "y", 556, NULL }, { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, { "quotedbl", 474, NULL }, + { "gcommaaccent", 611, NULL }, { "mu", 611, NULL }, + { "greaterequal", 549, NULL }, { "Scaron", 667, NULL }, { "Lslash", 611, NULL }, { "semicolon", 333, NULL }, { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, { "parenright", 333, NULL }, + { "ccaron", 556, NULL }, { "Ecircumflex", 667, NULL }, + { "gbreve", 611, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 556, NULL }, + { "nacute", 611, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 556, NULL }, { "AE", 1000, NULL }, @@ -1410,9 +1750,11 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "exclamdown", 333, NULL }, { "endash", 556, NULL }, { "oe", 944, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, { "ecircumflex", 556, NULL }, - { "copyright", 737, NULL }, { "Adieresis", 722, NULL }, + { "copyright", 737, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, @@ -1420,14 +1762,17 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "Idieresis", 278, NULL }, { "parenleft", 333, NULL }, { "one", 556, NULL }, - { "ucircumflex", 611, NULL }, + { "emacron", 556, NULL }, { "Odieresis", 778, NULL }, + { "ucircumflex", 611, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 278, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 667, NULL }, + { "umacron", 611, NULL }, + { "abreve", 556, NULL }, { "Eacute", 667, NULL }, { "adieresis", 556, NULL }, { "egrave", 556, NULL }, @@ -1443,111 +1788,174 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "five", 556, NULL }, { "udieresis", 611, NULL }, { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, { "threequarters", 834, NULL }, { "guillemotright", 556, NULL }, - { "ydieresis", 556, NULL }, { "Ccedilla", 722, NULL }, + { "ydieresis", 556, NULL }, { "tilde", 333, NULL }, + { "dbldaggerumlaut", 556, NULL }, { "at", 975, NULL }, { "eacute", 556, NULL }, { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, { "multiply", 584, NULL }, { "zero", 556, NULL }, { "eth", 611, NULL }, + { "Scedilla", 667, NULL }, { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, { "uacute", 611, NULL }, { "braceleft", 389, NULL }, { "Thorn", 667, NULL }, { "zcaron", 500, NULL }, + { "scommaaccent", 556, NULL }, { "ccedilla", 556, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 611, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, + { "scedilla", 556, NULL }, { "ogonek", 333, NULL }, { "ograve", 611, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, { "thorn", 611, NULL }, { "degree", 400, NULL }, { "registered", 737, NULL }, + { "radical", 549, NULL }, { "Aring", 722, NULL }, { "percent", 889, NULL }, { "six", 556, NULL }, { "paragraph", 556, NULL }, + { "dcaron", 743, NULL }, + { "Uogonek", 722, NULL }, { "two", 556, NULL }, + { "summation", 600, NULL }, { "Igrave", 278, NULL }, + { "Lacute", 611, NULL }, { "ocircumflex", 611, NULL }, { "oacute", 611, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 389, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, { "asciicircum", 584, NULL }, { "aring", 556, NULL }, { "grave", 333, NULL }, + { "uogonek", 611, NULL }, { "bracketright", 333, NULL }, { "Iacute", 278, NULL }, { "ampersand", 722, NULL }, { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, { "plus", 584, NULL }, + { "uring", 611, NULL }, { "quotesinglbase", 278, NULL }, + { "lcommaaccent", 278, NULL }, { "Yacute", 667, NULL }, + { "ohungarumlaut", 611, NULL }, { "threesuperior", 333, NULL }, { "acute", 333, NULL }, { "section", 556, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 500, NULL }, + { "ncaron", 611, NULL }, { "florin", 556, NULL }, { "yacute", 556, NULL }, + { "Rcommaaccent", 722, NULL }, { "fi", 611, NULL }, { "fl", 611, NULL }, { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, { "Icircumflex", 278, NULL }, { "guillemotleft", 556, NULL }, { "germandbls", 611, NULL }, + { "Amacron", 722, NULL }, { "seven", 556, NULL }, + { "Sacute", 667, NULL }, { "ordmasculine", 365, NULL }, { "dotlessi", 278, NULL }, { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, { "acircumflex", 556, NULL }, + { "cacute", 556, NULL }, + { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 389, NULL }, { "quotedblright", 500, NULL }, + { "amacron", 556, NULL }, + { "sacute", 556, NULL }, + { "imacron", 278, NULL }, { "cent", 556, NULL }, { "currency", 556, NULL }, { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, { "Atilde", 722, NULL }, { "breve", 333, NULL }, { "bar", 280, NULL }, { "fraction", 167, NULL }, { "less", 584, NULL }, + { "ecaron", 556, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 722, NULL }, { "greater", 584, NULL }, { "atilde", 556, NULL }, { "brokenbar", 280, NULL }, { "quoteleft", 278, NULL }, + { "Edotaccent", 667, NULL }, { "onesuperior", 333, NULL } }; static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, { "comma", 278, NULL }, { "cedilla", 333, NULL }, { "plusminus", 584, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, { "asciitilde", 584, NULL }, { "colon", 333, NULL }, { "onehalf", 834, NULL }, { "dollar", 556, NULL }, + { "Lcaron", 611, NULL }, { "ntilde", 611, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 611, NULL }, { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, { "yen", 556, NULL }, { "space", 278, NULL }, + { "Omacron", 778, NULL }, { "questiondown", 611, NULL }, { "emdash", 1000, NULL }, { "Agrave", 722, NULL }, { "three", 556, NULL }, { "numbersign", 556, NULL }, + { "lcaron", 400, NULL }, { "A", 722, NULL }, { "B", 722, NULL }, { "C", 722, NULL }, + { "aogonek", 556, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 834, NULL }, @@ -1557,14 +1965,18 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "I", 278, NULL }, { "J", 556, NULL }, { "K", 722, NULL }, + { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 611, NULL }, { "periodcentered", 278, NULL }, { "M", 833, NULL }, { "N", 722, NULL }, + { "omacron", 611, NULL }, + { "Tcommaaccent", 611, NULL }, { "O", 778, NULL }, { "P", 667, NULL }, { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 722, NULL }, { "caron", 333, NULL }, @@ -1581,6 +1993,7 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "Z", 611, NULL }, { "four", 556, NULL }, { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, { "b", 611, NULL }, { "c", 556, NULL }, { "d", 611, NULL }, @@ -1597,11 +2010,13 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "l", 278, NULL }, { "m", 889, NULL }, { "n", 611, NULL }, + { "tcommaaccent", 333, NULL }, { "o", 611, NULL }, { "ordfeminine", 370, NULL }, { "ring", 333, NULL }, { "p", 611, NULL }, { "q", 611, NULL }, + { "uhungarumlaut", 611, NULL }, { "r", 389, NULL }, { "twosuperior", 333, NULL }, { "aacute", 556, NULL }, @@ -1610,24 +2025,37 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "t", 333, NULL }, { "divide", 584, NULL }, { "u", 611, NULL }, + { "Ccaron", 722, NULL }, { "v", 556, NULL }, { "w", 778, NULL }, { "x", 556, NULL }, { "y", 556, NULL }, { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, { "quotedbl", 474, NULL }, + { "gcommaaccent", 611, NULL }, { "mu", 611, NULL }, + { "greaterequal", 549, NULL }, { "Scaron", 667, NULL }, { "Lslash", 611, NULL }, { "semicolon", 333, NULL }, { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, { "parenright", 333, NULL }, + { "ccaron", 556, NULL }, { "Ecircumflex", 667, NULL }, + { "gbreve", 611, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 556, NULL }, + { "nacute", 611, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 556, NULL }, { "AE", 1000, NULL }, @@ -1641,9 +2069,11 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "exclamdown", 333, NULL }, { "endash", 556, NULL }, { "oe", 944, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, { "ecircumflex", 556, NULL }, - { "copyright", 737, NULL }, { "Adieresis", 722, NULL }, + { "copyright", 737, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, @@ -1651,14 +2081,17 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "Idieresis", 278, NULL }, { "parenleft", 333, NULL }, { "one", 556, NULL }, - { "ucircumflex", 611, NULL }, + { "emacron", 556, NULL }, { "Odieresis", 778, NULL }, + { "ucircumflex", 611, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 278, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 667, NULL }, + { "umacron", 611, NULL }, + { "abreve", 556, NULL }, { "Eacute", 667, NULL }, { "adieresis", 556, NULL }, { "egrave", 556, NULL }, @@ -1674,111 +2107,173 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "five", 556, NULL }, { "udieresis", 611, NULL }, { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, { "threequarters", 834, NULL }, { "guillemotright", 556, NULL }, - { "ydieresis", 556, NULL }, { "Ccedilla", 722, NULL }, + { "ydieresis", 556, NULL }, { "tilde", 333, NULL }, { "at", 975, NULL }, { "eacute", 556, NULL }, { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, { "multiply", 584, NULL }, { "zero", 556, NULL }, { "eth", 611, NULL }, + { "Scedilla", 667, NULL }, { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, { "uacute", 611, NULL }, { "braceleft", 389, NULL }, { "Thorn", 667, NULL }, { "zcaron", 500, NULL }, + { "scommaaccent", 556, NULL }, { "ccedilla", 556, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 611, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, + { "scedilla", 556, NULL }, { "ogonek", 333, NULL }, { "ograve", 611, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, { "thorn", 611, NULL }, { "degree", 400, NULL }, { "registered", 737, NULL }, + { "radical", 549, NULL }, { "Aring", 722, NULL }, { "percent", 889, NULL }, { "six", 556, NULL }, { "paragraph", 556, NULL }, + { "dcaron", 743, NULL }, + { "Uogonek", 722, NULL }, { "two", 556, NULL }, + { "summation", 600, NULL }, { "Igrave", 278, NULL }, + { "Lacute", 611, NULL }, { "ocircumflex", 611, NULL }, { "oacute", 611, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 389, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, { "asciicircum", 584, NULL }, { "aring", 556, NULL }, { "grave", 333, NULL }, + { "uogonek", 611, NULL }, { "bracketright", 333, NULL }, { "Iacute", 278, NULL }, { "ampersand", 722, NULL }, { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, { "plus", 584, NULL }, + { "uring", 611, NULL }, { "quotesinglbase", 278, NULL }, + { "lcommaaccent", 278, NULL }, { "Yacute", 667, NULL }, + { "ohungarumlaut", 611, NULL }, { "threesuperior", 333, NULL }, { "acute", 333, NULL }, { "section", 556, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 500, NULL }, + { "ncaron", 611, NULL }, { "florin", 556, NULL }, { "yacute", 556, NULL }, + { "Rcommaaccent", 722, NULL }, { "fi", 611, NULL }, { "fl", 611, NULL }, { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, { "Icircumflex", 278, NULL }, { "guillemotleft", 556, NULL }, { "germandbls", 611, NULL }, + { "Amacron", 722, NULL }, { "seven", 556, NULL }, + { "Sacute", 667, NULL }, { "ordmasculine", 365, NULL }, { "dotlessi", 278, NULL }, { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, { "acircumflex", 556, NULL }, + { "cacute", 556, NULL }, + { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 389, NULL }, { "quotedblright", 500, NULL }, + { "amacron", 556, NULL }, + { "sacute", 556, NULL }, + { "imacron", 278, NULL }, { "cent", 556, NULL }, { "currency", 556, NULL }, { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, { "Atilde", 722, NULL }, { "breve", 333, NULL }, { "bar", 280, NULL }, { "fraction", 167, NULL }, { "less", 584, NULL }, + { "ecaron", 556, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 722, NULL }, { "greater", 584, NULL }, { "atilde", 556, NULL }, { "brokenbar", 280, NULL }, { "quoteleft", 278, NULL }, + { "Edotaccent", 667, NULL }, { "onesuperior", 333, NULL } }; static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, { "comma", 278, NULL }, { "cedilla", 333, NULL }, { "plusminus", 584, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, { "asciitilde", 584, NULL }, { "colon", 278, NULL }, { "onehalf", 834, NULL }, { "dollar", 556, NULL }, + { "Lcaron", 556, NULL }, { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, { "yen", 556, NULL }, { "space", 278, NULL }, + { "Omacron", 778, NULL }, { "questiondown", 611, NULL }, { "emdash", 1000, NULL }, { "Agrave", 667, NULL }, { "three", 556, NULL }, { "numbersign", 556, NULL }, + { "lcaron", 299, NULL }, { "A", 667, NULL }, { "B", 667, NULL }, { "C", 722, NULL }, + { "aogonek", 556, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 834, NULL }, @@ -1788,14 +2283,18 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "I", 278, NULL }, { "J", 500, NULL }, { "K", 667, NULL }, + { "iogonek", 222, NULL }, { "backslash", 278, NULL }, { "L", 556, NULL }, { "periodcentered", 278, NULL }, { "M", 833, NULL }, { "N", 722, NULL }, + { "omacron", 556, NULL }, + { "Tcommaaccent", 611, NULL }, { "O", 778, NULL }, { "P", 667, NULL }, { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 667, NULL }, { "caron", 333, NULL }, @@ -1812,6 +2311,7 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "Z", 611, NULL }, { "four", 556, NULL }, { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, { "b", 556, NULL }, { "c", 500, NULL }, { "d", 556, NULL }, @@ -1828,11 +2328,13 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "l", 222, NULL }, { "m", 833, NULL }, { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, { "o", 556, NULL }, { "ordfeminine", 370, NULL }, { "ring", 333, NULL }, { "p", 556, NULL }, { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, { "r", 333, NULL }, { "twosuperior", 333, NULL }, { "aacute", 556, NULL }, @@ -1841,24 +2343,37 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "t", 278, NULL }, { "divide", 584, NULL }, { "u", 556, NULL }, + { "Ccaron", 722, NULL }, { "v", 500, NULL }, { "w", 722, NULL }, { "x", 500, NULL }, { "y", 500, NULL }, { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, { "quotedbl", 355, NULL }, + { "gcommaaccent", 556, NULL }, { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, { "Scaron", 667, NULL }, { "Lslash", 556, NULL }, { "semicolon", 278, NULL }, { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, { "parenright", 333, NULL }, + { "ccaron", 500, NULL }, { "Ecircumflex", 667, NULL }, + { "gbreve", 556, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 556, NULL }, + { "nacute", 556, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 500, NULL }, { "AE", 1000, NULL }, @@ -1872,9 +2387,11 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "exclamdown", 333, NULL }, { "endash", 556, NULL }, { "oe", 944, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, { "ecircumflex", 556, NULL }, - { "copyright", 737, NULL }, { "Adieresis", 667, NULL }, + { "copyright", 737, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, @@ -1882,14 +2399,17 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "Idieresis", 278, NULL }, { "parenleft", 333, NULL }, { "one", 556, NULL }, - { "ucircumflex", 556, NULL }, + { "emacron", 556, NULL }, { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, { "bracketleft", 278, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 222, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 667, NULL }, + { "umacron", 556, NULL }, + { "abreve", 556, NULL }, { "Eacute", 667, NULL }, { "adieresis", 556, NULL }, { "egrave", 556, NULL }, @@ -1905,85 +2425,134 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "five", 556, NULL }, { "udieresis", 556, NULL }, { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, { "threequarters", 834, NULL }, { "guillemotright", 556, NULL }, - { "ydieresis", 500, NULL }, { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, { "tilde", 333, NULL }, { "at", 1015, NULL }, { "eacute", 556, NULL }, { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, { "multiply", 584, NULL }, { "zero", 556, NULL }, { "eth", 556, NULL }, + { "Scedilla", 667, NULL }, { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 476, NULL }, { "uacute", 556, NULL }, { "braceleft", 334, NULL }, { "Thorn", 667, NULL }, { "zcaron", 500, NULL }, + { "scommaaccent", 500, NULL }, { "ccedilla", 500, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, + { "scedilla", 500, NULL }, { "ogonek", 333, NULL }, { "ograve", 556, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, { "thorn", 556, NULL }, { "degree", 400, NULL }, { "registered", 737, NULL }, + { "radical", 453, NULL }, { "Aring", 667, NULL }, { "percent", 889, NULL }, { "six", 556, NULL }, { "paragraph", 537, NULL }, + { "dcaron", 643, NULL }, + { "Uogonek", 722, NULL }, { "two", 556, NULL }, + { "summation", 600, NULL }, { "Igrave", 278, NULL }, + { "Lacute", 556, NULL }, { "ocircumflex", 556, NULL }, { "oacute", 556, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 317, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, { "asciicircum", 469, NULL }, { "aring", 556, NULL }, { "grave", 333, NULL }, + { "uogonek", 556, NULL }, { "bracketright", 278, NULL }, { "Iacute", 278, NULL }, { "ampersand", 667, NULL }, { "igrave", 278, NULL }, + { "lacute", 222, NULL }, + { "Ncaron", 722, NULL }, { "plus", 584, NULL }, + { "uring", 556, NULL }, { "quotesinglbase", 222, NULL }, + { "lcommaaccent", 222, NULL }, { "Yacute", 667, NULL }, + { "ohungarumlaut", 556, NULL }, { "threesuperior", 333, NULL }, { "acute", 333, NULL }, { "section", 556, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 333, NULL }, + { "ncaron", 556, NULL }, { "florin", 556, NULL }, { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, { "fi", 500, NULL }, { "fl", 500, NULL }, { "Acircumflex", 667, NULL }, + { "Cacute", 722, NULL }, { "Icircumflex", 278, NULL }, { "guillemotleft", 556, NULL }, { "germandbls", 611, NULL }, + { "Amacron", 667, NULL }, { "seven", 556, NULL }, + { "Sacute", 667, NULL }, { "ordmasculine", 365, NULL }, { "dotlessi", 278, NULL }, { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, { "acircumflex", 556, NULL }, + { "cacute", 500, NULL }, + { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 334, NULL }, { "quotedblright", 333, NULL }, + { "amacron", 556, NULL }, + { "sacute", 500, NULL }, + { "imacron", 278, NULL }, { "cent", 556, NULL }, { "currency", 556, NULL }, { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, { "Atilde", 667, NULL }, { "breve", 333, NULL }, { "bar", 260, NULL }, { "fraction", 167, NULL }, { "less", 584, NULL }, + { "ecaron", 556, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 278, NULL }, { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 667, NULL }, { "greater", 584, NULL }, { "atilde", 556, NULL }, { "brokenbar", 260, NULL }, { "quoteleft", 222, NULL }, + { "Edotaccent", 667, NULL }, { "onesuperior", 333, NULL } }; @@ -2098,6 +2667,7 @@ static BuiltinFontWidth symbolWidthsTab[] = { { "parenrighttp", 384, NULL }, { "eta", 603, NULL }, { "underscore", 500, NULL }, + { "Euro", 750, NULL }, { "multiply", 549, NULL }, { "zero", 500, NULL }, { "partialdiff", 494, NULL }, @@ -2181,27 +2751,40 @@ static BuiltinFontWidth symbolWidthsTab[] = { static BuiltinFontWidth timesBoldWidthsTab[] = { { "Ntilde", 722, NULL }, + { "rcaron", 444, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 667, NULL }, { "comma", 250, NULL }, { "cedilla", 333, NULL }, { "plusminus", 570, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, { "asciitilde", 520, NULL }, { "colon", 333, NULL }, { "onehalf", 750, NULL }, { "dollar", 500, NULL }, + { "Lcaron", 667, NULL }, { "ntilde", 556, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 556, NULL }, { "minus", 570, NULL }, + { "Iogonek", 389, NULL }, + { "zacute", 444, NULL }, { "yen", 500, NULL }, { "space", 250, NULL }, + { "Omacron", 778, NULL }, { "questiondown", 500, NULL }, { "emdash", 1000, NULL }, { "Agrave", 722, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, + { "lcaron", 394, NULL }, { "A", 722, NULL }, { "B", 667, NULL }, { "C", 722, NULL }, + { "aogonek", 500, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 750, NULL }, @@ -2211,14 +2794,18 @@ static BuiltinFontWidth timesBoldWidthsTab[] = { { "I", 389, NULL }, { "J", 500, NULL }, { "K", 778, NULL }, + { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 667, NULL }, { "periodcentered", 250, NULL }, { "M", 944, NULL }, { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 667, NULL }, { "O", 778, NULL }, { "P", 611, NULL }, { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 722, NULL }, { "caron", 333, NULL }, @@ -2235,6 +2822,7 @@ static BuiltinFontWidth timesBoldWidthsTab[] = { { "Z", 667, NULL }, { "four", 500, NULL }, { "a", 500, NULL }, + { "Gcommaaccent", 778, NULL }, { "b", 556, NULL }, { "c", 444, NULL }, { "d", 556, NULL }, @@ -2251,11 +2839,13 @@ static BuiltinFontWidth timesBoldWidthsTab[] = { { "l", 278, NULL }, { "m", 833, NULL }, { "n", 556, NULL }, + { "tcommaaccent", 333, NULL }, { "o", 500, NULL }, { "ordfeminine", 300, NULL }, { "ring", 333, NULL }, { "p", 556, NULL }, { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, { "r", 444, NULL }, { "twosuperior", 300, NULL }, { "aacute", 500, NULL }, @@ -2264,24 +2854,37 @@ static BuiltinFontWidth timesBoldWidthsTab[] = { { "t", 333, NULL }, { "divide", 570, NULL }, { "u", 556, NULL }, + { "Ccaron", 722, NULL }, { "v", 500, NULL }, { "w", 722, NULL }, { "x", 500, NULL }, { "y", 500, NULL }, { "z", 444, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, + { "Idotaccent", 389, NULL }, + { "Nacute", 722, NULL }, { "quotedbl", 555, NULL }, + { "gcommaaccent", 500, NULL }, { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, { "Scaron", 556, NULL }, { "Lslash", 667, NULL }, { "semicolon", 333, NULL }, { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, { "Ecircumflex", 667, NULL }, + { "gbreve", 500, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 500, NULL }, + { "nacute", 556, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 389, NULL }, { "AE", 1000, NULL }, @@ -2295,9 +2898,11 @@ static BuiltinFontWidth timesBoldWidthsTab[] = { { "exclamdown", 333, NULL }, { "endash", 500, NULL }, { "oe", 722, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, { "ecircumflex", 444, NULL }, - { "copyright", 747, NULL }, { "Adieresis", 722, NULL }, + { "copyright", 747, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, @@ -2305,14 +2910,17 @@ static BuiltinFontWidth timesBoldWidthsTab[] = { { "Idieresis", 389, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, - { "ucircumflex", 556, NULL }, + { "emacron", 444, NULL }, { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 333, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 722, NULL }, + { "umacron", 556, NULL }, + { "abreve", 500, NULL }, { "Eacute", 667, NULL }, { "adieresis", 500, NULL }, { "egrave", 444, NULL }, @@ -2328,111 +2936,173 @@ static BuiltinFontWidth timesBoldWidthsTab[] = { { "five", 500, NULL }, { "udieresis", 556, NULL }, { "Zcaron", 667, NULL }, + { "Scommaaccent", 556, NULL }, { "threequarters", 750, NULL }, { "guillemotright", 500, NULL }, - { "ydieresis", 500, NULL }, { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, { "tilde", 333, NULL }, { "at", 930, NULL }, { "eacute", 444, NULL }, { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, { "multiply", 570, NULL }, { "zero", 500, NULL }, { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, { "uacute", 556, NULL }, { "braceleft", 394, NULL }, { "Thorn", 611, NULL }, { "zcaron", 444, NULL }, + { "scommaaccent", 389, NULL }, { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, + { "scedilla", 389, NULL }, { "ogonek", 333, NULL }, { "ograve", 500, NULL }, + { "racute", 444, NULL }, + { "Tcaron", 667, NULL }, + { "Eogonek", 667, NULL }, { "thorn", 556, NULL }, { "degree", 400, NULL }, { "registered", 747, NULL }, + { "radical", 549, NULL }, { "Aring", 722, NULL }, { "percent", 1000, NULL }, { "six", 500, NULL }, { "paragraph", 540, NULL }, + { "dcaron", 672, NULL }, + { "Uogonek", 722, NULL }, { "two", 500, NULL }, + { "summation", 600, NULL }, { "Igrave", 389, NULL }, + { "Lacute", 667, NULL }, { "ocircumflex", 500, NULL }, { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 667, NULL }, + { "tcaron", 416, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, { "asciicircum", 581, NULL }, { "aring", 500, NULL }, { "grave", 333, NULL }, + { "uogonek", 556, NULL }, { "bracketright", 333, NULL }, { "Iacute", 389, NULL }, { "ampersand", 833, NULL }, { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, { "plus", 570, NULL }, + { "uring", 556, NULL }, { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, { "Yacute", 722, NULL }, + { "ohungarumlaut", 500, NULL }, { "threesuperior", 300, NULL }, { "acute", 333, NULL }, { "section", 500, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 500, NULL }, + { "ncaron", 556, NULL }, { "florin", 500, NULL }, { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, { "fi", 556, NULL }, { "fl", 556, NULL }, { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, { "Icircumflex", 389, NULL }, { "guillemotleft", 500, NULL }, { "germandbls", 556, NULL }, + { "Amacron", 722, NULL }, { "seven", 500, NULL }, + { "Sacute", 556, NULL }, { "ordmasculine", 330, NULL }, { "dotlessi", 278, NULL }, { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 389, NULL }, + { "rcommaaccent", 444, NULL }, + { "Zdotaccent", 667, NULL }, { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 394, NULL }, { "quotedblright", 500, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, { "cent", 500, NULL }, { "currency", 500, NULL }, { "logicalnot", 570, NULL }, + { "zdotaccent", 444, NULL }, { "Atilde", 722, NULL }, { "breve", 333, NULL }, { "bar", 220, NULL }, { "fraction", 167, NULL }, { "less", 570, NULL }, + { "ecaron", 444, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 250, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 778, NULL }, { "greater", 570, NULL }, { "atilde", 500, NULL }, { "brokenbar", 220, NULL }, { "quoteleft", 333, NULL }, + { "Edotaccent", 667, NULL }, { "onesuperior", 300, NULL } }; static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, { "comma", 250, NULL }, { "cedilla", 333, NULL }, { "plusminus", 570, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, { "asciitilde", 570, NULL }, { "colon", 333, NULL }, { "onehalf", 750, NULL }, { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, { "minus", 606, NULL }, + { "Iogonek", 389, NULL }, + { "zacute", 389, NULL }, { "yen", 500, NULL }, { "space", 250, NULL }, + { "Omacron", 722, NULL }, { "questiondown", 500, NULL }, { "emdash", 1000, NULL }, { "Agrave", 667, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, + { "lcaron", 382, NULL }, { "A", 667, NULL }, { "B", 667, NULL }, { "C", 667, NULL }, + { "aogonek", 500, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 750, NULL }, @@ -2442,14 +3112,18 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "I", 389, NULL }, { "J", 500, NULL }, { "K", 667, NULL }, + { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 611, NULL }, { "periodcentered", 250, NULL }, { "M", 889, NULL }, { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 611, NULL }, { "O", 722, NULL }, { "P", 611, NULL }, { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, { "R", 667, NULL }, { "Aacute", 667, NULL }, { "caron", 333, NULL }, @@ -2466,6 +3140,7 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "Z", 611, NULL }, { "four", 500, NULL }, { "a", 500, NULL }, + { "Gcommaaccent", 722, NULL }, { "b", 500, NULL }, { "c", 444, NULL }, { "d", 500, NULL }, @@ -2482,11 +3157,13 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "l", 278, NULL }, { "m", 778, NULL }, { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, { "o", 500, NULL }, { "ordfeminine", 266, NULL }, { "ring", 333, NULL }, { "p", 500, NULL }, { "q", 500, NULL }, + { "uhungarumlaut", 556, NULL }, { "r", 389, NULL }, { "twosuperior", 300, NULL }, { "aacute", 500, NULL }, @@ -2495,24 +3172,37 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "t", 278, NULL }, { "divide", 570, NULL }, { "u", 556, NULL }, + { "Ccaron", 667, NULL }, { "v", 444, NULL }, { "w", 667, NULL }, { "x", 500, NULL }, { "y", 444, NULL }, { "z", 389, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, + { "Idotaccent", 389, NULL }, + { "Nacute", 722, NULL }, { "quotedbl", 555, NULL }, + { "gcommaaccent", 500, NULL }, { "mu", 576, NULL }, + { "greaterequal", 549, NULL }, { "Scaron", 556, NULL }, { "Lslash", 611, NULL }, { "semicolon", 333, NULL }, { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, { "Ecircumflex", 667, NULL }, + { "gbreve", 500, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 500, NULL }, + { "nacute", 556, NULL }, { "macron", 333, NULL }, { "Otilde", 722, NULL }, + { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 389, NULL }, { "AE", 944, NULL }, @@ -2526,9 +3216,11 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "exclamdown", 389, NULL }, { "endash", 500, NULL }, { "oe", 722, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, { "ecircumflex", 444, NULL }, - { "copyright", 747, NULL }, { "Adieresis", 667, NULL }, + { "copyright", 747, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, @@ -2536,14 +3228,17 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "Idieresis", 389, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, - { "ucircumflex", 556, NULL }, + { "emacron", 444, NULL }, { "Odieresis", 722, NULL }, + { "ucircumflex", 556, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 333, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 611, NULL }, + { "umacron", 556, NULL }, + { "abreve", 500, NULL }, { "Eacute", 667, NULL }, { "adieresis", 500, NULL }, { "egrave", 444, NULL }, @@ -2559,111 +3254,173 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "five", 500, NULL }, { "udieresis", 556, NULL }, { "Zcaron", 611, NULL }, + { "Scommaaccent", 556, NULL }, { "threequarters", 750, NULL }, { "guillemotright", 500, NULL }, - { "ydieresis", 444, NULL }, { "Ccedilla", 667, NULL }, + { "ydieresis", 444, NULL }, { "tilde", 333, NULL }, { "at", 832, NULL }, { "eacute", 444, NULL }, { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, { "multiply", 570, NULL }, { "zero", 500, NULL }, { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, { "Ograve", 722, NULL }, + { "Racute", 667, NULL }, + { "partialdiff", 494, NULL }, { "uacute", 556, NULL }, { "braceleft", 348, NULL }, { "Thorn", 611, NULL }, { "zcaron", 389, NULL }, + { "scommaaccent", 389, NULL }, { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, { "Ocircumflex", 722, NULL }, { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, { "ogonek", 333, NULL }, { "ograve", 500, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, { "thorn", 500, NULL }, { "degree", 400, NULL }, { "registered", 747, NULL }, + { "radical", 549, NULL }, { "Aring", 667, NULL }, { "percent", 833, NULL }, { "six", 500, NULL }, { "paragraph", 500, NULL }, + { "dcaron", 608, NULL }, + { "Uogonek", 722, NULL }, { "two", 500, NULL }, + { "summation", 600, NULL }, { "Igrave", 389, NULL }, + { "Lacute", 611, NULL }, { "ocircumflex", 500, NULL }, { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 366, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, { "asciicircum", 570, NULL }, { "aring", 500, NULL }, { "grave", 333, NULL }, + { "uogonek", 556, NULL }, { "bracketright", 333, NULL }, { "Iacute", 389, NULL }, { "ampersand", 778, NULL }, { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, { "plus", 570, NULL }, + { "uring", 556, NULL }, { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, { "Yacute", 611, NULL }, + { "ohungarumlaut", 500, NULL }, { "threesuperior", 300, NULL }, { "acute", 333, NULL }, { "section", 500, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 500, NULL }, + { "ncaron", 556, NULL }, { "florin", 500, NULL }, { "yacute", 444, NULL }, + { "Rcommaaccent", 667, NULL }, { "fi", 556, NULL }, { "fl", 556, NULL }, { "Acircumflex", 667, NULL }, + { "Cacute", 667, NULL }, { "Icircumflex", 389, NULL }, { "guillemotleft", 500, NULL }, { "germandbls", 500, NULL }, + { "Amacron", 667, NULL }, { "seven", 500, NULL }, + { "Sacute", 556, NULL }, { "ordmasculine", 300, NULL }, { "dotlessi", 278, NULL }, { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 389, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 348, NULL }, { "quotedblright", 500, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, { "cent", 500, NULL }, { "currency", 500, NULL }, { "logicalnot", 606, NULL }, + { "zdotaccent", 389, NULL }, { "Atilde", 667, NULL }, { "breve", 333, NULL }, { "bar", 220, NULL }, { "fraction", 167, NULL }, { "less", 570, NULL }, + { "ecaron", 444, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 389, NULL }, { "period", 250, NULL }, + { "Rcaron", 667, NULL }, + { "Kcommaaccent", 667, NULL }, { "greater", 570, NULL }, { "atilde", 500, NULL }, { "brokenbar", 220, NULL }, { "quoteleft", 333, NULL }, + { "Edotaccent", 667, NULL }, { "onesuperior", 300, NULL } }; static BuiltinFontWidth timesItalicWidthsTab[] = { { "Ntilde", 667, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 444, NULL }, + { "Ncommaaccent", 667, NULL }, + { "Zacute", 556, NULL }, { "comma", 250, NULL }, { "cedilla", 333, NULL }, { "plusminus", 675, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, { "asciitilde", 541, NULL }, { "colon", 333, NULL }, { "onehalf", 750, NULL }, { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, { "ntilde", 500, NULL }, + { "Aogonek", 611, NULL }, + { "ncommaaccent", 500, NULL }, { "minus", 675, NULL }, + { "Iogonek", 333, NULL }, + { "zacute", 389, NULL }, { "yen", 500, NULL }, { "space", 250, NULL }, + { "Omacron", 722, NULL }, { "questiondown", 500, NULL }, { "emdash", 889, NULL }, { "Agrave", 611, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, + { "lcaron", 300, NULL }, { "A", 611, NULL }, { "B", 611, NULL }, { "C", 667, NULL }, + { "aogonek", 500, NULL }, { "D", 722, NULL }, { "E", 611, NULL }, { "onequarter", 750, NULL }, @@ -2673,14 +3430,18 @@ static BuiltinFontWidth timesItalicWidthsTab[] = { { "I", 333, NULL }, { "J", 444, NULL }, { "K", 667, NULL }, + { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 556, NULL }, { "periodcentered", 250, NULL }, { "M", 833, NULL }, { "N", 667, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 556, NULL }, { "O", 722, NULL }, { "P", 611, NULL }, { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, { "R", 611, NULL }, { "Aacute", 611, NULL }, { "caron", 333, NULL }, @@ -2697,6 +3458,7 @@ static BuiltinFontWidth timesItalicWidthsTab[] = { { "Z", 556, NULL }, { "four", 500, NULL }, { "a", 500, NULL }, + { "Gcommaaccent", 722, NULL }, { "b", 500, NULL }, { "c", 444, NULL }, { "d", 500, NULL }, @@ -2713,11 +3475,13 @@ static BuiltinFontWidth timesItalicWidthsTab[] = { { "l", 278, NULL }, { "m", 722, NULL }, { "n", 500, NULL }, + { "tcommaaccent", 278, NULL }, { "o", 500, NULL }, { "ordfeminine", 276, NULL }, { "ring", 333, NULL }, { "p", 500, NULL }, { "q", 500, NULL }, + { "uhungarumlaut", 500, NULL }, { "r", 389, NULL }, { "twosuperior", 300, NULL }, { "aacute", 500, NULL }, @@ -2726,24 +3490,37 @@ static BuiltinFontWidth timesItalicWidthsTab[] = { { "t", 278, NULL }, { "divide", 675, NULL }, { "u", 500, NULL }, + { "Ccaron", 667, NULL }, { "v", 444, NULL }, { "w", 667, NULL }, { "x", 444, NULL }, { "y", 444, NULL }, { "z", 389, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, + { "Idotaccent", 333, NULL }, + { "Nacute", 667, NULL }, { "quotedbl", 420, NULL }, + { "gcommaaccent", 500, NULL }, { "mu", 500, NULL }, + { "greaterequal", 549, NULL }, { "Scaron", 500, NULL }, { "Lslash", 556, NULL }, { "semicolon", 333, NULL }, { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, { "Ecircumflex", 611, NULL }, + { "gbreve", 500, NULL }, { "trademark", 980, NULL }, { "daggerdbl", 500, NULL }, + { "nacute", 500, NULL }, { "macron", 333, NULL }, { "Otilde", 722, NULL }, + { "Emacron", 611, NULL }, { "ellipsis", 889, NULL }, { "scaron", 389, NULL }, { "AE", 889, NULL }, @@ -2757,9 +3534,11 @@ static BuiltinFontWidth timesItalicWidthsTab[] = { { "exclamdown", 389, NULL }, { "endash", 500, NULL }, { "oe", 667, NULL }, + { "Abreve", 611, NULL }, + { "Umacron", 722, NULL }, { "ecircumflex", 444, NULL }, - { "copyright", 760, NULL }, { "Adieresis", 611, NULL }, + { "copyright", 760, NULL }, { "Egrave", 611, NULL }, { "slash", 278, NULL }, { "Edieresis", 611, NULL }, @@ -2767,14 +3546,17 @@ static BuiltinFontWidth timesItalicWidthsTab[] = { { "Idieresis", 333, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, - { "ucircumflex", 500, NULL }, + { "emacron", 444, NULL }, { "Odieresis", 722, NULL }, + { "ucircumflex", 500, NULL }, { "bracketleft", 389, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 333, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 556, NULL }, + { "umacron", 500, NULL }, + { "abreve", 500, NULL }, { "Eacute", 611, NULL }, { "adieresis", 500, NULL }, { "egrave", 444, NULL }, @@ -2790,111 +3572,173 @@ static BuiltinFontWidth timesItalicWidthsTab[] = { { "five", 500, NULL }, { "udieresis", 500, NULL }, { "Zcaron", 556, NULL }, + { "Scommaaccent", 500, NULL }, { "threequarters", 750, NULL }, { "guillemotright", 500, NULL }, - { "ydieresis", 444, NULL }, { "Ccedilla", 667, NULL }, + { "ydieresis", 444, NULL }, { "tilde", 333, NULL }, { "at", 920, NULL }, { "eacute", 444, NULL }, { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, { "multiply", 675, NULL }, { "zero", 500, NULL }, { "eth", 500, NULL }, + { "Scedilla", 500, NULL }, { "Ograve", 722, NULL }, + { "Racute", 611, NULL }, + { "partialdiff", 476, NULL }, { "uacute", 500, NULL }, { "braceleft", 400, NULL }, { "Thorn", 611, NULL }, { "zcaron", 389, NULL }, + { "scommaaccent", 389, NULL }, { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, { "Ocircumflex", 722, NULL }, { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, { "ogonek", 333, NULL }, { "ograve", 500, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 556, NULL }, + { "Eogonek", 611, NULL }, { "thorn", 500, NULL }, { "degree", 400, NULL }, { "registered", 760, NULL }, + { "radical", 453, NULL }, { "Aring", 611, NULL }, { "percent", 833, NULL }, { "six", 500, NULL }, { "paragraph", 523, NULL }, + { "dcaron", 544, NULL }, + { "Uogonek", 722, NULL }, { "two", 500, NULL }, + { "summation", 600, NULL }, { "Igrave", 333, NULL }, + { "Lacute", 556, NULL }, { "ocircumflex", 500, NULL }, { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 300, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, { "asciicircum", 422, NULL }, { "aring", 500, NULL }, { "grave", 333, NULL }, + { "uogonek", 500, NULL }, { "bracketright", 389, NULL }, { "Iacute", 333, NULL }, { "ampersand", 778, NULL }, { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 667, NULL }, { "plus", 675, NULL }, + { "uring", 500, NULL }, { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, { "Yacute", 556, NULL }, + { "ohungarumlaut", 500, NULL }, { "threesuperior", 300, NULL }, { "acute", 333, NULL }, { "section", 500, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 556, NULL }, + { "ncaron", 500, NULL }, { "florin", 500, NULL }, { "yacute", 444, NULL }, + { "Rcommaaccent", 611, NULL }, { "fi", 500, NULL }, { "fl", 500, NULL }, { "Acircumflex", 611, NULL }, + { "Cacute", 667, NULL }, { "Icircumflex", 333, NULL }, { "guillemotleft", 500, NULL }, { "germandbls", 500, NULL }, + { "Amacron", 611, NULL }, { "seven", 500, NULL }, + { "Sacute", 500, NULL }, { "ordmasculine", 310, NULL }, { "dotlessi", 278, NULL }, { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 333, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 556, NULL }, { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 611, NULL }, { "icircumflex", 278, NULL }, { "braceright", 400, NULL }, { "quotedblright", 556, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, { "cent", 500, NULL }, { "currency", 500, NULL }, { "logicalnot", 675, NULL }, + { "zdotaccent", 389, NULL }, { "Atilde", 611, NULL }, { "breve", 333, NULL }, { "bar", 275, NULL }, { "fraction", 167, NULL }, { "less", 675, NULL }, + { "ecaron", 444, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 250, NULL }, + { "Rcaron", 611, NULL }, + { "Kcommaaccent", 667, NULL }, { "greater", 675, NULL }, { "atilde", 500, NULL }, { "brokenbar", 275, NULL }, { "quoteleft", 333, NULL }, + { "Edotaccent", 611, NULL }, { "onesuperior", 300, NULL } }; static BuiltinFontWidth timesRomanWidthsTab[] = { { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, { "comma", 250, NULL }, { "cedilla", 333, NULL }, { "plusminus", 564, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, { "asciitilde", 541, NULL }, { "colon", 278, NULL }, { "onehalf", 750, NULL }, { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, { "ntilde", 500, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 500, NULL }, { "minus", 564, NULL }, + { "Iogonek", 333, NULL }, + { "zacute", 444, NULL }, { "yen", 500, NULL }, { "space", 250, NULL }, + { "Omacron", 722, NULL }, { "questiondown", 444, NULL }, { "emdash", 1000, NULL }, { "Agrave", 722, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, + { "lcaron", 344, NULL }, { "A", 722, NULL }, { "B", 667, NULL }, { "C", 667, NULL }, + { "aogonek", 444, NULL }, { "D", 722, NULL }, { "E", 611, NULL }, { "onequarter", 750, NULL }, @@ -2904,14 +3748,18 @@ static BuiltinFontWidth timesRomanWidthsTab[] = { { "I", 333, NULL }, { "J", 389, NULL }, { "K", 722, NULL }, + { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 611, NULL }, { "periodcentered", 250, NULL }, { "M", 889, NULL }, { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 611, NULL }, { "O", 722, NULL }, { "P", 556, NULL }, { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, { "R", 667, NULL }, { "Aacute", 722, NULL }, { "caron", 333, NULL }, @@ -2928,6 +3776,7 @@ static BuiltinFontWidth timesRomanWidthsTab[] = { { "Z", 611, NULL }, { "four", 500, NULL }, { "a", 444, NULL }, + { "Gcommaaccent", 722, NULL }, { "b", 500, NULL }, { "c", 444, NULL }, { "d", 500, NULL }, @@ -2944,11 +3793,13 @@ static BuiltinFontWidth timesRomanWidthsTab[] = { { "l", 278, NULL }, { "m", 778, NULL }, { "n", 500, NULL }, + { "tcommaaccent", 278, NULL }, { "o", 500, NULL }, { "ordfeminine", 276, NULL }, { "ring", 333, NULL }, { "p", 500, NULL }, { "q", 500, NULL }, + { "uhungarumlaut", 500, NULL }, { "r", 333, NULL }, { "twosuperior", 300, NULL }, { "aacute", 444, NULL }, @@ -2957,24 +3808,37 @@ static BuiltinFontWidth timesRomanWidthsTab[] = { { "t", 278, NULL }, { "divide", 564, NULL }, { "u", 500, NULL }, + { "Ccaron", 667, NULL }, { "v", 500, NULL }, { "w", 722, NULL }, { "x", 500, NULL }, { "y", 500, NULL }, { "z", 444, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, + { "Idotaccent", 333, NULL }, + { "Nacute", 722, NULL }, { "quotedbl", 408, NULL }, + { "gcommaaccent", 500, NULL }, { "mu", 500, NULL }, + { "greaterequal", 549, NULL }, { "Scaron", 556, NULL }, { "Lslash", 611, NULL }, { "semicolon", 278, NULL }, { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, { "Ecircumflex", 611, NULL }, + { "gbreve", 500, NULL }, { "trademark", 980, NULL }, { "daggerdbl", 500, NULL }, + { "nacute", 500, NULL }, { "macron", 333, NULL }, { "Otilde", 722, NULL }, + { "Emacron", 611, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 389, NULL }, { "AE", 889, NULL }, @@ -2988,9 +3852,11 @@ static BuiltinFontWidth timesRomanWidthsTab[] = { { "exclamdown", 333, NULL }, { "endash", 500, NULL }, { "oe", 722, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, { "ecircumflex", 444, NULL }, - { "copyright", 760, NULL }, { "Adieresis", 722, NULL }, + { "copyright", 760, NULL }, { "Egrave", 611, NULL }, { "slash", 278, NULL }, { "Edieresis", 611, NULL }, @@ -2998,14 +3864,17 @@ static BuiltinFontWidth timesRomanWidthsTab[] = { { "Idieresis", 333, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, - { "ucircumflex", 500, NULL }, + { "emacron", 444, NULL }, { "Odieresis", 722, NULL }, + { "ucircumflex", 500, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 333, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 722, NULL }, + { "umacron", 500, NULL }, + { "abreve", 444, NULL }, { "Eacute", 611, NULL }, { "adieresis", 444, NULL }, { "egrave", 444, NULL }, @@ -3021,85 +3890,134 @@ static BuiltinFontWidth timesRomanWidthsTab[] = { { "five", 500, NULL }, { "udieresis", 500, NULL }, { "Zcaron", 611, NULL }, + { "Scommaaccent", 556, NULL }, { "threequarters", 750, NULL }, { "guillemotright", 500, NULL }, - { "ydieresis", 500, NULL }, { "Ccedilla", 667, NULL }, + { "ydieresis", 500, NULL }, { "tilde", 333, NULL }, { "at", 921, NULL }, { "eacute", 444, NULL }, { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, { "multiply", 564, NULL }, { "zero", 500, NULL }, { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, { "Ograve", 722, NULL }, + { "Racute", 667, NULL }, + { "partialdiff", 476, NULL }, { "uacute", 500, NULL }, { "braceleft", 480, NULL }, { "Thorn", 556, NULL }, { "zcaron", 444, NULL }, + { "scommaaccent", 389, NULL }, { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, { "Ocircumflex", 722, NULL }, { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, { "ogonek", 333, NULL }, { "ograve", 500, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 611, NULL }, { "thorn", 500, NULL }, { "degree", 400, NULL }, { "registered", 760, NULL }, + { "radical", 453, NULL }, { "Aring", 722, NULL }, { "percent", 833, NULL }, { "six", 500, NULL }, { "paragraph", 453, NULL }, + { "dcaron", 588, NULL }, + { "Uogonek", 722, NULL }, { "two", 500, NULL }, + { "summation", 600, NULL }, { "Igrave", 333, NULL }, + { "Lacute", 611, NULL }, { "ocircumflex", 500, NULL }, { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 326, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, { "asciicircum", 469, NULL }, { "aring", 444, NULL }, { "grave", 333, NULL }, + { "uogonek", 500, NULL }, { "bracketright", 333, NULL }, { "Iacute", 333, NULL }, { "ampersand", 778, NULL }, { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, { "plus", 564, NULL }, + { "uring", 500, NULL }, { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, { "Yacute", 722, NULL }, + { "ohungarumlaut", 500, NULL }, { "threesuperior", 300, NULL }, { "acute", 333, NULL }, { "section", 500, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 444, NULL }, + { "ncaron", 500, NULL }, { "florin", 500, NULL }, { "yacute", 500, NULL }, + { "Rcommaaccent", 667, NULL }, { "fi", 556, NULL }, { "fl", 556, NULL }, { "Acircumflex", 722, NULL }, + { "Cacute", 667, NULL }, { "Icircumflex", 333, NULL }, { "guillemotleft", 500, NULL }, { "germandbls", 500, NULL }, + { "Amacron", 722, NULL }, { "seven", 500, NULL }, + { "Sacute", 556, NULL }, { "ordmasculine", 310, NULL }, { "dotlessi", 278, NULL }, { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 333, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, { "acircumflex", 444, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 611, NULL }, { "icircumflex", 278, NULL }, { "braceright", 480, NULL }, { "quotedblright", 444, NULL }, + { "amacron", 444, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, { "cent", 500, NULL }, { "currency", 500, NULL }, { "logicalnot", 564, NULL }, + { "zdotaccent", 444, NULL }, { "Atilde", 722, NULL }, { "breve", 333, NULL }, { "bar", 200, NULL }, { "fraction", 167, NULL }, { "less", 564, NULL }, + { "ecaron", 444, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 250, NULL }, + { "Rcaron", 667, NULL }, + { "Kcommaaccent", 722, NULL }, { "greater", 564, NULL }, { "atilde", 444, NULL }, { "brokenbar", 200, NULL }, { "quoteleft", 333, NULL }, + { "Edotaccent", 611, NULL }, { "onesuperior", 300, NULL } }; @@ -3278,10 +4196,10 @@ static BuiltinFontWidth zapfDingbatsWidthsTab[] = { { "a203", 762, NULL }, { "a123", 788, NULL }, { "a204", 759, NULL }, - { "a205", 509, NULL }, { "a124", 788, NULL }, - { "a206", 410, NULL }, + { "a205", 509, NULL }, { "a125", 788, NULL }, + { "a206", 410, NULL }, { "a126", 788, NULL }, { "a127", 788, NULL }, { "a128", 788, NULL }, @@ -3309,19 +4227,19 @@ static BuiltinFontWidth zapfDingbatsWidthsTab[] = { }; BuiltinFont builtinFonts[] = { - { "Courier", standardEncoding, 624, -207, { -40, -290, 640, 795}, NULL }, - { "Courier-Bold", standardEncoding, 674, -257, {-100, -350, 700, 855}, NULL }, - { "Courier-BoldOblique", standardEncoding, 674, -257, {-145, -350, 817, 855}, NULL }, - { "Courier-Oblique", standardEncoding, 624, -207, { -85, -290, 759, 795}, NULL }, - { "Helvetica", standardEncoding, 729, -219, {-174, -220, 1001, 944}, NULL }, - { "Helvetica-Bold", standardEncoding, 729, -219, {-173, -221, 1003, 936}, NULL }, - { "Helvetica-BoldOblique", standardEncoding, 729, -219, {-177, -221, 1107, 936}, NULL }, - { "Helvetica-Oblique", standardEncoding, 729, -219, {-178, -220, 1108, 944}, NULL }, + { "Courier", standardEncoding, 629, -157, { -23, -250, 715, 805}, NULL }, + { "Courier-Bold", standardEncoding, 629, -157, {-113, -250, 749, 801}, NULL }, + { "Courier-BoldOblique", standardEncoding, 629, -157, { -57, -250, 869, 801}, NULL }, + { "Courier-Oblique", standardEncoding, 629, -157, { -27, -250, 849, 805}, NULL }, + { "Helvetica", standardEncoding, 718, -207, {-166, -225, 1000, 931}, NULL }, + { "Helvetica-Bold", standardEncoding, 718, -207, {-170, -228, 1003, 962}, NULL }, + { "Helvetica-BoldOblique", standardEncoding, 718, -207, {-174, -228, 1114, 962}, NULL }, + { "Helvetica-Oblique", standardEncoding, 718, -207, {-170, -225, 1116, 931}, NULL }, { "Symbol", symbolEncoding, 1010, -293, {-180, -293, 1090, 1010}, NULL }, - { "Times-Bold", standardEncoding, 670, -210, {-172, -256, 1008, 965}, NULL }, - { "Times-BoldItalic", standardEncoding, 682, -203, {-168, -232, 1014, 894}, NULL }, - { "Times-Italic", standardEncoding, 684, -206, {-176, -252, 990, 930}, NULL }, - { "Times-Roman", standardEncoding, 682, -217, {-170, -223, 1024, 896}, NULL }, + { "Times-Bold", standardEncoding, 683, -217, {-168, -218, 1000, 935}, NULL }, + { "Times-BoldItalic", standardEncoding, 683, -217, {-200, -218, 996, 921}, NULL }, + { "Times-Italic", standardEncoding, 683, -217, {-169, -217, 1010, 883}, NULL }, + { "Times-Roman", standardEncoding, 683, -217, {-168, -218, 1000, 898}, NULL }, { "ZapfDingbats", zapfDingbatsEncoding, 820, -143, { -1, -143, 981, 820}, NULL } }; @@ -3341,19 +4259,19 @@ BuiltinFont *builtinFontSubst[] = { }; void initBuiltinFontTables() { - builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 260); - builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 260); - builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 260); - builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 260); - builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 228); - builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 228); - builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 228); - builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 228); - builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 189); - builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 228); - builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 228); - builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 228); - builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 228); + builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 315); + builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 315); + builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 315); + builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 315); + builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 315); + builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 316); + builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 315); + builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 315); + builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 190); + builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 315); + builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 315); + builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 315); + builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 315); builtinFonts[13].widths = new BuiltinFontWidths(zapfDingbatsWidthsTab, 202); } diff --git a/pdf2swf/xpdf/BuiltinFontTables.h b/pdf2swf/xpdf/BuiltinFontTables.h index 3a8892e..eb45549 100644 --- a/pdf2swf/xpdf/BuiltinFontTables.h +++ b/pdf2swf/xpdf/BuiltinFontTables.h @@ -2,7 +2,7 @@ // // BuiltinFontTables.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf2swf/xpdf/CMap.cc b/pdf2swf/xpdf/CMap.cc index b49cffd..25f3af7 100644 --- a/pdf2swf/xpdf/CMap.cc +++ b/pdf2swf/xpdf/CMap.cc @@ -2,15 +2,16 @@ // // CMap.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -143,6 +144,9 @@ CMap::CMap(GString *collectionA, GString *cMapNameA) { vector[i].cid = 0; } refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif } CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) { @@ -151,6 +155,9 @@ CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) { wMode = wModeA; vector = NULL; refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif } void CMap::useCMap(CMapCache *cache, char *useName) { @@ -251,6 +258,9 @@ CMap::~CMap() { if (vector) { freeCMapVector(vector); } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif } void CMap::freeCMapVector(CMapVectorEntry *vec) { @@ -265,11 +275,26 @@ void CMap::freeCMapVector(CMapVectorEntry *vec) { } void CMap::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif } void CMap::decRefCnt() { - if (--refCnt == 0) { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { delete this; } } diff --git a/pdf2swf/xpdf/CMap.h b/pdf2swf/xpdf/CMap.h index fe49acf..eff2a81 100644 --- a/pdf2swf/xpdf/CMap.h +++ b/pdf2swf/xpdf/CMap.h @@ -2,20 +2,26 @@ // // CMap.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef CMAP_H #define CMAP_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "CharTypes.h" +#if MULTITHREADED +#include "GMutex.h" +#endif + class GString; struct CMapVectorEntry; class CMapCache; @@ -67,6 +73,9 @@ private: CMapVectorEntry *vector; // vector for first byte (NULL for // identity CMap) int refCnt; +#ifdef MULTITHREADED + GMutex mutex; +#endif }; //------------------------------------------------------------------------ diff --git a/pdf2swf/xpdf/Catalog.cc b/pdf2swf/xpdf/Catalog.cc index 1212e2e..c645fd0 100644 --- a/pdf2swf/xpdf/Catalog.cc +++ b/pdf2swf/xpdf/Catalog.cc @@ -2,15 +2,16 @@ // // Catalog.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "gmem.h" #include "Object.h" @@ -26,7 +27,7 @@ // Catalog //------------------------------------------------------------------------ -Catalog::Catalog(XRef *xrefA, GBool printCommands) { +Catalog::Catalog(XRef *xrefA) { Object catDict, pagesDict; Object obj, obj2; int numPages0; @@ -55,12 +56,13 @@ Catalog::Catalog(XRef *xrefA, GBool printCommands) { goto err2; } pagesDict.dictLookup("Count", &obj); - if (!obj.isInt()) { + // some PDF files actually use real numbers here ("/Count 9.0") + if (!obj.isNum()) { error(-1, "Page count in top-level pages object is wrong type (%s)", obj.getTypeName()); goto err3; } - pagesSize = numPages0 = obj.getInt(); + pagesSize = numPages0 = (int)obj.getNum(); obj.free(); pages = (Page **)gmalloc(pagesSize * sizeof(Page *)); pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref)); @@ -69,7 +71,7 @@ Catalog::Catalog(XRef *xrefA, GBool printCommands) { pageRefs[i].num = -1; pageRefs[i].gen = -1; } - numPages = readPageTree(pagesDict.getDict(), NULL, 0, printCommands); + numPages = readPageTree(pagesDict.getDict(), NULL, 0); if (numPages != numPages0) { error(-1, "Page count in top-level pages object is incorrect"); } @@ -100,6 +102,9 @@ Catalog::Catalog(XRef *xrefA, GBool printCommands) { // get the structure tree root catDict.dictLookup("StructTreeRoot", &structTreeRoot); + // get the outline dictionary + catDict.dictLookup("Outlines", &outline); + catDict.free(); return; @@ -133,6 +138,7 @@ Catalog::~Catalog() { } metadata.free(); structTreeRoot.free(); + outline.free(); } GString *Catalog::readMetadata() { @@ -159,8 +165,7 @@ GString *Catalog::readMetadata() { return s; } -int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, - GBool printCommands) { +int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { Object kids; Object kid; Object kidRef; @@ -179,7 +184,7 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, kids.arrayGet(i, &kid); if (kid.isDict("Page")) { attrs2 = new PageAttrs(attrs1, kid.getDict()); - page = new Page(xref, start+1, kid.getDict(), attrs2, printCommands); + page = new Page(xref, start+1, kid.getDict(), attrs2); if (!page->isOk()) { ++start; goto err3; @@ -205,7 +210,7 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, // This should really be isDict("Pages"), but I've seen at least one // PDF file where the /Type entry is missing. } else if (kid.isDict()) { - if ((start = readPageTree(kid.getDict(), attrs1, start, printCommands)) + if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0) goto err2; } else { @@ -276,6 +281,10 @@ LinkDest *Catalog::findDest(GString *name) { error(-1, "Bad named destination value"); } obj1.free(); + if (dest && !dest->isOk()) { + delete dest; + dest = NULL; + } return dest; } @@ -299,8 +308,8 @@ Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) { } else if (cmp < 0) { done = gTrue; } - name1.free(); } + name1.free(); } names.free(); if (!found) diff --git a/pdf2swf/xpdf/Catalog.h b/pdf2swf/xpdf/Catalog.h index afad803..8ab7c61 100644 --- a/pdf2swf/xpdf/Catalog.h +++ b/pdf2swf/xpdf/Catalog.h @@ -2,14 +2,16 @@ // // Catalog.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef CATALOG_H #define CATALOG_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -28,7 +30,7 @@ class Catalog { public: // Constructor. - Catalog(XRef *xrefA, GBool printCommands = gFalse); + Catalog(XRef *xrefA); // Destructor. ~Catalog(); @@ -63,6 +65,8 @@ public: // NULL if is not a destination. LinkDest *findDest(GString *name); + Object *getOutline() { return &outline; } + private: XRef *xref; // the xref table for this PDF file @@ -75,10 +79,10 @@ private: GString *baseURI; // base URI for URI-type links Object metadata; // metadata stream Object structTreeRoot; // structure tree root dictionary + Object outline; // outline dictionary GBool ok; // true if catalog is valid - int readPageTree(Dict *pages, PageAttrs *attrs, int start, - GBool printCommands); + int readPageTree(Dict *pages, PageAttrs *attrs, int start); Object *findDestInTree(Object *tree, GString *name, Object *obj); }; diff --git a/pdf2swf/xpdf/CharCodeToUnicode.cc b/pdf2swf/xpdf/CharCodeToUnicode.cc index 912981e..2e2ad47 100644 --- a/pdf2swf/xpdf/CharCodeToUnicode.cc +++ b/pdf2swf/xpdf/CharCodeToUnicode.cc @@ -2,15 +2,16 @@ // // CharCodeToUnicode.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include "gmem.h" @@ -53,7 +54,8 @@ static int getCharFromFile(void *data) { //------------------------------------------------------------------------ -CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) { +CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName, + GString *collection) { FILE *f; Unicode *mapA; CharCode size, mapLenA; @@ -61,9 +63,9 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) { Unicode u; CharCodeToUnicode *ctu; - if (!(f = globalParams->getCIDToUnicodeFile(collectionA))) { - error(-1, "Couldn't find cidToUnicode file for the '%s' collection", - collectionA->getCString()); + if (!(f = fopen(fileName->getCString(), "r"))) { + error(-1, "Couldn't open cidToUnicode file '%s'", + fileName->getCString()); return NULL; } @@ -79,21 +81,110 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) { if (sscanf(buf, "%x", &u) == 1) { mapA[mapLenA] = u; } else { - error(-1, "Bad line (%d) in cidToUnicode file for the '%s' collection", - (int)(mapLenA + 1), collectionA->getCString()); + error(-1, "Bad line (%d) in cidToUnicode file '%s'", + (int)(mapLenA + 1), fileName->getCString()); mapA[mapLenA] = 0; } ++mapLenA; } + fclose(f); - ctu = new CharCodeToUnicode(collectionA->copy(), mapA, mapLenA, gTrue, - NULL, 0); + ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue, + NULL, 0, 0); + gfree(mapA); + return ctu; +} + +CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( + GString *fileName) { + FILE *f; + Unicode *mapA; + CharCodeToUnicodeString *sMapA; + CharCode size, oldSize, len, sMapSizeA, sMapLenA; + char buf[256]; + char *tok; + Unicode u0; + Unicode uBuf[maxUnicodeString]; + CharCodeToUnicode *ctu; + int line, n, i; + + if (!(f = fopen(fileName->getCString(), "r"))) { + error(-1, "Couldn't open unicodeToUnicode file '%s'", + fileName->getCString()); + return NULL; + } + + size = 4096; + mapA = (Unicode *)gmalloc(size * sizeof(Unicode)); + memset(mapA, 0, size * sizeof(Unicode)); + len = 0; + sMapA = NULL; + sMapSizeA = sMapLenA = 0; + + line = 0; + while (getLine(buf, sizeof(buf), f)) { + ++line; + if (!(tok = strtok(buf, " \t\r\n")) || + sscanf(tok, "%x", &u0) != 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + continue; + } + n = 0; + while (n < maxUnicodeString) { + if (!(tok = strtok(NULL, " \t\r\n"))) { + break; + } + if (sscanf(tok, "%x", &uBuf[n]) != 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + break; + } + ++n; + } + if (n < 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + continue; + } + if (u0 >= size) { + oldSize = size; + while (u0 >= size) { + size *= 2; + } + mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode)); + memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode)); + } + if (n == 1) { + mapA[u0] = uBuf[0]; + } else { + mapA[u0] = 0; + if (sMapLenA == sMapSizeA) { + sMapSizeA += 16; + sMapA = (CharCodeToUnicodeString *) + grealloc(sMapA, sMapSizeA * sizeof(CharCodeToUnicodeString)); + } + sMapA[sMapLenA].c = u0; + for (i = 0; i < n; ++i) { + sMapA[sMapLenA].u[i] = uBuf[i]; + } + sMapA[sMapLenA].len = n; + ++sMapLenA; + } + if (u0 >= len) { + len = u0 + 1; + } + } + fclose(f); + + ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue, + sMapA, sMapLenA, sMapSizeA); gfree(mapA); return ctu; } CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) { - return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0); + return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0); } CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) { @@ -106,16 +197,20 @@ CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) { return ctu; } +void CharCodeToUnicode::mergeCMap(GString *buf, int nBits) { + char *p; + + p = buf->getCString(); + parseCMap1(&getCharFromString, &p, nBits); +} + void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, int nBits) { PSTokenizer *pst; char tok1[256], tok2[256], tok3[256]; int nDigits, n1, n2, n3; - CharCode oldLen, i; + CharCode i; CharCode code1, code2; - Unicode u; - char uHex[5]; - int j; GString *name; FILE *f; @@ -156,38 +251,7 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); continue; } - if (code1 >= mapLen) { - oldLen = mapLen; - mapLen = (code1 + 256) & ~255; - map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode)); - for (i = oldLen; i < mapLen; ++i) { - map[i] = 0; - } - } - if (n2 == 6) { - if (sscanf(tok2 + 1, "%x", &u) != 1) { - error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); - continue; - } - map[code1] = u; - } else { - map[code1] = 0; - if (sMapLen == sMapSize) { - sMapSize += 8; - sMap = (CharCodeToUnicodeString *) - grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); - } - sMap[sMapLen].c = code1; - sMap[sMapLen].len = (n2 - 2) / 4; - for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) { - strncpy(uHex, tok2 + 1 + j*4, 4); - uHex[4] = '\0'; - if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) { - error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); - } - } - ++sMapLen; - } + addMapping(code1, tok2 + 1, n2 - 1, 0); } pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "beginbfrange")) { @@ -203,53 +267,39 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, break; } if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && - n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>' && - tok3[0] == '<' && tok3[n3 - 1] == '>')) { + n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) { error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); continue; } - tok1[n1 - 1] = tok2[n2 - 1] = tok3[n3 - 1] = '\0'; + tok1[n1 - 1] = tok2[n2 - 1] = '\0'; if (sscanf(tok1 + 1, "%x", &code1) != 1 || sscanf(tok2 + 1, "%x", &code2) != 1) { error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); continue; } - if (code2 >= mapLen) { - oldLen = mapLen; - mapLen = (code2 + 256) & ~255; - map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode)); - for (i = oldLen; i < mapLen; ++i) { - map[i] = 0; - } - } - if (n3 == 6) { - if (sscanf(tok3 + 1, "%x", &u) != 1) { - error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); - continue; - } - for (; code1 <= code2; ++code1) { - map[code1] = u++; - } - } else { - if (sMapLen + (int)(code2 - code1 + 1) > sMapSize) { - sMapSize = (sMapSize + (code2 - code1 + 1) + 7) & ~7; - sMap = (CharCodeToUnicodeString *) - grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); + if (!strcmp(tok3, "[")) { + i = 0; + while (pst->getToken(tok1, sizeof(tok1), &n1) && + code1 + i <= code2) { + if (!strcmp(tok1, "]")) { + break; + } + if (tok1[0] == '<' && tok1[n1 - 1] == '>') { + tok1[n1 - 1] = '\0'; + addMapping(code1 + i, tok1 + 1, n1 - 2, 0); + } else { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + } + ++i; } + } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') { + tok3[n3 - 1] = '\0'; for (i = 0; code1 <= code2; ++code1, ++i) { - map[code1] = 0; - sMap[sMapLen].c = code1; - sMap[sMapLen].len = (n3 - 2) / 4; - for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) { - strncpy(uHex, tok3 + 1 + j*4, 4); - uHex[4] = '\0'; - if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) { - error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); - } - } - sMap[sMapLen].u[sMap[sMapLen].len - 1] += i; - ++sMapLen; + addMapping(code1, tok3 + 1, n3 - 2, i); } + + } else { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); } } pst->getToken(tok1, sizeof(tok1), &n1); @@ -260,10 +310,52 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, delete pst; } -CharCodeToUnicode::CharCodeToUnicode(GString *collectionA) { +void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, + int offset) { + CharCode oldLen, i; + Unicode u; + char uHex[5]; + int j; + + if (code >= mapLen) { + oldLen = mapLen; + mapLen = (code + 256) & ~255; + map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode)); + for (i = oldLen; i < mapLen; ++i) { + map[i] = 0; + } + } + if (n <= 4) { + if (sscanf(uStr, "%x", &u) != 1) { + error(-1, "Illegal entry in ToUnicode CMap"); + return; + } + map[code] = u + offset; + } else { + if (sMapLen >= sMapSize) { + sMapSize = sMapSize + 16; + sMap = (CharCodeToUnicodeString *) + grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); + } + map[code] = 0; + sMap[sMapLen].c = code; + sMap[sMapLen].len = n / 4; + for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) { + strncpy(uHex, uStr + j*4, 4); + uHex[4] = '\0'; + if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) { + error(-1, "Illegal entry in ToUnicode CMap"); + } + } + sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset; + ++sMapLen; + } +} + +CharCodeToUnicode::CharCodeToUnicode(GString *tagA) { CharCode i; - collection = collectionA; + tag = tagA; mapLen = 256; map = (Unicode *)gmalloc(mapLen * sizeof(Unicode)); for (i = 0; i < mapLen; ++i) { @@ -272,13 +364,16 @@ CharCodeToUnicode::CharCodeToUnicode(GString *collectionA) { sMap = NULL; sMapLen = sMapSize = 0; refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif } -CharCodeToUnicode::CharCodeToUnicode(GString *collectionA, Unicode *mapA, +CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA, CharCode mapLenA, GBool copyMap, CharCodeToUnicodeString *sMapA, - int sMapLenA) { - collection = collectionA; + int sMapLenA, int sMapSizeA) { + tag = tagA; mapLen = mapLenA; if (copyMap) { map = (Unicode *)gmalloc(mapLen * sizeof(Unicode)); @@ -287,32 +382,75 @@ CharCodeToUnicode::CharCodeToUnicode(GString *collectionA, Unicode *mapA, map = mapA; } sMap = sMapA; - sMapLen = sMapSize = sMapLenA; + sMapLen = sMapLenA; + sMapSize = sMapSizeA; refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif } CharCodeToUnicode::~CharCodeToUnicode() { - if (collection) { - delete collection; + if (tag) { + delete tag; } gfree(map); if (sMap) { gfree(sMap); } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif } void CharCodeToUnicode::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif } void CharCodeToUnicode::decRefCnt() { - if (--refCnt == 0) { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { delete this; } } -GBool CharCodeToUnicode::match(GString *collectionA) { - return collection && !collection->cmp(collectionA); +GBool CharCodeToUnicode::match(GString *tagA) { + return tag && !tag->cmp(tagA); +} + +void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) { + int i; + + if (len == 1) { + map[c] = u[0]; + } else { + map[c] = 0; + if (sMapLen == sMapSize) { + sMapSize += 8; + sMap = (CharCodeToUnicodeString *) + grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); + } + sMap[sMapLen].c = c; + sMap[sMapLen].len = len; + for (i = 0; i < len && i < maxUnicodeString; ++i) { + sMap[sMapLen].u[i] = u[i]; + } + ++sMapLen; + } } int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) { @@ -338,34 +476,37 @@ int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) { //------------------------------------------------------------------------ -CIDToUnicodeCache::CIDToUnicodeCache() { +CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) { int i; - for (i = 0; i < cidToUnicodeCacheSize; ++i) { + size = sizeA; + cache = (CharCodeToUnicode **)gmalloc(size * sizeof(CharCodeToUnicode *)); + for (i = 0; i < size; ++i) { cache[i] = NULL; } } -CIDToUnicodeCache::~CIDToUnicodeCache() { +CharCodeToUnicodeCache::~CharCodeToUnicodeCache() { int i; - for (i = 0; i < cidToUnicodeCacheSize; ++i) { + for (i = 0; i < size; ++i) { if (cache[i]) { cache[i]->decRefCnt(); } } + gfree(cache); } -CharCodeToUnicode *CIDToUnicodeCache::getCIDToUnicode(GString *collection) { +CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GString *tag) { CharCodeToUnicode *ctu; int i, j; - if (cache[0] && cache[0]->match(collection)) { + if (cache[0] && cache[0]->match(tag)) { cache[0]->incRefCnt(); return cache[0]; } - for (i = 1; i < cidToUnicodeCacheSize; ++i) { - if (cache[i] && cache[i]->match(collection)) { + for (i = 1; i < size; ++i) { + if (cache[i] && cache[i]->match(tag)) { ctu = cache[i]; for (j = i; j >= 1; --j) { cache[j] = cache[j - 1]; @@ -375,16 +516,18 @@ CharCodeToUnicode *CIDToUnicodeCache::getCIDToUnicode(GString *collection) { return ctu; } } - if ((ctu = CharCodeToUnicode::parseCIDToUnicode(collection))) { - if (cache[cidToUnicodeCacheSize - 1]) { - cache[cidToUnicodeCacheSize - 1]->decRefCnt(); - } - for (j = cidToUnicodeCacheSize - 1; j >= 1; --j) { - cache[j] = cache[j - 1]; - } - cache[0] = ctu; - ctu->incRefCnt(); - return ctu; - } return NULL; } + +void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) { + int i; + + if (cache[size - 1]) { + cache[size - 1]->decRefCnt(); + } + for (i = size - 1; i >= 1; --i) { + cache[i] = cache[i - 1]; + } + cache[0] = ctu; + ctu->incRefCnt(); +} diff --git a/pdf2swf/xpdf/CharCodeToUnicode.h b/pdf2swf/xpdf/CharCodeToUnicode.h index 06916c8..605e2bd 100644 --- a/pdf2swf/xpdf/CharCodeToUnicode.h +++ b/pdf2swf/xpdf/CharCodeToUnicode.h @@ -4,19 +4,25 @@ // // Mapping from character codes to Unicode. // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef CHARCODETOUNICODE_H #define CHARCODETOUNICODE_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "CharTypes.h" +#if MULTITHREADED +#include "GMutex.h" +#endif + struct CharCodeToUnicodeString; //------------------------------------------------------------------------ @@ -24,10 +30,16 @@ struct CharCodeToUnicodeString; class CharCodeToUnicode { public: - // Create the CID-to-Unicode mapping specified by . - // This reads a .cidToUnicode file from disk. Sets the initial - // reference count to 1. Returns NULL on failure. - static CharCodeToUnicode *parseCIDToUnicode(GString *collectionA); + // Read the CID-to-Unicode mapping for from the file + // specified by . Sets the initial reference count to 1. + // Returns NULL on failure. + static CharCodeToUnicode *parseCIDToUnicode(GString *fileName, + GString *collection); + + // Create a Unicode-to-Unicode mapping from the file specified by + // . Sets the initial reference count to 1. Returns NULL + // on failure. + static CharCodeToUnicode *parseUnicodeToUnicode(GString *fileName); // Create the CharCode-to-Unicode mapping for an 8-bit font. // is an array of 256 Unicode indexes. Sets the initial @@ -37,13 +49,20 @@ public: // Parse a ToUnicode CMap for an 8- or 16-bit font. static CharCodeToUnicode *parseCMap(GString *buf, int nBits); + // Parse a ToUnicode CMap for an 8- or 16-bit font, merging it into + // . + void mergeCMap(GString *buf, int nBits); + ~CharCodeToUnicode(); void incRefCnt(); void decRefCnt(); - // Return true if this mapping matches the specified . - GBool match(GString *collectionA); + // Return true if this mapping matches the specified . + GBool match(GString *tagA); + + // Set the mapping for . + void setMapping(CharCode c, Unicode *u, int len); // Map a CharCode to Unicode. int mapToUnicode(CharCode c, Unicode *u, int size); @@ -51,38 +70,44 @@ public: private: void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); - CharCodeToUnicode(GString *collectionA); - CharCodeToUnicode(GString *collectionA, Unicode *mapA, + void addMapping(CharCode code, char *uStr, int n, int offset); + CharCodeToUnicode(GString *tagA); + CharCodeToUnicode(GString *tagA, Unicode *mapA, CharCode mapLenA, GBool copyMap, - CharCodeToUnicodeString *sMapA, int sMapLenA); + CharCodeToUnicodeString *sMapA, + int sMapLenA, int sMapSizeA); - GString *collection; + GString *tag; Unicode *map; CharCode mapLen; CharCodeToUnicodeString *sMap; int sMapLen, sMapSize; int refCnt; +#ifdef MULTITHREADED + GMutex mutex; +#endif }; //------------------------------------------------------------------------ -#define cidToUnicodeCacheSize 4 - -class CIDToUnicodeCache { +class CharCodeToUnicodeCache { public: - CIDToUnicodeCache(); - ~CIDToUnicodeCache(); + CharCodeToUnicodeCache(int sizeA); + ~CharCodeToUnicodeCache(); + + // Get the CharCodeToUnicode object for . Increments its + // reference count; there will be one reference for the cache plus + // one for the caller of this function. Returns NULL on failure. + CharCodeToUnicode *getCharCodeToUnicode(GString *tag); - // Get the CharCodeToUnicode object for . Increments - // its reference count; there will be one reference for the cache - // plus one for the caller of this function. Returns NULL on - // failure. - CharCodeToUnicode *getCIDToUnicode(GString *collection); + // Insert into the cache, in the most-recently-used position. + void add(CharCodeToUnicode *ctu); private: - CharCodeToUnicode *cache[cidToUnicodeCacheSize]; + CharCodeToUnicode **cache; + int size; }; #endif diff --git a/pdf2swf/xpdf/CharTypes.h b/pdf2swf/xpdf/CharTypes.h index bae2f26..d0df630 100644 --- a/pdf2swf/xpdf/CharTypes.h +++ b/pdf2swf/xpdf/CharTypes.h @@ -2,7 +2,7 @@ // // CharTypes.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf2swf/xpdf/Decrypt.cc b/pdf2swf/xpdf/Decrypt.cc index 8de4091..dab0750 100644 --- a/pdf2swf/xpdf/Decrypt.cc +++ b/pdf2swf/xpdf/Decrypt.cc @@ -2,15 +2,16 @@ // // Decrypt.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include "gmem.h" #include "Decrypt.h" @@ -65,13 +66,15 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, Guchar *fileKey, GBool *ownerPasswordOk) { - Guchar test[32]; + Guchar test[32], test2[32]; GString *userPassword2; Guchar fState[256]; + Guchar tmpKey[16]; Guchar fx, fy; - int len, i; + int len, i, j; // try using the supplied owner password to generate the user password + *ownerPasswordOk = gFalse; if (ownerPassword) { len = ownerPassword->getLength(); if (len < 32) { @@ -80,29 +83,40 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, } else { memcpy(test, ownerPassword->getCString(), 32); } - } else { - memcpy(test, passwordPad, 32); - } - md5(test, 32, test); - if (encRevision == 3) { - for (i = 0; i < 50; ++i) { - md5(test, 16, test); + md5(test, 32, test); + if (encRevision == 3) { + for (i = 0; i < 50; ++i) { + md5(test, 16, test); + } + } + if (encRevision == 2) { + rc4InitKey(test, keyLength, fState); + fx = fy = 0; + for (i = 0; i < 32; ++i) { + test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); + } + } else { + memcpy(test2, ownerKey->getCString(), 32); + for (i = 19; i >= 0; --i) { + for (j = 0; j < keyLength; ++j) { + tmpKey[j] = test[j] ^ i; + } + rc4InitKey(tmpKey, keyLength, fState); + fx = fy = 0; + for (j = 0; j < 32; ++j) { + test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]); + } + } + } + userPassword2 = new GString((char *)test2, 32); + if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, + permissions, fileID, userPassword2, fileKey)) { + *ownerPasswordOk = gTrue; + delete userPassword2; + return gTrue; } - } - rc4InitKey(test, keyLength, fState); - fx = fy = 0; - for (i = 0; i < 32; ++i) { - test[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); - } - userPassword2 = new GString((char *)test, 32); - if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword2, fileKey)) { - *ownerPasswordOk = gTrue; delete userPassword2; - return gTrue; } - *ownerPasswordOk = gFalse; - delete userPassword2; // try using the supplied user password return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, @@ -143,7 +157,7 @@ GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, md5(buf, 68 + fileID->getLength(), fileKey); if (encRevision == 3) { for (i = 0; i < 50; ++i) { - md5(fileKey, 16, fileKey); + md5(fileKey, keyLength, fileKey); } } @@ -366,20 +380,20 @@ static void md5(Guchar *msg, int msgLen, Guchar *digest) { } // break digest into bytes - digest[0] = a & 0xff; - digest[1] = (a >>= 8) & 0xff; - digest[2] = (a >>= 8) & 0xff; - digest[3] = (a >>= 8) & 0xff; - digest[4] = b & 0xff; - digest[5] = (b >>= 8) & 0xff; - digest[6] = (b >>= 8) & 0xff; - digest[7] = (b >>= 8) & 0xff; - digest[8] = c & 0xff; - digest[9] = (c >>= 8) & 0xff; - digest[10] = (c >>= 8) & 0xff; - digest[11] = (c >>= 8) & 0xff; - digest[12] = d & 0xff; - digest[13] = (d >>= 8) & 0xff; - digest[14] = (d >>= 8) & 0xff; - digest[15] = (d >>= 8) & 0xff; + digest[0] = (Guchar)(a & 0xff); + digest[1] = (Guchar)((a >>= 8) & 0xff); + digest[2] = (Guchar)((a >>= 8) & 0xff); + digest[3] = (Guchar)((a >>= 8) & 0xff); + digest[4] = (Guchar)(b & 0xff); + digest[5] = (Guchar)((b >>= 8) & 0xff); + digest[6] = (Guchar)((b >>= 8) & 0xff); + digest[7] = (Guchar)((b >>= 8) & 0xff); + digest[8] = (Guchar)(c & 0xff); + digest[9] = (Guchar)((c >>= 8) & 0xff); + digest[10] = (Guchar)((c >>= 8) & 0xff); + digest[11] = (Guchar)((c >>= 8) & 0xff); + digest[12] = (Guchar)(d & 0xff); + digest[13] = (Guchar)((d >>= 8) & 0xff); + digest[14] = (Guchar)((d >>= 8) & 0xff); + digest[15] = (Guchar)((d >>= 8) & 0xff); } diff --git a/pdf2swf/xpdf/Decrypt.h b/pdf2swf/xpdf/Decrypt.h index 52afb2f..71f9457 100644 --- a/pdf2swf/xpdf/Decrypt.h +++ b/pdf2swf/xpdf/Decrypt.h @@ -2,14 +2,16 @@ // // Decrypt.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef DECRYPT_H #define DECRYPT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/Dict.cc b/pdf2swf/xpdf/Dict.cc index 5eb077e..6274590 100644 --- a/pdf2swf/xpdf/Dict.cc +++ b/pdf2swf/xpdf/Dict.cc @@ -2,15 +2,16 @@ // // Dict.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include "gmem.h" @@ -40,8 +41,12 @@ Dict::~Dict() { } void Dict::add(char *key, Object *val) { - if (length + 1 > size) { - size += 8; + if (length == size) { + if (length == 0) { + size = 8; + } else { + size *= 2; + } entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry)); } entries[length].key = key; diff --git a/pdf2swf/xpdf/Dict.h b/pdf2swf/xpdf/Dict.h index b994514..08f55ec 100644 --- a/pdf2swf/xpdf/Dict.h +++ b/pdf2swf/xpdf/Dict.h @@ -2,14 +2,16 @@ // // Dict.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef DICT_H #define DICT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/Error.cc b/pdf2swf/xpdf/Error.cc index 3eae5c9..c03f75f 100644 --- a/pdf2swf/xpdf/Error.cc +++ b/pdf2swf/xpdf/Error.cc @@ -2,15 +2,16 @@ // // Error.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include diff --git a/pdf2swf/xpdf/Error.h b/pdf2swf/xpdf/Error.h index 77801c5..0ce55e9 100644 --- a/pdf2swf/xpdf/Error.h +++ b/pdf2swf/xpdf/Error.h @@ -2,14 +2,16 @@ // // Error.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef ERROR_H #define ERROR_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/ErrorCodes.h b/pdf2swf/xpdf/ErrorCodes.h index 4e0d38a..b28528d 100644 --- a/pdf2swf/xpdf/ErrorCodes.h +++ b/pdf2swf/xpdf/ErrorCodes.h @@ -2,7 +2,7 @@ // // ErrorCodes.h // -// Copyright 2002 Glyph & Cog, LLC +// Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== @@ -21,4 +21,16 @@ #define errEncrypted 4 // file was encrypted and password was // incorrect or not supplied +#define errHighlightFile 5 // nonexistent or invalid highlight file + +#define errBadPrinter 6 // invalid printer + +#define errPrinting 7 // error during printing + +#define errPermission 8 // PDF file doesn't allow that operation + +#define errBadPageNum 9 // invalid page number + +#define errFileIO 10 // file I/O error + #endif diff --git a/pdf2swf/xpdf/FoFiBase.cc b/pdf2swf/xpdf/FoFiBase.cc new file mode 100644 index 0000000..28d0b8c --- /dev/null +++ b/pdf2swf/xpdf/FoFiBase.cc @@ -0,0 +1,156 @@ +//======================================================================== +// +// 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/pdf2swf/xpdf/FoFiBase.h b/pdf2swf/xpdf/FoFiBase.h new file mode 100644 index 0000000..b78840b --- /dev/null +++ b/pdf2swf/xpdf/FoFiBase.h @@ -0,0 +1,57 @@ +//======================================================================== +// +// FoFiBase.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIBASE_H +#define FOFIBASE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ + +typedef void (*FoFiOutputFunc)(void *stream, char *data, int len); + +//------------------------------------------------------------------------ +// FoFiBase +//------------------------------------------------------------------------ + +class FoFiBase { +public: + + virtual ~FoFiBase(); + +protected: + + FoFiBase(char *fileA, int lenA, GBool freeFileDataA); + static char *readFile(char *fileName, int *fileLen); + + // S = signed / U = unsigned + // 8/16/32/Var = word length, in bytes + // BE = big endian + int getS8(int pos, GBool *ok); + int getU8(int pos, GBool *ok); + int getS16BE(int pos, GBool *ok); + int getU16BE(int pos, GBool *ok); + int getS32BE(int pos, GBool *ok); + Guint getU32BE(int pos, GBool *ok); + Guint getUVarBE(int pos, int size, GBool *ok); + + GBool checkRegion(int pos, int size); + + Guchar *fileData; + Guchar *file; + int len; + GBool freeFileData; +}; + +#endif diff --git a/pdf2swf/xpdf/FoFiEncodings.cc b/pdf2swf/xpdf/FoFiEncodings.cc new file mode 100644 index 0000000..37a17f5 --- /dev/null +++ b/pdf2swf/xpdf/FoFiEncodings.cc @@ -0,0 +1,994 @@ +//======================================================================== +// +// 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/pdf2swf/xpdf/FoFiEncodings.h b/pdf2swf/xpdf/FoFiEncodings.h new file mode 100644 index 0000000..50e285d --- /dev/null +++ b/pdf2swf/xpdf/FoFiEncodings.h @@ -0,0 +1,36 @@ +//======================================================================== +// +// FoFiEncodings.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIENCODINGS_H +#define FOFIENCODINGS_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// Type 1 and 1C font data +//------------------------------------------------------------------------ + +extern char *fofiType1StandardEncoding[256]; +extern char *fofiType1ExpertEncoding[256]; + +//------------------------------------------------------------------------ +// Type 1C font data +//------------------------------------------------------------------------ + +extern char *fofiType1CStdStrings[391]; +extern Gushort fofiType1CISOAdobeCharset[229]; +extern Gushort fofiType1CExpertCharset[166]; +extern Gushort fofiType1CExpertSubsetCharset[87]; + +#endif diff --git a/pdf2swf/xpdf/FoFiTrueType.cc b/pdf2swf/xpdf/FoFiTrueType.cc new file mode 100644 index 0000000..a4cf43c --- /dev/null +++ b/pdf2swf/xpdf/FoFiTrueType.cc @@ -0,0 +1,1438 @@ +//======================================================================== +// +// FoFiTrueType.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gtypes.h" +#include "gmem.h" +#include "GString.h" +#include "GHash.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 +// + +//------------------------------------------------------------------------ + +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 locaTag 0x6c6f6361 +#define nameTag 0x6e616d65 +#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 + +//------------------------------------------------------------------------ + +// 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) { + FoFiTrueType *ff; + + ff = new FoFiTrueType(fileA, lenA, gFalse); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType *FoFiTrueType::load(char *fileName) { + FoFiTrueType *ff; + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + ff = new FoFiTrueType(fileA, lenA, gTrue); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + tables = NULL; + nTables = 0; + cmaps = NULL; + nCmaps = 0; + nameToGID = NULL; + parsedOk = gFalse; + + parse(); +} + +FoFiTrueType::~FoFiTrueType() { + gfree(tables); + gfree(cmaps); + 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); +} + +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) { + char buf[512]; + GBool ok; + + // write the header + ok = gTrue; + sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf, strlen(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); + sprintf(buf, "/FontBBox [%d %d %d %d] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf, strlen(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); + + // end the dictionary and define the font + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::convertToCIDType2(char *psName, + Gushort *cidMap, int nCIDs, + FoFiOutputFunc outputFunc, + void *outputStream) { + char buf[512]; + Gushort cid; + GBool ok; + int i, j, k; + + // write the header + ok = gTrue; + sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf, strlen(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) { + sprintf(buf, "/CIDCount %d def\n", nCIDs); + (*outputFunc)(outputStream, buf, strlen(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]; + sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf, strlen(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]; + sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, "> def\n", 6); + } + } else { + // direct mapping - just fill the string(s) with s[i]=i + sprintf(buf, "/CIDCount %d def\n", nGlyphs); + (*outputFunc)(outputStream, buf, strlen(buf)); + if (nGlyphs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [\n", 10); + for (i = 0; i < nGlyphs; i += 32767) { + j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; + sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add" + " 255 and put\n", i); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, " } for\n", 8); + } + (*outputFunc)(outputStream, "] def\n", 6); + } else { + sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, " 0 1 %d {\n", nGlyphs - 1); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*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); + sprintf(buf, "/FontBBox [%d %d %d %d] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf, strlen(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); + + // end the dictionary and define the font + (*outputFunc)(outputStream, + "CIDFontName currentdict end /CIDFont defineresource pop\n", + 56); +} + +void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, + FoFiOutputFunc outputFunc, + void *outputStream) { + char buf[512]; + GString *sfntsName; + int n, i, j; + + // write the Type 42 sfnts array + sfntsName = (new GString(psName))->append("_sfnts"); + cvtSfnts(outputFunc, outputStream, sfntsName); + 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)); + sprintf(buf, "_%02x def\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + sprintf(buf, "/FontBBox [%d %d %d %d] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/sfnts ", 7); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, "_sfnts def\n", 11); + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < n; ++j) { + sprintf(buf, "dup %d /c%02x put\n", j, j); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + for (j = 0; j < 256 && i+j < n; ++j) { + sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*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) { + sprintf(buf, "%d\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, strlen(psName)); + sprintf(buf, "_%02x findfont\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, + void *outputStream) { + static char cmapTab[20] = { + 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, 0, // subtable format + 0, 1, // subtable length + 0, 1, // subtable version + 0, // map char 0 -> glyph 0 + 0 // pad to multiple 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 + }; + GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen; + int nZeroLengthTables; + TrueTypeLoca *locaTable; + TrueTypeTable *newTables; + int nNewTables, cmapIdx, cmapLen, glyfLen; + char *tableDir; + char locaBuf[4]; + GBool ok; + Guint t; + int pos, i, j, k, n; + + // check for missing tables + missingCmap = (cmapIdx = seekTable("cmap")) < 0; + missingName = seekTable("name") < 0; + missingPost = seekTable("post") < 0; + + // read the loca table, check to see if it's sorted + locaTable = (TrueTypeLoca *)gmalloc((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; + } + 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; + } + } + + // if nothing is broken, just write the TTF file as is + if (!missingCmap && !missingName && !missingPost && !unsortedLoca && + !badCmapLen && nZeroLengthTables == 0) { + (*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; + } + + // 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 + nNewTables = nTables - nZeroLengthTables + + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + + (missingPost ? 1 : 0); + newTables = (TrueTypeTable *)gmalloc(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 (newTables[j].tag == cmapTag && badCmapLen) { + newTables[j].len = cmapLen; + } else if (newTables[j].tag == locaTag && unsortedLoca) { + newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); + } else if (newTables[j].tag == glyfTag && unsortedLoca) { + newTables[j].len = glyfLen; + } + ++j; + } + } + if (missingCmap) { + newTables[j].tag = cmapTag; + newTables[j].checksum = 0; //~ should compute the checksum + newTables[j].len = sizeof(cmapTab); + ++j; + } + if (missingName) { + newTables[j].tag = nameTag; + newTables[j].checksum = 0; //~ should compute the checksum + newTables[j].len = sizeof(nameTab); + ++j; + } + if (missingPost) { + newTables[j].tag = postTag; + newTables[j].checksum = 0; //~ should compute the checksum + newTables[j].len = sizeof(postTab); + ++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); + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (newTables[i].tag == cmapTag && missingCmap) { + (*outputFunc)(outputStream, cmapTab, 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 == 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(tableDir); + gfree(newTables); + done1: + gfree(locaTable); +} + +void FoFiTrueType::cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + char buf[64]; + int i; + + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + if (encoding) { + for (i = 0; i < 256; ++i) { + if (!(name = encoding[i])) { + name = ".notdef"; + } + sprintf(buf, "dup %d /", i); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, name, strlen(name)); + (*outputFunc)(outputStream, " put\n", 5); + } + } else { + for (i = 0; i < 256; ++i) { + sprintf(buf, "dup %d /c%02x put\n", i, i); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); +} + +void FoFiTrueType::cvtCharStrings(char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + char buf[64], 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)); + sprintf(buf, " %d def\n", k); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } + } + + err: + (*outputFunc)(outputStream, "end readonly def\n", 17); +} + +void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name) { + 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; + + // 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 *)gmalloc((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 *)gmalloc((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; + } + } + + // 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 (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); + } + } + } + } + + // end the sfnts array + (*outputFunc)(outputStream, "] def\n", 6); + + gfree(locaData); + gfree(locaTable); +} + +void FoFiTrueType::dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream) { + char buf[64]; + int pad, i, j; + + (*outputFunc)(outputStream, "<", 1); + for (i = 0; i < length; i += 32) { + for (j = 0; j < 32 && i+j < length; ++j) { + sprintf(buf, "%02X", s[i+j] & 0xff); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + 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() { + int pos, i, j; + + parsedOk = gTrue; + + // read the table directory + nTables = getU16BE(4, &parsedOk); + if (!parsedOk) { + return; + } + tables = (TrueTypeTable *)gmalloc(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("loca") < 0 || + seekTable("maxp") < 0 || + seekTable("glyf") < 0 || + seekTable("hmtx") < 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 *)gmalloc(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; + } + + // read the post table + readPostTable(); + if (!parsedOk) { + return; + } +} + +void FoFiTrueType::readPostTable() { + GString *name; + int tablePos, postFmt, stringIdx, stringPos; + int i, j, n, m; + + if ((i = seekTable("post")) < 0) { + return; + } + tablePos = tables[i].offset; + postFmt = getU32BE(tablePos, &parsedOk); + if (!parsedOk) { + return; + } + 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, &parsedOk); + if (!parsedOk) { + return; + } + if (n > nGlyphs) { + n = nGlyphs; + } + stringIdx = 0; + stringPos = tablePos + 34 + 2*n; + for (i = 0; i < n; ++i) { + j = getU16BE(tablePos + 34 + 2*i, &parsedOk); + 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, &parsedOk)) ; + if (!parsedOk) { + return; + } + } + m = getU8(stringPos, &parsedOk); + if (!parsedOk || !checkRegion(stringPos + 1, m)) { + parsedOk = gFalse; + return; + } + 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, &parsedOk); + if (!parsedOk) { + return; + } + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } + } + } +} + +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/pdf2swf/xpdf/FoFiTrueType.h b/pdf2swf/xpdf/FoFiTrueType.h new file mode 100644 index 0000000..ea05eec --- /dev/null +++ b/pdf2swf/xpdf/FoFiTrueType.h @@ -0,0 +1,133 @@ +//======================================================================== +// +// FoFiTrueType.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITRUETYPE_H +#define FOFITRUETYPE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +class GHash; +struct TrueTypeTable; +struct TrueTypeCmap; + +//------------------------------------------------------------------------ +// FoFiTrueType +//------------------------------------------------------------------------ + +class FoFiTrueType: public FoFiBase { +public: + + // Create a FoFiTrueType object from a memory buffer. + static FoFiTrueType *make(char *fileA, int lenA); + + // Create a FoFiTrueType object from a file on disk. + static FoFiTrueType *load(char *fileName); + + virtual ~FoFiTrueType(); + + // Return the number of cmaps defined by this font. + int getNumCmaps(); + + // Return the platform ID of the th cmap. + int getCmapPlatform(int i); + + // Return the encoding ID of the th cmap. + int getCmapEncoding(int i); + + // Return the index of the cmap for , . Returns + // -1 if there is no corresponding cmap. + int findCmap(int platform, int encoding); + + // Return the GID corresponding to according to the th cmap. + Gushort mapCodeToGID(int i, int c); + + // Returns the GID corresponding to according to the post + // table. Returns 0 if there is no mapping for or if the + // font does not have a post table. + int mapNameToGID(char *name); + + // Returns the least restrictive embedding licensing right (as + // defined by the TrueType spec): + // * 4: OS/2 table is missing or invalid + // * 3: installable embedding + // * 2: editable embedding + // * 1: preview & print embedding + // * 0: restricted license embedding + int getEmbeddingRights(); + + // Convert to a Type 42 font, suitable for embedding in a PostScript + // file. will be used as the PostScript font name (so we + // don't need to depend on the 'name' table in the font). The + // array specifies the mapping from char codes to names. + // If is NULL, the encoding is unknown or undefined. The + // array specifies the mapping from char codes to GIDs. + void convertToType42(char *psName, char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 2 CIDFont, suitable for embedding in a + // PostScript file. will be used as the PostScript font + // name (so we don't need to depend on the 'name' table in the + // font). The array maps CIDs to GIDs; it has + // entries. + void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. will be used as the + // PostScript font name (so we don't need to depend on the 'name' + // table in the font). The array maps CIDs to GIDs; it has + // entries. + void convertToType0(char *psName, Gushort *cidMap, int nCIDs, + FoFiOutputFunc outputFunc, void *outputStream); + + // Write a clean TTF file, filling in missing tables and correcting + // various other errors. If the font is complete and correct, it + // will be written unmodified. + void writeTTF(FoFiOutputFunc outputFunc, void *outputStream); + +private: + + FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA); + void cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream); + void cvtCharStrings(char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream); + void cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name); + void dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream); + Guint computeTableChecksum(Guchar *data, int length); + void parse(); + void readPostTable(); + int seekTable(char *tag); + + TrueTypeTable *tables; + int nTables; + TrueTypeCmap *cmaps; + int nCmaps; + int nGlyphs; + int locaFmt; + int bbox[4]; + GHash *nameToGID; + + GBool parsedOk; +}; + +#endif diff --git a/pdf2swf/xpdf/FoFiType1.cc b/pdf2swf/xpdf/FoFiType1.cc new file mode 100644 index 0000000..fe54a63 --- /dev/null +++ b/pdf2swf/xpdf/FoFiType1.cc @@ -0,0 +1,207 @@ +//======================================================================== +// +// 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; + 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); + + // copy everything after the encoding + if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { + line = getNextLine(line); + } else { + for (line = getNextLine(line); + line && strncmp(line, "readonly def", 12); + line = getNextLine(line)) ; + } + if (line) { + (*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 **)gmalloc(256 * sizeof(char *)); + for (j = 0; j < 256; ++j) { + encoding[j] = NULL; + } + line = getNextLine(line); + for (j = 0; j < 300 && line; ++j) { + line1 = getNextLine(line); + 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'; + if ((code = atoi(p)) < 256) { + *p2 = c; + 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 { + if (strtok(buf, " \t") && + (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { + break; + } + } + line = line1; + } + //~ check for getinterval/putinterval junk + + } else { + line = getNextLine(line); + } + + ++i; + } + + parsed = gTrue; +} diff --git a/pdf2swf/xpdf/FoFiType1.h b/pdf2swf/xpdf/FoFiType1.h new file mode 100644 index 0000000..843352b --- /dev/null +++ b/pdf2swf/xpdf/FoFiType1.h @@ -0,0 +1,59 @@ +//======================================================================== +// +// FoFiType1.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITYPE1_H +#define FOFITYPE1_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +//------------------------------------------------------------------------ +// FoFiType1 +//------------------------------------------------------------------------ + +class FoFiType1: public FoFiBase { +public: + + // Create a FoFiType1 object from a memory buffer. + static FoFiType1 *make(char *fileA, int lenA); + + // Create a FoFiType1 object from a file on disk. + static FoFiType1 *load(char *fileName); + + virtual ~FoFiType1(); + + // Return the font name. + char *getName(); + + // Return the encoding, as an array of 256 names (any of which may + // be NULL). + char **getEncoding(); + + // Write a version of the Type 1 font file with a new encoding. + void writeEncoded(char **newEncoding, + FoFiOutputFunc outputFunc, void *outputStream); + +private: + + FoFiType1(char *fileA, int lenA, GBool freeFileDataA); + + char *getNextLine(char *line); + void parse(); + + char *name; + char **encoding; + GBool parsed; +}; + +#endif diff --git a/pdf2swf/xpdf/FoFiType1C.cc b/pdf2swf/xpdf/FoFiType1C.cc new file mode 100644 index 0000000..91a21ad --- /dev/null +++ b/pdf2swf/xpdf/FoFiType1C.cc @@ -0,0 +1,2385 @@ +//======================================================================== +// +// 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 *)gmalloc(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 **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, + void *outputStream) { + Type1CEexecBuf eb; + Type1CIndex subrIdx; + Type1CIndexVal val; + char buf[512]; + char **enc; + GBool ok; + int i; + + // write header and font dictionary, up to encoding + ok = gTrue; + (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); + (*outputFunc)(outputStream, name->getCString(), name->getLength()); + if (topDict.versionSID != 0) { + getString(topDict.versionSID, buf, &ok); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*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, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.noticeSID != 0) { + getString(topDict.noticeSID, buf, &ok); + (*outputFunc)(outputStream, "/Notice (", 9); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.copyrightSID != 0) { + getString(topDict.copyrightSID, buf, &ok); + (*outputFunc)(outputStream, "/Copyright (", 12); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.fullNameSID != 0) { + getString(topDict.fullNameSID, buf, &ok); + (*outputFunc)(outputStream, "/FullName (", 11); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.familyNameSID != 0) { + getString(topDict.familyNameSID, buf, &ok); + (*outputFunc)(outputStream, "/FamilyName (", 13); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.weightSID != 0) { + getString(topDict.weightSID, buf, &ok); + (*outputFunc)(outputStream, "/Weight (", 9); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.isFixedPitch) { + (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); + } else { + (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); + } + sprintf(buf, "/ItalicAngle %g def\n", topDict.italicAngle); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/UnderlinePosition %g def\n", topDict.underlinePosition); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/UnderlineThickness %g def\n", topDict.underlineThickness); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, name->getCString(), name->getLength()); + (*outputFunc)(outputStream, " def\n", 5); + sprintf(buf, "/PaintType %d def\n", topDict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], + topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/FontBBox [%g %g %g %g] readonly def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf, strlen(buf)); + if (topDict.uniqueID != 0) { + sprintf(buf, "/UniqueID %d def\n", topDict.uniqueID); + (*outputFunc)(outputStream, buf, strlen(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]) { + sprintf(buf, "dup %d /%s put\n", i, enc[i]); + (*outputFunc)(outputStream, buf, strlen(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) { + sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].blueValues[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (i = 0; i < privateDicts[0].nOtherBlues; ++i) { + sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].otherBlues[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) { + sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].familyBlues[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) { + sprintf(buf, "%s%d", i > 0 ? " " : "", + privateDicts[0].familyOtherBlues[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].blueScale != 0.039625) { + sprintf(buf, "/BlueScale %g def\n", privateDicts[0].blueScale); + eexecWrite(&eb, buf); + } + if (privateDicts[0].blueShift != 7) { + sprintf(buf, "/BlueShift %d def\n", privateDicts[0].blueShift); + eexecWrite(&eb, buf); + } + if (privateDicts[0].blueFuzz != 1) { + sprintf(buf, "/BlueFuzz %d def\n", privateDicts[0].blueFuzz); + eexecWrite(&eb, buf); + } + if (privateDicts[0].hasStdHW) { + sprintf(buf, "/StdHW [%g] def\n", privateDicts[0].stdHW); + eexecWrite(&eb, buf); + } + if (privateDicts[0].hasStdVW) { + sprintf(buf, "/StdVW [%g] def\n", privateDicts[0].stdVW); + eexecWrite(&eb, buf); + } + if (privateDicts[0].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { + sprintf(buf, "%s%g", i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { + sprintf(buf, "%s%g", i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].hasForceBold) { + sprintf(buf, "/ForceBold %s def\n", + privateDicts[0].forceBold ? "true" : "false"); + eexecWrite(&eb, buf); + } + if (privateDicts[0].forceBoldThreshold != 0) { + sprintf(buf, "/ForceBoldThreshold %g def\n", + privateDicts[0].forceBoldThreshold); + eexecWrite(&eb, buf); + } + if (privateDicts[0].languageGroup != 0) { + sprintf(buf, "/LanguageGroup %d def\n", privateDicts[0].languageGroup); + eexecWrite(&eb, buf); + } + if (privateDicts[0].expansionFactor != 0.06) { + sprintf(buf, "/ExpansionFactor %g def\n", privateDicts[0].expansionFactor); + eexecWrite(&eb, buf); + } + + // set up subroutines + ok = gTrue; + getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // write the CharStrings + sprintf(buf, "2 index /CharStrings %d dict dup begin\n", nGlyphs); + eexecWrite(&eb, buf); + for (i = 0; i < nGlyphs; ++i) { + ok = gTrue; + getIndexVal(&charStringsIdx, i, &val, &ok); + if (ok) { + getString(charset[i], buf, &ok); + if (ok) { + eexecCvtGlyph(&eb, buf, 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; + char buf[512], buf2[512]; + 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 *)gmalloc(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 *)gmalloc((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, buf, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Registry (", 13); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") def\n", 6); + } + ok = gTrue; + getString(topDict.orderingSID, buf, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Ordering (", 13); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") def\n", 6); + } + } else { + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + } + sprintf(buf, " /Supplement %d def\n", topDict.supplement); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "end def\n", 8); + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], + topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/FontBBox [%g %g %g %g] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); + (*outputFunc)(outputStream, " /FSType 8 def\n", 16); + (*outputFunc)(outputStream, "end def\n", 8); + + // CIDFont-specific entries + sprintf(buf, "/CIDCount %d def\n", nCIDs); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); + sprintf(buf, "/GDBytes %d def\n", gdBytes); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); + if (topDict.paintType != 0) { + sprintf(buf, "/PaintType %d def\n", topDict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + + // FDArray entry + sprintf(buf, "/FDArray %d array\n", nFDs); + (*outputFunc)(outputStream, buf, strlen(buf)); + for (i = 0; i < nFDs; ++i) { + sprintf(buf, "dup %d 10 dict begin\n", i); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + sprintf(buf, "/PaintType %d def\n", topDict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); + if (privateDicts[i].nBlueValues) { + (*outputFunc)(outputStream, "/BlueValues [", 13); + for (j = 0; j < privateDicts[i].nBlueValues; ++j) { + sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].blueValues[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nOtherBlues) { + (*outputFunc)(outputStream, "/OtherBlues [", 13); + for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { + sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].otherBlues[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyBlues) { + (*outputFunc)(outputStream, "/FamilyBlues [", 14); + for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { + sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].familyBlues[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyOtherBlues) { + (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19); + for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { + sprintf(buf, "%s%d", j > 0 ? " " : "", + privateDicts[i].familyOtherBlues[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].blueScale != 0.039625) { + sprintf(buf, "/BlueScale %g def\n", privateDicts[i].blueScale); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].blueShift != 7) { + sprintf(buf, "/BlueShift %d def\n", privateDicts[i].blueShift); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].blueFuzz != 1) { + sprintf(buf, "/BlueFuzz %d def\n", privateDicts[i].blueFuzz); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].hasStdHW) { + sprintf(buf, "/StdHW [%g] def\n", privateDicts[i].stdHW); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].hasStdVW) { + sprintf(buf, "/StdVW [%g] def\n", privateDicts[i].stdVW); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].nStemSnapH) { + (*outputFunc)(outputStream, "/StemSnapH [", 12); + for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { + sprintf(buf, "%s%g", j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nStemSnapV) { + (*outputFunc)(outputStream, "/StemSnapV [", 12); + for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { + sprintf(buf, "%s%g", j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].hasForceBold) { + sprintf(buf, "/ForceBold %s def\n", + privateDicts[i].forceBold ? "true" : "false"); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].forceBoldThreshold != 0) { + sprintf(buf, "/ForceBoldThreshold %g def\n", + privateDicts[i].forceBoldThreshold); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].languageGroup != 0) { + sprintf(buf, "/LanguageGroup %d def\n", privateDicts[i].languageGroup); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].expansionFactor != 0.06) { + sprintf(buf, "/ExpansionFactor %g def\n", + privateDicts[i].expansionFactor); + (*outputFunc)(outputStream, buf, strlen(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); + sprintf(buf, "(Hex) %d StartData\n", + offset + charStrings->getLength()); + (*outputFunc)(outputStream, buf, strlen(buf)); + + // write the charstring offset (CIDMap) table + for (i = 0; i <= nCIDs; i += 6) { + for (j = 0; j < 6 && i+j <= nCIDs; ++j) { + if (i+j < nCIDs && cidMap[i+j] >= 0) { + buf[0] = (char)fdSelect[cidMap[i+j]]; + } else { + buf[0] = (char)0; + } + n = offset + charStringOffsets[i+j]; + for (k = gdBytes; k >= 1; --k) { + buf[k] = (char)(n & 0xff); + n >>= 8; + } + for (k = 0; k <= gdBytes; ++k) { + sprintf(buf2, "%02x", buf[k] & 0xff); + (*outputFunc)(outputStream, buf2, 2); + } + } + (*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) { + sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff); + (*outputFunc)(outputStream, buf, strlen(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; + char buf[512]; + 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 *)gmalloc(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 + fd = 0; + for (j = 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)); + sprintf(buf, "_%02x def\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/FontBBox [%g %g %g %g] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/PaintType %d def\n", topDict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + if (topDict.paintType != 0) { + sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + sprintf(buf, "dup %d /c%02x put\n", j, j); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (j < 256) { + sprintf(buf, "%d 1 255 { 1 index exch /.notdef put } for\n", j); + (*outputFunc)(outputStream, buf, strlen(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) { + sprintf(buf, "%s%d", k > 0 ? " " : "", privateDicts[fd].blueValues[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { + sprintf(buf, "%s%d", k > 0 ? " " : "", privateDicts[fd].otherBlues[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { + sprintf(buf, "%s%d", k > 0 ? " " : "", + privateDicts[fd].familyBlues[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { + sprintf(buf, "%s%d", k > 0 ? " " : "", + privateDicts[fd].familyOtherBlues[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].blueScale != 0.039625) { + sprintf(buf, "/BlueScale %g def\n", privateDicts[fd].blueScale); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].blueShift != 7) { + sprintf(buf, "/BlueShift %d def\n", privateDicts[fd].blueShift); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].blueFuzz != 1) { + sprintf(buf, "/BlueFuzz %d def\n", privateDicts[fd].blueFuzz); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].hasStdHW) { + sprintf(buf, "/StdHW [%g] def\n", privateDicts[fd].stdHW); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].hasStdVW) { + sprintf(buf, "/StdVW [%g] def\n", privateDicts[fd].stdVW); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { + sprintf(buf, "%s%g", k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { + sprintf(buf, "%s%g", k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].hasForceBold) { + sprintf(buf, "/ForceBold %s def\n", + privateDicts[fd].forceBold ? "true" : "false"); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].forceBoldThreshold != 0) { + sprintf(buf, "/ForceBoldThreshold %g def\n", + privateDicts[fd].forceBoldThreshold); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].languageGroup != 0) { + sprintf(buf, "/LanguageGroup %d def\n", privateDicts[fd].languageGroup); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].expansionFactor != 0.06) { + sprintf(buf, "/ExpansionFactor %g def\n", + privateDicts[fd].expansionFactor); + eexecWrite(&eb, buf); + } + + // set up the subroutines + ok = gTrue; + getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // start the CharStrings + sprintf(buf, "2 index /CharStrings 256 dict dup begin\n"); + eexecWrite(&eb, buf); + + // 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) { + sprintf(buf, "c%02x", j); + eexecCvtGlyph(&eb, buf, val.pos, val.len, + &subrIdx, &privateDicts[fd]); + } + } + } + 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); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < nCIDs; i += 256) { + sprintf(buf, "%d\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < nCIDs; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, strlen(psName)); + sprintf(buf, "_%02x findfont\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*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) { + char buf[512]; + GString *charBuf; + + // generate the charstring + charBuf = new GString(); + cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue); + + sprintf(buf, "/%s %d RD ", glyphName, charBuf->getLength()); + eexecWrite(eb, buf); + 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; + } + + 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) { + 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) { + 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 (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; + 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; + 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; + 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; + 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 (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 (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 (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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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 *) + gmalloc(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.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; 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. +void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { + int pos, pSize, pOffset; + + 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; + } + nOps = 0; + } + } + readPrivateDict(pOffset, pSize, pDict); +} + +void FoFiType1C::readPrivateDict(int offset, int length, + Type1CPrivateDict *pDict) { + int pos; + + 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 = 0; + pDict->nominalWidthX = 0; + pDict->nominalWidthXFP = 0; + + // 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; + break; + case 0x0015: + pDict->nominalWidthX = ops[0].num; + 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 **)gmalloc(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 *)gmalloc(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 + idx->offSize = 0; + idx->startPos = idx->endPos = 0; + } 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/pdf2swf/xpdf/FoFiType1C.h b/pdf2swf/xpdf/FoFiType1C.h new file mode 100644 index 0000000..e6f2b64 --- /dev/null +++ b/pdf2swf/xpdf/FoFiType1C.h @@ -0,0 +1,226 @@ +//======================================================================== +// +// FoFiType1C.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITYPE1C_H +#define FOFITYPE1C_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +class GString; + +//------------------------------------------------------------------------ + +struct Type1CIndex { + int pos; // absolute position in file + int len; // length (number of entries) + int offSize; // offset size + int startPos; // position of start of index data - 1 + int endPos; // position one byte past end of the index +}; + +struct Type1CIndexVal { + int pos; // absolute position in file + int len; // length, in bytes +}; + +struct Type1CTopDict { + int firstOp; + + int versionSID; + int noticeSID; + int copyrightSID; + int fullNameSID; + int familyNameSID; + int weightSID; + int isFixedPitch; + double italicAngle; + double underlinePosition; + double underlineThickness; + int paintType; + int charstringType; + double fontMatrix[6]; + int uniqueID; + double fontBBox[4]; + double strokeWidth; + int charsetOffset; + int encodingOffset; + int charStringsOffset; + int privateSize; + int privateOffset; + + // CIDFont entries + int registrySID; + int orderingSID; + int supplement; + int fdArrayOffset; + int fdSelectOffset; +}; + +#define type1CMaxBlueValues 14 +#define type1CMaxOtherBlues 10 +#define type1CMaxStemSnap 12 + +struct Type1CPrivateDict { + int blueValues[type1CMaxBlueValues]; + int nBlueValues; + int otherBlues[type1CMaxOtherBlues]; + int nOtherBlues; + int familyBlues[type1CMaxBlueValues]; + int nFamilyBlues; + int familyOtherBlues[type1CMaxOtherBlues]; + int nFamilyOtherBlues; + double blueScale; + int blueShift; + int blueFuzz; + double stdHW; + GBool hasStdHW; + double stdVW; + GBool hasStdVW; + double stemSnapH[type1CMaxStemSnap]; + int nStemSnapH; + double stemSnapV[type1CMaxStemSnap]; + int nStemSnapV; + GBool forceBold; + GBool hasForceBold; + double forceBoldThreshold; + int languageGroup; + double expansionFactor; + int initialRandomSeed; + int subrsOffset; + double defaultWidthX; + GBool defaultWidthXFP; + double nominalWidthX; + GBool nominalWidthXFP; +}; + +struct Type1COp { + GBool isNum; // true -> number, false -> operator + GBool isFP; // true -> floating point number, false -> int + union { + double num; // if num is true + int op; // if num is false + }; +}; + +struct Type1CEexecBuf { + FoFiOutputFunc outputFunc; + void *outputStream; + GBool ascii; // ASCII encoding? + Gushort r1; // eexec encryption key + int line; // number of eexec chars left on current line +}; + +//------------------------------------------------------------------------ +// FoFiType1C +//------------------------------------------------------------------------ + +class FoFiType1C: public FoFiBase { +public: + + // Create a FoFiType1C object from a memory buffer. + static FoFiType1C *make(char *fileA, int lenA); + + // Create a FoFiType1C object from a file on disk. + static FoFiType1C *load(char *fileName); + + virtual ~FoFiType1C(); + + // Return the font name. + char *getName(); + + // Return the encoding, as an array of 256 names (any of which may + // be NULL). This is only useful with 8-bit fonts. + char **getEncoding(); + + // Return the mapping from CIDs to GIDs, and return the number of + // CIDs in *. This is only useful for CID fonts. + Gushort *getCIDToGIDMap(int *nCIDs); + + // Convert to a Type 1 font, suitable for embedding in a PostScript + // file. This is only useful with 8-bit fonts. If is + // not NULL, it will be used in place of the encoding in the Type 1C + // font. If is true the eexec section will be hex-encoded, + // otherwise it will be left as binary data. + void convertToType1(char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 CIDFont, suitable for embedding in a + // PostScript file. will be used as the PostScript font + // name. + void convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. will be used as the + // PostScript font name. + void convertToType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + +private: + + FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); + void eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName, + int offset, int nBytes, + Type1CIndex *subrIdx, + Type1CPrivateDict *pDict); + void cvtGlyph(int offset, int nBytes, GString *charBuf, + Type1CIndex *subrIdx, Type1CPrivateDict *pDict, + GBool top); + void cvtGlyphWidth(GBool useOp, GString *charBuf, + Type1CPrivateDict *pDict); + void cvtNum(double x, GBool isFP, GString *charBuf); + void eexecWrite(Type1CEexecBuf *eb, char *s); + void eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n); + GBool parse(); + void readTopDict(); + void readFD(int offset, int length, Type1CPrivateDict *pDict); + void readPrivateDict(int offset, int length, Type1CPrivateDict *pDict); + void readFDSelect(); + void buildEncoding(); + GBool readCharset(); + int getOp(int pos, GBool charstring, GBool *ok); + int getDeltaIntArray(int *arr, int maxLen); + int getDeltaFPArray(double *arr, int maxLen); + void getIndex(int pos, Type1CIndex *idx, GBool *ok); + void getIndexVal(Type1CIndex *idx, int i, Type1CIndexVal *val, GBool *ok); + char *getString(int sid, char *buf, GBool *ok); + + GString *name; + char **encoding; + + Type1CIndex nameIdx; + Type1CIndex topDictIdx; + Type1CIndex stringIdx; + Type1CIndex gsubrIdx; + Type1CIndex charStringsIdx; + + Type1CTopDict topDict; + Type1CPrivateDict *privateDicts; + + int nGlyphs; + int nFDs; + Guchar *fdSelect; + Gushort *charset; + int gsubrBias; + + GBool parsedOk; + + Type1COp ops[49]; // operands and operator + int nOps; // number of operands + int nHints; // number of hints for the current glyph + GBool firstOp; // true if we haven't hit the first op yet +}; + +#endif diff --git a/pdf2swf/xpdf/FontEncodingTables.cc b/pdf2swf/xpdf/FontEncodingTables.cc index bd5f9cf..f3b9280 100644 --- a/pdf2swf/xpdf/FontEncodingTables.cc +++ b/pdf2swf/xpdf/FontEncodingTables.cc @@ -2,7 +2,7 @@ // // FontEncodingTables.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -184,32 +184,32 @@ char *macRomanEncoding[256] = { "trademark", "acute", "dieresis", - NULL, + "notequal", "AE", "Oslash", - NULL, + "infinity", "plusminus", - NULL, - NULL, + "lessequal", + "greaterequal", "yen", "mu", - NULL, - NULL, - NULL, - NULL, - NULL, + "partialdiff", + "summation", + "product", + "pi", + "integral", "ordfeminine", "ordmasculine", - NULL, + "Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot", - NULL, + "radical", "florin", - NULL, - NULL, + "approxequal", + "Delta", "guillemotleft", "guillemotright", "ellipsis", @@ -226,7 +226,7 @@ char *macRomanEncoding[256] = { "quoteleft", "quoteright", "divide", - NULL, + "lozenge", "ydieresis", "Ydieresis", "fraction", @@ -251,7 +251,7 @@ char *macRomanEncoding[256] = { "Igrave", "Oacute", "Ocircumflex", - NULL, + "apple", "Ograve", "Uacute", "Ucircumflex", diff --git a/pdf2swf/xpdf/FontEncodingTables.h b/pdf2swf/xpdf/FontEncodingTables.h index deee0a8..8b0a1e7 100644 --- a/pdf2swf/xpdf/FontEncodingTables.h +++ b/pdf2swf/xpdf/FontEncodingTables.h @@ -2,7 +2,7 @@ // // FontEncodingTables.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf2swf/xpdf/Function.cc b/pdf2swf/xpdf/Function.cc index 64ea60c..46b1912 100644 --- a/pdf2swf/xpdf/Function.cc +++ b/pdf2swf/xpdf/Function.cc @@ -2,15 +2,16 @@ // // Function.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -379,8 +380,8 @@ void SampledFunction::transform(double *in, double *out) { // pull 2^m values out of the sample array for (j = 0; j < (1<= 0; --k) { + idx = 0; + for (k = m - 1; k >= 0; --k) { idx = idx * sampleSize[k] + e[(j >> k) & 1][k]; } idx = idx * n + i; @@ -411,7 +412,6 @@ void SampledFunction::transform(double *in, double *out) { ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { Object obj1, obj2; - GBool hasN; int i; ok = gFalse; @@ -424,23 +424,14 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { error(-1, "Exponential function with more than one input"); goto err1; } - hasN = hasRange; - - //----- default values - for (i = 0; i < funcMaxOutputs; ++i) { - c0[i] = 0; - c1[i] = 1; - } //----- C0 if (dict->lookup("C0", &obj1)->isArray()) { - if (!hasN) { - n = obj1.arrayGetLength(); - hasN = gTrue; - } else if (obj1.arrayGetLength() != n) { + if (hasRange && obj1.arrayGetLength() != n) { error(-1, "Function's C0 array is wrong length"); goto err2; } + n = obj1.arrayGetLength(); for (i = 0; i < n; ++i) { obj1.arrayGet(i, &obj2); if (!obj2.isNum()) { @@ -450,15 +441,19 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { c0[i] = obj2.getNum(); obj2.free(); } + } else { + if (hasRange && n != 1) { + error(-1, "Function's C0 array is wrong length"); + goto err2; + } + n = 1; + c0[0] = 0; } obj1.free(); //----- C1 if (dict->lookup("C1", &obj1)->isArray()) { - if (!hasN) { - n = obj1.arrayGetLength(); - hasN = gTrue; - } else if (obj1.arrayGetLength() != n) { + if (obj1.arrayGetLength() != n) { error(-1, "Function's C1 array is wrong length"); goto err2; } @@ -471,6 +466,12 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { c1[i] = obj2.getNum(); obj2.free(); } + } else { + if (n != 1) { + error(-1, "Function's C1 array is wrong length"); + goto err2; + } + c1[0] = 1; } obj1.free(); @@ -482,13 +483,6 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { e = obj1.getNum(); obj1.free(); - // this isn't supposed to happen, but I've run into (broken) PDF - // files where it does - if (!hasN) { - error(-1, "Exponential function does not define number of output values"); - n = 1; - } - ok = gTrue; return; @@ -622,9 +616,13 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) { } StitchingFunction::StitchingFunction(StitchingFunction *func) { + int i; + k = func->k; funcs = (Function **)gmalloc(k * sizeof(Function *)); - memcpy(funcs, func->funcs, k * sizeof(Function *)); + for (i = 0; i < k; ++i) { + funcs[i] = func->funcs[i]->copy(); + } bounds = (double *)gmalloc((k + 1) * sizeof(double)); memcpy(bounds, func->bounds, (k + 1) * sizeof(double)); encode = (double *)gmalloc(2 * k * sizeof(double)); @@ -635,9 +633,11 @@ StitchingFunction::StitchingFunction(StitchingFunction *func) { StitchingFunction::~StitchingFunction() { int i; - for (i = 0; i < k; ++i) { - if (funcs[i]) { - delete funcs[i]; + if (funcs) { + for (i = 0; i < k; ++i) { + if (funcs[i]) { + delete funcs[i]; + } } } gfree(funcs); @@ -1095,14 +1095,14 @@ GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) { if (!parseCode(str, codePtr)) { return gFalse; } + delete tok; + if (!(tok = getToken(str))) { + error(-1, "Unexpected end of PostScript function stream"); + return gFalse; + } } else { elsePtr = -1; } - delete tok; - if (!(tok = getToken(str))) { - error(-1, "Unexpected end of PostScript function stream"); - return gFalse; - } if (!tok->cmp("if")) { if (elsePtr >= 0) { error(-1, "Got 'if' operator with two blocks in PostScript function"); @@ -1247,7 +1247,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) { } else { b2 = stack->popBool(); b1 = stack->popBool(); - stack->pushReal(b1 && b2); + stack->pushBool(b1 && b2); } break; case psOpAtan: @@ -1314,8 +1314,8 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) { stack->roll(2, 1); break; case psOpExp: - r2 = stack->popInt(); - r1 = stack->popInt(); + r2 = stack->popNum(); + r1 = stack->popNum(); stack->pushReal(pow(r1, r2)); break; case psOpFalse: @@ -1427,7 +1427,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) { if (stack->topIsInt()) { stack->pushInt(~stack->popInt()); } else { - stack->pushReal(!stack->popBool()); + stack->pushBool(!stack->popBool()); } break; case psOpOr: @@ -1438,7 +1438,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) { } else { b2 = stack->popBool(); b1 = stack->popBool(); - stack->pushReal(b1 || b2); + stack->pushBool(b1 || b2); } break; case psOpPop: @@ -1456,7 +1456,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) { } break; case psOpSin: - stack->pushReal(cos(stack->popNum())); + stack->pushReal(sin(stack->popNum())); break; case psOpSqrt: stack->pushReal(sqrt(stack->popNum())); @@ -1489,7 +1489,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) { } else { b2 = stack->popBool(); b1 = stack->popBool(); - stack->pushReal(b1 ^ b2); + stack->pushBool(b1 ^ b2); } break; case psOpIf: diff --git a/pdf2swf/xpdf/Function.h b/pdf2swf/xpdf/Function.h index 9b0879f..0ceb035 100644 --- a/pdf2swf/xpdf/Function.h +++ b/pdf2swf/xpdf/Function.h @@ -2,14 +2,16 @@ // // Function.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef FUNCTION_H #define FUNCTION_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -25,8 +27,8 @@ class PSStack; // Function //------------------------------------------------------------------------ -#define funcMaxInputs 8 -#define funcMaxOutputs 8 +#define funcMaxInputs 8 +#define funcMaxOutputs 32 class Function { public: diff --git a/pdf2swf/xpdf/GHash.cc b/pdf2swf/xpdf/GHash.cc index dc09f71..1dd0e26 100644 --- a/pdf2swf/xpdf/GHash.cc +++ b/pdf2swf/xpdf/GHash.cc @@ -2,15 +2,16 @@ // // GHash.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include "gmem.h" #include "GString.h" #include "GHash.h" @@ -19,7 +20,10 @@ struct GHashBucket { GString *key; - void *val; + union { + void *p; + int i; + } val; GHashBucket *next; }; @@ -60,35 +64,37 @@ GHash::~GHash() { } void GHash::add(GString *key, void *val) { - GHashBucket **oldTab; GHashBucket *p; - int oldSize, i, h; + int h; // expand the table if necessary if (len >= size) { - oldSize = size; - oldTab = tab; - size = 2*size + 1; - tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *)); - for (h = 0; h < size; ++h) { - tab[h] = NULL; - } - for (i = 0; i < oldSize; ++i) { - while (oldTab[i]) { - p = oldTab[i]; - oldTab[i] = oldTab[i]->next; - h = hash(p->key); - p->next = tab[h]; - tab[h] = p; - } - } - gfree(oldTab); + expand(); } // add the new symbol p = new GHashBucket; p->key = key; - p->val = val; + p->val.p = val; + h = hash(key); + p->next = tab[h]; + tab[h] = p; + ++len; +} + +void GHash::add(GString *key, int val) { + GHashBucket *p; + int h; + + // expand the table if necessary + if (len >= size) { + expand(); + } + + // add the new symbol + p = new GHashBucket; + p->key = key; + p->val.i = val; h = hash(key); p->next = tab[h]; tab[h] = p; @@ -102,7 +108,17 @@ void *GHash::lookup(GString *key) { if (!(p = find(key, &h))) { return NULL; } - return p->val; + return p->val.p; +} + +int GHash::lookupInt(GString *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + return p->val.i; } void *GHash::lookup(char *key) { @@ -112,7 +128,17 @@ void *GHash::lookup(char *key) { if (!(p = find(key, &h))) { return NULL; } - return p->val; + return p->val.p; +} + +int GHash::lookupInt(char *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + return p->val.i; } void *GHash::remove(GString *key) { @@ -132,7 +158,30 @@ void *GHash::remove(GString *key) { if (deleteKeys) { delete p->key; } - val = p->val; + val = p->val.p; + delete p; + --len; + return val; +} + +int GHash::removeInt(GString *key) { + GHashBucket *p; + GHashBucket **q; + int val; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.i; delete p; --len; return val; @@ -155,7 +204,30 @@ void *GHash::remove(char *key) { if (deleteKeys) { delete p->key; } - val = p->val; + val = p->val.p; + delete p; + --len; + return val; +} + +int GHash::removeInt(char *key) { + GHashBucket *p; + GHashBucket **q; + int val; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.i; delete p; --len; return val; @@ -183,7 +255,27 @@ GBool GHash::getNext(GHashIter **iter, GString **key, void **val) { (*iter)->p = tab[(*iter)->h]; } *key = (*iter)->p->key; - *val = (*iter)->p->val; + *val = (*iter)->p->val.p; + return gTrue; +} + +GBool GHash::getNext(GHashIter **iter, GString **key, int *val) { + if (!*iter) { + return gFalse; + } + if ((*iter)->p) { + (*iter)->p = (*iter)->p->next; + } + while (!(*iter)->p) { + if (++(*iter)->h == size) { + delete *iter; + *iter = NULL; + return gFalse; + } + (*iter)->p = tab[(*iter)->h]; + } + *key = (*iter)->p->key; + *val = (*iter)->p->val.i; return gTrue; } @@ -192,6 +284,30 @@ void GHash::killIter(GHashIter **iter) { *iter = NULL; } +void GHash::expand() { + GHashBucket **oldTab; + GHashBucket *p; + int oldSize, h, i; + + oldSize = size; + oldTab = tab; + size = 2*size + 1; + tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *)); + for (h = 0; h < size; ++h) { + tab[h] = NULL; + } + for (i = 0; i < oldSize; ++i) { + while (oldTab[i]) { + p = oldTab[i]; + oldTab[i] = oldTab[i]->next; + h = hash(p->key); + p->next = tab[h]; + tab[h] = p; + } + } + gfree(oldTab); +} + GHashBucket *GHash::find(GString *key, int *h) { GHashBucket *p; diff --git a/pdf2swf/xpdf/GHash.h b/pdf2swf/xpdf/GHash.h index 91d9700..4a6e08d 100644 --- a/pdf2swf/xpdf/GHash.h +++ b/pdf2swf/xpdf/GHash.h @@ -2,14 +2,16 @@ // // GHash.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GHASH_H #define GHASH_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -27,17 +29,24 @@ public: GHash(GBool deleteKeysA = gFalse); ~GHash(); void add(GString *key, void *val); + void add(GString *key, int val); void *lookup(GString *key); + int lookupInt(GString *key); void *lookup(char *key); + int lookupInt(char *key); void *remove(GString *key); + int removeInt(GString *key); void *remove(char *key); + int removeInt(char *key); int getLength() { return len; } void startIter(GHashIter **iter); GBool getNext(GHashIter **iter, GString **key, void **val); + GBool getNext(GHashIter **iter, GString **key, int *val); void killIter(GHashIter **iter); private: + void expand(); GHashBucket *find(GString *key, int *h); GHashBucket *find(char *key, int *h); int hash(GString *key); diff --git a/pdf2swf/xpdf/GList.cc b/pdf2swf/xpdf/GList.cc index f52bc26..9534232 100644 --- a/pdf2swf/xpdf/GList.cc +++ b/pdf2swf/xpdf/GList.cc @@ -2,15 +2,16 @@ // // GList.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "gmem.h" #include "GList.h" diff --git a/pdf2swf/xpdf/GList.h b/pdf2swf/xpdf/GList.h index 0ef4fd7..4c52489 100644 --- a/pdf2swf/xpdf/GList.h +++ b/pdf2swf/xpdf/GList.h @@ -2,14 +2,16 @@ // // GList.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GLIST_H #define GLIST_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/GMutex.h b/pdf2swf/xpdf/GMutex.h new file mode 100644 index 0000000..7fa93d8 --- /dev/null +++ b/pdf2swf/xpdf/GMutex.h @@ -0,0 +1,49 @@ +//======================================================================== +// +// GMutex.h +// +// Portable mutex macros. +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GMUTEX_H +#define GMUTEX_H + +// Usage: +// +// GMutex m; +// gInitMutex(&m); +// ... +// gLockMutex(&m); +// ... critical section ... +// gUnlockMutex(&m); +// ... +// gDestroyMutex(&m); + +#ifdef WIN32 + +#include + +typedef CRITICAL_SECTION GMutex; + +#define gInitMutex(m) InitializeCriticalSection(m) +#define gDestroyMutex(m) DeleteCriticalSection(m) +#define gLockMutex(m) EnterCriticalSection(m) +#define gUnlockMutex(m) LeaveCriticalSection(m) + +#else // assume pthreads + +#include + +typedef pthread_mutex_t GMutex; + +#define gInitMutex(m) pthread_mutex_init(m, NULL) +#define gDestroyMutex(m) pthread_mutex_destroy(m) +#define gLockMutex(m) pthread_mutex_lock(m) +#define gUnlockMutex(m) pthread_mutex_unlock(m) + +#endif + +#endif diff --git a/pdf2swf/xpdf/GString.cc b/pdf2swf/xpdf/GString.cc index 3bf626a..7653fd0 100644 --- a/pdf2swf/xpdf/GString.cc +++ b/pdf2swf/xpdf/GString.cc @@ -4,15 +4,16 @@ // // Simple variable-length string type. // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -203,8 +204,12 @@ GString *GString::del(int i, int n) { int j; if (n > 0) { - for (j = i; j <= length - n; ++j) + if (i + n > length) { + n = length - i; + } + for (j = i; j <= length - n; ++j) { s[j] = s[j + n]; + } resize(length -= n); } return this; diff --git a/pdf2swf/xpdf/GString.h b/pdf2swf/xpdf/GString.h index 93796cb..2083802 100644 --- a/pdf2swf/xpdf/GString.h +++ b/pdf2swf/xpdf/GString.h @@ -4,14 +4,16 @@ // // Simple variable-length string type. // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GSTRING_H #define GSTRING_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/Gfx.cc b/pdf2swf/xpdf/Gfx.cc index 81d164e..a52aa02 100644 --- a/pdf2swf/xpdf/Gfx.cc +++ b/pdf2swf/xpdf/Gfx.cc @@ -2,20 +2,22 @@ // // Gfx.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include #include #include "gmem.h" +#include "GlobalParams.h" #include "CharTypes.h" #include "Object.h" #include "Array.h" @@ -39,6 +41,12 @@ // constants //------------------------------------------------------------------------ +// Max recursive depth for a function shading fill. +#define functionMaxDepth 6 + +// Max delta allowed in any color component for a function shading fill. +#define functionColorDelta (1 / 256.0) + // Max number of splits along the t axis for an axial shading fill. #define axialMaxSplits 256 @@ -55,6 +63,10 @@ // Operator table //------------------------------------------------------------------------ +#ifdef WIN32 // this works around a bug in the VC7 compiler +# pragma optimize("",off) +#endif + Operator Gfx::opTab[] = { {"\"", 3, {tchkNum, tchkNum, tchkString}, &Gfx::opMoveSetShowText}, @@ -210,6 +222,10 @@ Operator Gfx::opTab[] = { &Gfx::opCurveTo2}, }; +#ifdef WIN32 // this works around a bug in the VC7 compiler +# pragma optimize("",on) +#endif + #define numOps (sizeof(opTab) / sizeof(Operator)) //------------------------------------------------------------------------ @@ -217,15 +233,23 @@ Operator Gfx::opTab[] = { //------------------------------------------------------------------------ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) { - Object obj1; + Object obj1, obj2; + Ref r; if (resDict) { // build font dictionary fonts = NULL; - resDict->lookup("Font", &obj1); - if (obj1.isDict()) { - fonts = new GfxFontDict(xref, obj1.getDict()); + resDict->lookupNF("Font", &obj1); + if (obj1.isRef()) { + obj1.fetch(xref, &obj2); + if (obj2.isDict()) { + r = obj1.getRef(); + fonts = new GfxFontDict(xref, &r, obj2.getDict()); + } + obj2.free(); + } else if (obj1.isDict()) { + fonts = new GfxFontDict(xref, NULL, obj1.getDict()); } obj1.free(); @@ -249,6 +273,7 @@ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) { xObjDict.initNull(); colorSpaceDict.initNull(); patternDict.initNull(); + shadingDict.initNull(); gStateDict.initNull(); } @@ -379,33 +404,38 @@ GBool GfxResources::lookupGState(char *name, Object *obj) { // Gfx //------------------------------------------------------------------------ -Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi, - PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate, - GBool printCommandsA) { +Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, + double hDPI, double vDPI, PDFRectangle *box, GBool crop, + PDFRectangle *cropBox, int rotate, + GBool (*abortCheckCbkA)(void *data), + void *abortCheckCbkDataA) { int i; xref = xrefA; subPage = gFalse; - printCommands = printCommandsA; + printCommands = globalParams->getPrintCommands(); // start the resource stack res = new GfxResources(xref, resDict, NULL); // initialize out = outA; - state = new GfxState(dpi, box, rotate, out->upsideDown()); + state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown()); fontChanged = gFalse; clip = clipNone; ignoreUndef = 0; - out->startPage(pageNum, state, cropBox->x1,cropBox->y1,cropBox->x2,cropBox->y2); + out->startPage(pageNum, state); out->setDefaultCTM(state->getCTM()); out->updateAll(state); for (i = 0; i < 6; ++i) { baseMatrix[i] = state->getCTM()[i]; } + formDepth = 0; + abortCheckCbk = abortCheckCbkA; + abortCheckCbkData = abortCheckCbkDataA; // set crop box - /*if (crop) { + if (crop) { state->moveTo(cropBox->x1, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y2); @@ -414,29 +444,34 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi, state->clip(); out->clip(state); state->clearPath(); - }*/ + } } Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, GBool crop, PDFRectangle *cropBox) { + PDFRectangle *box, GBool crop, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data), + void *abortCheckCbkDataA) { int i; xref = xrefA; subPage = gTrue; - printCommands = gFalse; + printCommands = globalParams->getPrintCommands(); // start the resource stack res = new GfxResources(xref, resDict, NULL); // initialize out = outA; - state = new GfxState(72, box, 0, gFalse); + state = new GfxState(72, 72, box, 0, gFalse); fontChanged = gFalse; clip = clipNone; ignoreUndef = 0; for (i = 0; i < 6; ++i) { baseMatrix[i] = state->getCTM()[i]; } + formDepth = 0; + abortCheckCbk = abortCheckCbkA; + abortCheckCbkData = abortCheckCbkDataA; // set crop box if (crop) { @@ -453,8 +488,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Gfx::~Gfx() { while (state->hasSaves()) { - state = state->restore(); - out->restoreState(state); + restoreState(); } if (!subPage) { out->endPage(); @@ -494,11 +528,11 @@ void Gfx::display(Object *obj, GBool topLevel) { void Gfx::go(GBool topLevel) { Object obj; Object args[maxArgs]; - int numArgs; - int i; + int numArgs, i; + int lastAbortCheck; // scan a sequence of objects - updateLevel = 0; + updateLevel = lastAbortCheck = 0; numArgs = 0; parser->getObj(&obj); while (!obj.isEOF()) { @@ -526,6 +560,16 @@ void Gfx::go(GBool topLevel) { updateLevel = 0; } + // check for an abort + if (abortCheckCbk) { + if (updateLevel - lastAbortCheck > 10) { + if ((*abortCheckCbk)(abortCheckCbkData)) { + break; + } + lastAbortCheck = updateLevel; + } + } + // got an argument - save it } else if (numArgs < maxArgs) { args[numArgs++] = obj; @@ -572,10 +616,11 @@ void Gfx::go(GBool topLevel) { void Gfx::execOp(Object *cmd, Object args[], int numArgs) { Operator *op; char *name; + Object *argPtr; int i; // find operator - name = cmd->getName(); + name = cmd->getCmd(); if (!(op = findOp(name))) { if (ignoreUndef == 0) error(getPos(), "Unknown operator '%s'", name); @@ -583,12 +628,19 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) { } // type check args + argPtr = args; if (op->numArgs >= 0) { - if (numArgs != op->numArgs) { - error(getPos(), "Wrong number (%d) of args to '%s' operator", - numArgs, name); + if (numArgs < op->numArgs) { + error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name); return; } + if (numArgs > op->numArgs) { +#if 0 + error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name); +#endif + argPtr += numArgs - op->numArgs; + numArgs = op->numArgs; + } } else { if (numArgs > -op->numArgs) { error(getPos(), "Too many (%d) args to '%s' operator", @@ -597,15 +649,15 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) { } } for (i = 0; i < numArgs; ++i) { - if (!checkArg(&args[i], op->tchk[i])) { + if (!checkArg(&argPtr[i], op->tchk[i])) { error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)", - i, name, args[i].getTypeName()); + i, name, argPtr[i].getTypeName()); return; } } // do it - (this->*op->func)(args, numArgs); + (this->*op->func)(argPtr, numArgs); } Operator *Gfx::findOp(char *name) { @@ -653,13 +705,11 @@ int Gfx::getPos() { //------------------------------------------------------------------------ void Gfx::opSave(Object args[], int numArgs) { - out->saveState(state); - state = state->save(); + saveState(); } void Gfx::opRestore(Object args[], int numArgs) { - state = state->restore(); - out->restoreState(state); + restoreState(); } void Gfx::opConcat(Object args[], int numArgs) { @@ -1175,18 +1225,7 @@ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { } void Gfx::doPatternFill(GBool eoFill) { - GfxPatternColorSpace *patCS; GfxPattern *pattern; - GfxTilingPattern *tPat; - GfxColorSpace *cs; - double xMin, yMin, xMax, yMax, x, y, x1, y1; - double cxMin, cyMin, cxMax, cyMax; - int xi0, yi0, xi1, yi1, xi, yi; - double *ctm, *btm, *ptm; - double m[6], ictm[6], m1[6], imb[6]; - double det; - double xstep, ystep; - int i; // this is a bit of a kludge -- patterns can be really slow, so we // skip them if we're only doing text extraction, since they almost @@ -1195,17 +1234,38 @@ void Gfx::doPatternFill(GBool eoFill) { return; } - // get color space - patCS = (GfxPatternColorSpace *)state->getFillColorSpace(); - - // get pattern if (!(pattern = state->getFillPattern())) { return; } - if (pattern->getType() != 1) { - return; + switch (pattern->getType()) { + case 1: + doTilingPatternFill((GfxTilingPattern *)pattern, eoFill); + break; + case 2: + doShadingPatternFill((GfxShadingPattern *)pattern, eoFill); + break; + default: + error(getPos(), "Unimplemented pattern type (%d) in fill", + pattern->getType()); + break; } - tPat = (GfxTilingPattern *)pattern; +} + +void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { + GfxPatternColorSpace *patCS; + GfxColorSpace *cs; + GfxPath *savedPath; + double xMin, yMin, xMax, yMax, x, y, x1, y1; + double cxMin, cyMin, cxMax, cyMax; + int xi0, yi0, xi1, yi1, xi, yi; + double *ctm, *btm, *ptm; + double m[6], ictm[6], m1[6], imb[6]; + double det; + double xstep, ystep; + int i; + + // get color space + patCS = (GfxPatternColorSpace *)state->getFillColorSpace(); // construct a (pattern space) -> (current space) transform matrix ctm = state->getCTM(); @@ -1244,17 +1304,26 @@ void Gfx::doPatternFill(GBool eoFill) { imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det; // save current graphics state - out->saveState(state); - state = state->save(); + savedPath = state->getPath()->copy(); + saveState(); - // set underlying color space (for uncolored tiling patterns) + // set underlying color space (for uncolored tiling patterns); set + // various other parameters (stroke color, line width) to match + // Adobe's behavior if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { state->setFillColorSpace(cs->copy()); + state->setStrokeColorSpace(cs->copy()); + state->setStrokeColor(state->getFillColor()); } else { state->setFillColorSpace(new GfxDeviceGrayColorSpace()); + state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); } state->setFillPattern(NULL); out->updateFillColor(state); + state->setStrokePattern(NULL); + out->updateStrokeColor(state); + state->setLineWidth(0); + out->updateLineWidth(state); // clip to current path state->clip(); @@ -1311,10 +1380,10 @@ void Gfx::doPatternFill(GBool eoFill) { //~ edge instead of left/bottom (?) xstep = fabs(tPat->getXStep()); ystep = fabs(tPat->getYStep()); - xi0 = (int)floor(xMin / xstep); - xi1 = (int)ceil(xMax / xstep); - yi0 = (int)floor(yMin / ystep); - yi1 = (int)ceil(yMax / ystep); + xi0 = (int)floor((xMin - tPat->getBBox()[0]) / xstep); + xi1 = (int)ceil((xMax - tPat->getBBox()[0]) / xstep); + yi0 = (int)floor((yMin - tPat->getBBox()[1]) / ystep); + yi1 = (int)ceil((yMax - tPat->getBBox()[1]) / ystep); for (i = 0; i < 4; ++i) { m1[i] = m[i]; } @@ -1330,12 +1399,101 @@ void Gfx::doPatternFill(GBool eoFill) { } // restore graphics state - state = state->restore(); - out->restoreState(state); + restoreState(); + state->setPath(savedPath); +} + +void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { + GfxShading *shading; + GfxPath *savedPath; + double *ctm, *btm, *ptm; + double m[6], ictm[6], m1[6]; + double xMin, yMin, xMax, yMax; + double det; + + shading = sPat->getShading(); + + // save current graphics state + savedPath = state->getPath()->copy(); + saveState(); + + // clip to bbox + if (shading->getHasBBox()) { + shading->getBBox(&xMin, &yMin, &xMax, &yMax); + state->moveTo(xMin, yMin); + state->lineTo(xMax, yMin); + state->lineTo(xMax, yMax); + state->lineTo(xMin, yMax); + state->closePath(); + state->clip(); + out->clip(state); + state->clearPath(); + } + + // clip to current path + state->clip(); + if (eoFill) { + out->eoClip(state); + } else { + out->clip(state); + } + state->clearPath(); + + // construct a (pattern space) -> (current space) transform matrix + ctm = state->getCTM(); + btm = baseMatrix; + ptm = sPat->getMatrix(); + // iCTM = invert CTM + det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); + ictm[0] = ctm[3] * det; + ictm[1] = -ctm[1] * det; + ictm[2] = -ctm[2] * det; + ictm[3] = ctm[0] * det; + ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; + ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; + // m1 = PTM * BTM = PTM * base transform matrix + m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; + m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; + m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; + m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; + m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; + m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; + // m = m1 * iCTM = (PTM * BTM) * (iCTM) + m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; + m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; + m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; + m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; + m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; + m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; + + // set the new matrix + state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]); + out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]); + + // set the color space + state->setFillColorSpace(shading->getColorSpace()->copy()); + + // do shading type-specific operations + switch (shading->getType()) { + case 1: + doFunctionShFill((GfxFunctionShading *)shading); + break; + case 2: + doAxialShFill((GfxAxialShading *)shading); + break; + case 3: + doRadialShFill((GfxRadialShading *)shading); + break; + } + + // restore graphics state + restoreState(); + state->setPath(savedPath); } void Gfx::opShFill(Object args[], int numArgs) { GfxShading *shading; + GfxPath *savedPath; double xMin, yMin, xMax, yMax; if (!(shading = res->lookupShading(args[0].getName()))) { @@ -1343,8 +1501,8 @@ void Gfx::opShFill(Object args[], int numArgs) { } // save current graphics state - out->saveState(state); - state = state->save(); + savedPath = state->getPath()->copy(); + saveState(); // clip to bbox if (shading->getHasBBox()) { @@ -1364,6 +1522,9 @@ void Gfx::opShFill(Object args[], int numArgs) { // do shading type-specific operations switch (shading->getType()) { + case 1: + doFunctionShFill((GfxFunctionShading *)shading); + break; case 2: doAxialShFill((GfxAxialShading *)shading); break; @@ -1373,12 +1534,132 @@ void Gfx::opShFill(Object args[], int numArgs) { } // restore graphics state - state = state->restore(); - out->restoreState(state); + restoreState(); + state->setPath(savedPath); delete shading; } +void Gfx::doFunctionShFill(GfxFunctionShading *shading) { + double x0, y0, x1, y1; + GfxColor colors[4]; + + shading->getDomain(&x0, &y0, &x1, &y1); + shading->getColor(x0, y0, &colors[0]); + shading->getColor(x0, y1, &colors[1]); + shading->getColor(x1, y0, &colors[2]); + shading->getColor(x1, y1, &colors[3]); + doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0); +} + +void Gfx::doFunctionShFill1(GfxFunctionShading *shading, + double x0, double y0, + double x1, double y1, + GfxColor *colors, int depth) { + GfxColor fillColor; + GfxColor color0M, color1M, colorM0, colorM1, colorMM; + GfxColor colors2[4]; + double *matrix; + double xM, yM; + int nComps, i, j; + + nComps = shading->getColorSpace()->getNComps(); + matrix = shading->getMatrix(); + + // compare the four corner colors + for (i = 0; i < 4; ++i) { + for (j = 0; j < nComps; ++j) { + if (fabs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) { + break; + } + } + if (j < nComps) { + break; + } + } + + // center of the rectangle + xM = 0.5 * (x0 + x1); + yM = 0.5 * (y0 + y1); + + // the four corner colors are close (or we hit the recursive limit) + // -- fill the rectangle; but require at least one subdivision + // (depth==0) to avoid problems when the four outer corners of the + // shaded region are the same color + if ((i == 4 && depth > 0) || depth == functionMaxDepth) { + + // use the center color + shading->getColor(xM, yM, &fillColor); + state->setFillColor(&fillColor); + out->updateFillColor(state); + + // fill the rectangle + state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4], + x0 * matrix[1] + y0 * matrix[3] + matrix[5]); + state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4], + x1 * matrix[1] + y0 * matrix[3] + matrix[5]); + state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4], + x1 * matrix[1] + y1 * matrix[3] + matrix[5]); + state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4], + x0 * matrix[1] + y1 * matrix[3] + matrix[5]); + state->closePath(); + out->fill(state); + state->clearPath(); + + // the four corner colors are not close enough -- subdivide the + // rectangle + } else { + + // colors[0] colorM0 colors[2] + // (x0,y0) (xM,y0) (x1,y0) + // +----------+----------+ + // | | | + // | UL | UR | + // color0M | colorMM | color1M + // (x0,yM) +----------+----------+ (x1,yM) + // | (xM,yM) | + // | LL | LR | + // | | | + // +----------+----------+ + // colors[1] colorM1 colors[3] + // (x0,y1) (xM,y1) (x1,y1) + + shading->getColor(x0, yM, &color0M); + shading->getColor(x1, yM, &color1M); + shading->getColor(xM, y0, &colorM0); + shading->getColor(xM, y1, &colorM1); + shading->getColor(xM, yM, &colorMM); + + // upper-left sub-rectangle + colors2[0] = colors[0]; + colors2[1] = color0M; + colors2[2] = colorM0; + colors2[3] = colorMM; + doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1); + + // lower-left sub-rectangle + colors2[0] = color0M; + colors2[1] = colors[1]; + colors2[2] = colorMM; + colors2[3] = colorM1; + doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1); + + // upper-right sub-rectangle + colors2[0] = colorM0; + colors2[1] = colorMM; + colors2[2] = colors[2]; + colors2[3] = color1M; + doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1); + + // lower-right sub-rectangle + colors2[0] = colorMM; + colors2[1] = colorM1; + colors2[2] = color1M; + colors2[3] = colors[3]; + doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1); + } +} + void Gfx::doAxialShFill(GfxAxialShading *shading) { double xMin, yMin, xMax, yMax; double x0, y0, x1, y1; @@ -1461,11 +1742,14 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { // difference across a region is small enough, and then the region // is painted with a single color. - // set up + // set up: require at least one split to avoid problems when the two + // ends of the t axis have the same color nComps = shading->getColorSpace()->getNComps(); ta[0] = tMin; + next[0] = axialMaxSplits / 2; + ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax); + next[axialMaxSplits / 2] = axialMaxSplits; ta[axialMaxSplits] = tMax; - next[0] = axialMaxSplits; // compute the color at t = tMin if (tMin < 0) { @@ -1730,7 +2014,9 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { // go as far along the t axis (toward t1) as we can, such that the // color difference is within the tolerance (radialColorDelta) -- // this uses bisection (between the current value, t, and t1), - // limited to radialMaxSplits points along the t axis + // limited to radialMaxSplits points along the t axis; require at + // least one split to avoid problems when the innermost and + // outermost colors are the same ib = radialMaxSplits; sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin); tb = t0 + sb * (t1 - t0); @@ -1747,7 +2033,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { break; } } - if (k == nComps) { + if (k == nComps && ib < radialMaxSplits) { break; } ib = (ia + ib) / 2; @@ -1806,7 +2092,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { } void Gfx::doEndPath() { - if (state->isPath() && clip != clipNone) { + if (state->isCurPt() && clip != clipNone) { state->clip(); if (clip == clipNormal) { out->clip(state); @@ -1843,6 +2129,7 @@ void Gfx::opBeginText(Object args[], int numArgs) { } void Gfx::opEndText(Object args[], int numArgs) { + out->endTextObject(state); } //------------------------------------------------------------------------ @@ -2019,7 +2306,7 @@ void Gfx::doShowText(GString *s) { double riseX, riseY; CharCode code; Unicode u[8]; - double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy; + double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY; double originX, originY, tOriginX, tOriginY; double oldCTM[6], newCTM[6]; double *mat; @@ -2057,12 +2344,16 @@ void Gfx::doShowText(GString *s) { newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2]; newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3]; newCTM[0] *= state->getFontSize(); + newCTM[1] *= state->getFontSize(); + newCTM[2] *= state->getFontSize(); newCTM[3] *= state->getFontSize(); newCTM[0] *= state->getHorizScaling(); newCTM[2] *= state->getHorizScaling(); state->textTransformDelta(0, state->getRise(), &riseX, &riseY); curX = state->getCurX(); curY = state->getCurY(); + lineX = state->getLineX(); + lineY = state->getLineY(); oldParser = parser; p = s->getCString(); len = s->getLength(); @@ -2078,11 +2369,11 @@ void Gfx::doShowText(GString *s) { dy *= state->getFontSize(); state->textTransformDelta(dx, dy, &tdx, &tdy); state->transform(curX + riseX, curY + riseY, &x, &y); - out->saveState(state); - state = state->save(); + saveState(); state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); //~ out->updateCTM(???) - if (!out->beginType3Char(state, code, u, uLen)) { + if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy, + code, u, uLen)) { ((Gfx8BitFont *)font)->getCharProc(code, &charProc); if ((resDict = ((Gfx8BitFont *)font)->getResources())) { pushResources(resDict); @@ -2098,13 +2389,13 @@ void Gfx::doShowText(GString *s) { } charProc.free(); } - state = state->restore(); - out->restoreState(state); + restoreState(); // GfxState::restore() does *not* restore the current position, - // so we track it here with (curX, curY) + // so we deal with it here using (curX, curY) and (lineX, lineY) curX += tdx; curY += tdy; state->moveTo(curX, curY); + state->textSetPos(lineX, lineY); p += n; len -= n; } @@ -2291,9 +2582,13 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj1.free(); dict->lookup("BPC", &obj1); } - if (!obj1.isInt()) + if (obj1.isInt()) { + bits = obj1.getInt(); + } else if (mask) { + bits = 1; + } else { goto err2; - bits = obj1.getInt(); + } obj1.free(); // display a mask @@ -2397,6 +2692,11 @@ void Gfx::doForm(Object *str) { Object obj1; int i; + // check for excessive recursion + if (formDepth > 20) { + return; + } + // get stream dict dict = str->streamGetDict(); @@ -2442,7 +2742,9 @@ void Gfx::doForm(Object *str) { resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; // draw it + ++formDepth; doForm1(str, resDict, m, bbox); + --formDepth; resObj.free(); } @@ -2570,8 +2872,10 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) { pushResources(resDict); // save current graphics state - out->saveState(state); - state = state->save(); + saveState(); + + // kill any pre-existing path + state->clearPath(); // save current parser oldParser = parser; @@ -2610,8 +2914,7 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) { parser = oldParser; // restore graphics state - state = state->restore(); - out->restoreState(state); + restoreState(); // pop resource stack popResources(); @@ -2619,18 +2922,6 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) { return; } -void Gfx::pushResources(Dict *resDict) { - res = new GfxResources(xref, resDict, res); -} - -void Gfx::popResources() { - GfxResources *resPtr; - - resPtr = res->getNext(); - delete res; - res = resPtr; -} - //------------------------------------------------------------------------ // in-line image operators //------------------------------------------------------------------------ @@ -2691,7 +2982,7 @@ Stream *Gfx::buildImageStream() { obj.free(); // make stream - str = new EmbedStream(parser->getStream(), &dict); + str = new EmbedStream(parser->getStream(), &dict, gFalse, 0); str = str->addFilters(&dict); return str; @@ -2758,3 +3049,29 @@ void Gfx::opMarkPoint(Object args[], int numArgs) { fflush(stdout); } } + +//------------------------------------------------------------------------ +// misc +//------------------------------------------------------------------------ + +void Gfx::saveState() { + out->saveState(state); + state = state->save(); +} + +void Gfx::restoreState() { + state = state->restore(); + out->restoreState(state); +} + +void Gfx::pushResources(Dict *resDict) { + res = new GfxResources(xref, resDict, res); +} + +void Gfx::popResources() { + GfxResources *resPtr; + + resPtr = res->getNext(); + delete res; + res = resPtr; +} diff --git a/pdf2swf/xpdf/Gfx.h b/pdf2swf/xpdf/Gfx.h index b4da531..2e40a57 100644 --- a/pdf2swf/xpdf/Gfx.h +++ b/pdf2swf/xpdf/Gfx.h @@ -2,14 +2,16 @@ // // Gfx.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GFX_H #define GFX_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -25,12 +27,16 @@ class OutputDev; class GfxFontDict; class GfxFont; class GfxPattern; +class GfxTilingPattern; +class GfxShadingPattern; class GfxShading; +class GfxFunctionShading; class GfxAxialShading; class GfxRadialShading; class GfxState; +struct GfxColor; class Gfx; -struct PDFRectangle; +class PDFRectangle; //------------------------------------------------------------------------ // Gfx @@ -94,13 +100,17 @@ class Gfx { public: // Constructor for regular output. - Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi, - PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate, - GBool printCommandsA); + Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, + double hDPI, double vDPI, PDFRectangle *box, GBool crop, + PDFRectangle *cropBox, int rotate, + GBool (*abortCheckCbkA)(void *data) = NULL, + void *abortCheckCbkDataA = NULL); // Constructor for a sub-page object. Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, GBool crop, PDFRectangle *cropBox); + PDFRectangle *box, GBool crop, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data) = NULL, + void *abortCheckCbkDataA = NULL); ~Gfx(); @@ -112,8 +122,11 @@ public: void doAnnot(Object *str, double xMin, double yMin, double xMax, double yMax); - void pushResources(Dict *resDict); - void popResources(); + // Save graphics state. + void saveState(); + + // Restore graphics state. + void restoreState(); private: @@ -130,9 +143,14 @@ private: int ignoreUndef; // current BX/EX nesting level double baseMatrix[6]; // default matrix for most recent // page/form/pattern + int formDepth; Parser *parser; // parser for page content stream(s) + GBool // callback to check for an abort + (*abortCheckCbk)(void *data); + void *abortCheckCbkData; + static Operator opTab[]; // table of operators void go(GBool topLevel); @@ -188,7 +206,14 @@ private: void opEOFillStroke(Object args[], int numArgs); void opCloseEOFillStroke(Object args[], int numArgs); void doPatternFill(GBool eoFill); + void doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill); + void doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill); void opShFill(Object args[], int numArgs); + void doFunctionShFill(GfxFunctionShading *shading); + void doFunctionShFill1(GfxFunctionShading *shading, + double x0, double y0, + double x1, double y1, + GfxColor *colors, int depth); void doAxialShFill(GfxAxialShading *shading); void doRadialShFill(GfxRadialShading *shading); void doEndPath(); @@ -247,6 +272,9 @@ private: void opBeginMarkedContent(Object args[], int numArgs); void opEndMarkedContent(Object args[], int numArgs); void opMarkPoint(Object args[], int numArgs); + + void pushResources(Dict *resDict); + void popResources(); }; #endif diff --git a/pdf2swf/xpdf/GfxFont.cc b/pdf2swf/xpdf/GfxFont.cc index 8dcd8e7..ed9f076 100644 --- a/pdf2swf/xpdf/GfxFont.cc +++ b/pdf2swf/xpdf/GfxFont.cc @@ -2,15 +2,16 @@ // // GfxFont.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -24,7 +25,9 @@ #include "CharCodeToUnicode.h" #include "FontEncodingTables.h" #include "BuiltinFontTables.h" -#include "FontFile.h" +#include "FoFiType1.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" #include "GfxFont.h" //------------------------------------------------------------------------ @@ -34,6 +37,11 @@ struct StdFontMapEntry { char *properName; }; +// Acrobat 4.0 and earlier substituted Base14-compatible fonts without +// providing Widths and a FontDescriptor, so we munge the names into +// the proper Base14 names. This table is from implementation note 44 +// in the PDF 1.4 spec, with some additions based on empirical +// evidence. static StdFontMapEntry stdFontMap[] = { { "Arial", "Helvetica" }, { "Arial,Bold", "Helvetica-Bold" }, @@ -65,6 +73,9 @@ static StdFontMapEntry stdFontMap[] = { { "Helvetica,Italic", "Helvetica-Oblique" }, { "Helvetica-BoldItalic", "Helvetica-BoldOblique" }, { "Helvetica-Italic", "Helvetica-Oblique" }, + { "Symbol,Bold", "Symbol" }, + { "Symbol,BoldItalic", "Symbol" }, + { "Symbol,Italic", "Symbol" }, { "TimesNewRoman", "Times-Roman" }, { "TimesNewRoman,Bold", "Times-Bold" }, { "TimesNewRoman,BoldItalic", "Times-BoldItalic" }, @@ -79,7 +90,10 @@ static StdFontMapEntry stdFontMap[] = { { "TimesNewRomanPS-BoldMT", "Times-Bold" }, { "TimesNewRomanPS-Italic", "Times-Italic" }, { "TimesNewRomanPS-ItalicMT", "Times-Italic" }, - { "TimesNewRomanPSMT", "Times-Roman" } + { "TimesNewRomanPSMT", "Times-Roman" }, + { "TimesNewRomanPSMT,Bold", "Times-Bold" }, + { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" }, + { "TimesNewRomanPSMT,Italic", "Times-Italic" } }; //------------------------------------------------------------------------ @@ -127,12 +141,16 @@ GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) { tag = new GString(tagA); id = idA; name = nameA; + origName = nameA; embFontName = NULL; extFontFile = NULL; } GfxFont::~GfxFont() { delete tag; + if (origName && origName != name) { + delete origName; + } if (name) { delete name; } @@ -255,6 +273,10 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { if (t != 0) { descent = t; } + // some broken font descriptors specify a positive descent + if (descent > 0) { + descent = -descent; + } } obj2.free(); @@ -273,8 +295,8 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { obj1.free(); } -CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits) { - CharCodeToUnicode *ctu; +CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, + CharCodeToUnicode *ctu) { GString *buf; Object obj1; int c; @@ -290,17 +312,24 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits) { } obj1.streamClose(); obj1.free(); - ctu = CharCodeToUnicode::parseCMap(buf, nBits); + if (ctu) { + ctu->mergeCMap(buf, nBits); + } else { + ctu = CharCodeToUnicode::parseCMap(buf, nBits); + } delete buf; return ctu; } void GfxFont::findExtFontFile() { + static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL }; + static char *ttExts[] = { ".ttf", NULL }; + if (name) { if (type == fontType1) { - extFontFile = globalParams->findFontFile(name, ".pfa", ".pfb"); + extFontFile = globalParams->findFontFile(name, type1Exts); } else if (type == fontTrueType) { - extFontFile = globalParams->findFontFile(name, ".ttf", NULL); + extFontFile = globalParams->findFontFile(name, ttExts); } } } @@ -318,7 +347,8 @@ char *GfxFont::readExtFontFile(int *len) { fseek(f, 0, SEEK_SET); buf = (char *)gmalloc(*len); if ((int)fread(buf, 1, *len, f) != *len) { - error(-1, "Error reading external font file '%s'", extFontFile); + error(-1, "Error reading external font file '%s'", + extFontFile->getCString()); } fclose(f); return buf; @@ -374,11 +404,14 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GBool baseEncFromFontFile; char *buf; int len; - FontFile *fontFile; + FoFiType1 *ffT1; + FoFiType1C *ffT1C; int code, code2; char *charName; GBool missing, hex; Unicode toUnicode[256]; + CharCodeToUnicode *utu, *ctu2; + Unicode uBuf[8]; double mul; int firstChar, lastChar; Gushort w; @@ -388,10 +421,8 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, type = typeA; ctu = NULL; - // Acrobat 4.0 and earlier substituted Base14-compatible fonts - // without providing Widths and a FontDescriptor, so we munge the - // names into the proper Base14 names. (This table is from - // implementation note 44 in the PDF 1.4 spec.) + // do font name substitution for various aliases of the Base 14 font + // names if (name) { a = 0; b = sizeof(stdFontMap) / sizeof(StdFontMapEntry); @@ -405,7 +436,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } } if (!name->cmp(stdFontMap[a].altName)) { - delete name; name = new GString(stdFontMap[a].properName); } } @@ -490,6 +520,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // check FontDict for base encoding hasEncoding = gFalse; + usesMacRomanEnc = gFalse; baseEnc = NULL; baseEncFromFontFile = gFalse; fontDict->lookup("Encoding", &obj1); @@ -497,6 +528,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj1.dictLookup("BaseEncoding", &obj2); if (obj2.isName("MacRomanEncoding")) { hasEncoding = gTrue; + usesMacRomanEnc = gTrue; baseEnc = macRomanEncoding; } else if (obj2.isName("MacExpertEncoding")) { hasEncoding = gTrue; @@ -511,6 +543,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj2.free(); } else if (obj1.isName("MacRomanEncoding")) { hasEncoding = gTrue; + usesMacRomanEnc = gTrue; baseEnc = macRomanEncoding; } else if (obj1.isName("MacExpertEncoding")) { hasEncoding = gTrue; @@ -526,46 +559,59 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // check embedded or external font file for base encoding // (only for Type 1 fonts - trying to get an encoding out of a // TrueType font is a losing proposition) - fontFile = NULL; + ffT1 = NULL; + ffT1C = NULL; buf = NULL; - if ((type == fontType1 || type == fontType1C) && - (extFontFile || embFontID.num >= 0)) { + if (type == fontType1 && (extFontFile || embFontID.num >= 0)) { if (extFontFile) { - buf = readExtFontFile(&len); + ffT1 = FoFiType1::load(extFontFile->getCString()); } else { buf = readEmbFontFile(xref, &len); + ffT1 = FoFiType1::make(buf, len); } - if (buf) { - if (type == fontType1C && !strncmp(buf, "%!", 2)) { - // various tools (including Adobe's) occasionally embed Type 1 - // fonts but label them Type 1C - type = fontType1; + if (ffT1) { + if (ffT1->getName()) { + if (embFontName) { + delete embFontName; + } + embFontName = new GString(ffT1->getName()); } - if (type == fontType1) { - fontFile = new Type1FontFile(buf, len); - } else { - fontFile = new Type1CFontFile(buf, len); + if (!baseEnc) { + baseEnc = ffT1->getEncoding(); + baseEncFromFontFile = gTrue; } - if (fontFile->getName()) { + } + } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) { + if (extFontFile) { + ffT1C = FoFiType1C::load(extFontFile->getCString()); + } else { + buf = readEmbFontFile(xref, &len); + ffT1C = FoFiType1C::make(buf, len); + } + if (ffT1C) { + if (ffT1C->getName()) { if (embFontName) { delete embFontName; } - embFontName = new GString(fontFile->getName()); + embFontName = new GString(ffT1C->getName()); } if (!baseEnc) { - baseEnc = fontFile->getEncoding(); + baseEnc = ffT1C->getEncoding(); baseEncFromFontFile = gTrue; } - gfree(buf); } } + if (buf) { + gfree(buf); + } // get default base encoding if (!baseEnc) { if (builtinFont) { baseEnc = builtinFont->defaultBaseEnc; + hasEncoding = gTrue; } else if (type == fontTrueType) { - baseEnc = macRomanEncoding; + baseEnc = winAnsiEncoding; } else { baseEnc = standardEncoding; } @@ -579,6 +625,20 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } } + // some Type 1C font files have empty encodings, which can break the + // T1C->T1 conversion (since the 'seac' operator depends on having + // the accents in the encoding), so we fill in any gaps from + // StandardEncoding + if (type == fontType1C && (extFontFile || embFontID.num >= 0) && + baseEncFromFontFile) { + for (i = 0; i < 256; ++i) { + if (!enc[i] && standardEncoding[i]) { + enc[i] = standardEncoding[i]; + encFree[i] = gFalse; + } + } + } + // merge differences into encoding if (obj1.isDict()) { obj1.dictLookup("Differences", &obj2); @@ -590,7 +650,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, if (obj3.isInt()) { code = obj3.getInt(); } else if (obj3.isName()) { - if (code < 256) { + if (code >= 0 && code < 256) { if (encFree[code]) { gfree(enc[code]); } @@ -608,82 +668,106 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj2.free(); } obj1.free(); - if (fontFile) { - delete fontFile; + if (ffT1) { + delete ffT1; + } + if (ffT1C) { + delete ffT1C; } //----- build the mapping to Unicode ----- - // look for a ToUnicode CMap - if (!(ctu = readToUnicodeCMap(fontDict, 8))) { - - // no ToUnicode CMap, so use the char names + // pass 1: use the name-to-Unicode mapping table + missing = hex = gFalse; + for (code = 0; code < 256; ++code) { + if ((charName = enc[code])) { + if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) && + strcmp(charName, ".notdef")) { + // if it wasn't in the name-to-Unicode table, check for a + // name that looks like 'Axx' or 'xx', where 'A' is any letter + // and 'xx' is two hex digits + if ((strlen(charName) == 3 && + isalpha(charName[0]) && + isxdigit(charName[1]) && isxdigit(charName[2]) && + ((charName[1] >= 'a' && charName[1] <= 'f') || + (charName[1] >= 'A' && charName[1] <= 'F') || + (charName[2] >= 'a' && charName[2] <= 'f') || + (charName[2] >= 'A' && charName[2] <= 'F'))) || + (strlen(charName) == 2 && + isxdigit(charName[0]) && isxdigit(charName[1]) && + ((charName[0] >= 'a' && charName[0] <= 'f') || + (charName[0] >= 'A' && charName[0] <= 'F') || + (charName[1] >= 'a' && charName[1] <= 'f') || + (charName[1] >= 'A' && charName[1] <= 'F')))) { + hex = gTrue; + } + missing = gTrue; + } + } else { + toUnicode[code] = 0; + } + } - // pass 1: use the name-to-Unicode mapping table - missing = hex = gFalse; + // pass 2: try to fill in the missing chars, looking for names of + // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B' + // are any letters, 'xx' is two hex digits, and 'nn' is 2-4 + // decimal digits + if (missing && globalParams->getMapNumericCharNames()) { for (code = 0; code < 256; ++code) { - if ((charName = enc[code])) { - if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) && - strcmp(charName, ".notdef")) { - // if it wasn't in the name-to-Unicode table, check for a - // name that looks like 'Axx' or 'xx', where 'A' is any letter - // and 'xx' is two hex digits - if ((strlen(charName) == 3 && - isalpha(charName[0]) && - isxdigit(charName[1]) && isxdigit(charName[2]) && - ((charName[1] >= 'a' && charName[1] <= 'f') || - (charName[1] >= 'A' && charName[1] <= 'F') || - (charName[2] >= 'a' && charName[2] <= 'f') || - (charName[2] >= 'A' && charName[2] <= 'F'))) || - (strlen(charName) == 2 && - isxdigit(charName[0]) && isxdigit(charName[1]) && - ((charName[0] >= 'a' && charName[0] <= 'f') || - (charName[0] >= 'A' && charName[0] <= 'F') || - (charName[1] >= 'a' && charName[1] <= 'f') || - (charName[1] >= 'A' && charName[1] <= 'F')))) { - hex = gTrue; - } - missing = gTrue; + if ((charName = enc[code]) && !toUnicode[code] && + strcmp(charName, ".notdef")) { + n = strlen(charName); + code2 = -1; + if (hex && n == 3 && isalpha(charName[0]) && + isxdigit(charName[1]) && isxdigit(charName[2])) { + sscanf(charName+1, "%x", &code2); + } else if (hex && n == 2 && + isxdigit(charName[0]) && isxdigit(charName[1])) { + sscanf(charName, "%x", &code2); + } else if (!hex && n >= 2 && n <= 4 && + isdigit(charName[0]) && isdigit(charName[1])) { + code2 = atoi(charName); + } else if (n >= 3 && n <= 5 && + isdigit(charName[1]) && isdigit(charName[2])) { + code2 = atoi(charName+1); + } else if (n >= 4 && n <= 6 && + isdigit(charName[2]) && isdigit(charName[3])) { + code2 = atoi(charName+2); + } + if (code2 >= 0 && code2 <= 0xff) { + toUnicode[code] = (Unicode)code2; } - } else { - toUnicode[code] = 0; } } + } - // pass 2: try to fill in the missing chars, looking for names of - // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B' - // are any letters, 'xx' is two hex digits, and 'nn' is 2-4 - // decimal digits - if (missing && globalParams->getMapNumericCharNames()) { - for (code = 0; code < 256; ++code) { - if ((charName = enc[code]) && !toUnicode[code] && - strcmp(charName, ".notdef")) { - n = strlen(charName); - code2 = -1; - if (hex && n == 3 && isalpha(charName[0]) && - isxdigit(charName[1]) && isxdigit(charName[2])) { - sscanf(charName+1, "%x", &code2); - } else if (hex && n == 2 && - isxdigit(charName[0]) && isxdigit(charName[1])) { - sscanf(charName, "%x", &code2); - } else if (!hex && n >= 2 && n <= 4 && - isdigit(charName[0]) && isdigit(charName[1])) { - code2 = atoi(charName); - } else if (n >= 3 && n <= 5 && - isdigit(charName[1]) && isdigit(charName[2])) { - code2 = atoi(charName+1); - } else if (n >= 4 && n <= 6 && - isdigit(charName[2]) && isdigit(charName[3])) { - code2 = atoi(charName+2); - } - if (code2 >= 0 && code2 <= 0xff) { - toUnicode[code] = (Unicode)code2; - } + // construct the char code -> Unicode mapping object + ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode); + + // merge in a ToUnicode CMap, if there is one -- this overwrites + // existing entries in ctu, i.e., the ToUnicode CMap takes + // precedence, but the other encoding info is allowed to fill in any + // holes + readToUnicodeCMap(fontDict, 8, ctu); + + // look for a Unicode-to-Unicode mapping + if (name && (utu = globalParams->getUnicodeToUnicode(name))) { + for (i = 0; i < 256; ++i) { + toUnicode[i] = 0; + } + ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode); + for (i = 0; i < 256; ++i) { + n = ctu->mapToUnicode((CharCode)i, uBuf, 8); + if (n >= 1) { + n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (n >= 1) { + ctu2->setMapping((CharCode)i, uBuf, n); } } } - - ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode); + utu->decRefCnt(); + delete ctu; + ctu = ctu2; } //----- get the character widths ----- @@ -697,13 +781,22 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, fontDict->lookup("FirstChar", &obj1); firstChar = obj1.isInt() ? obj1.getInt() : 0; obj1.free(); + if (firstChar < 0 || firstChar > 255) { + firstChar = 0; + } fontDict->lookup("LastChar", &obj1); lastChar = obj1.isInt() ? obj1.getInt() : 255; obj1.free(); + if (lastChar < 0 || lastChar > 255) { + lastChar = 255; + } mul = (type == fontType3) ? fontMat[0] : 0.001; fontDict->lookup("Widths", &obj1); if (obj1.isArray()) { flags |= fontFixedWidth; + if (obj1.arrayGetLength() < lastChar - firstChar + 1) { + lastChar = firstChar + obj1.arrayGetLength() - 1; + } for (code = firstChar; code <= lastChar; ++code) { obj1.arrayGet(code - firstChar, &obj2); if (obj2.isNum()) { @@ -797,12 +890,126 @@ CharCodeToUnicode *Gfx8BitFont::getToUnicode() { return ctu; } +Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { + Gushort *map; + int cmapPlatform, cmapEncoding; + int unicodeCmap, macRomanCmap, msSymbolCmap, cmap; + GBool useMacRoman, useUnicode; + char *charName; + Unicode u; + int code, i, n; + + map = (Gushort *)gmalloc(256 * sizeof(Gushort)); + for (i = 0; i < 256; ++i) { + map[i] = 0; + } + + // To match up with the Adobe-defined behaviour, we choose a cmap + // like this: + // 1. If the PDF font has an encoding: + // 1a. If the PDF font specified MacRomanEncoding and the + // TrueType font has a Macintosh Roman cmap, use it, and + // reverse map the char names through MacRomanEncoding to + // get char codes. + // 1b. If the TrueType font has a Microsoft Unicode cmap or a + // non-Microsoft Unicode cmap, use it, and use the Unicode + // indexes, not the char codes. + // 1c. If the PDF font is symbolic and the TrueType font has a + // Microsoft Symbol cmap, use it, and use char codes + // directly (possibly with an offset of 0xf000). + // 1d. If the TrueType font has a Macintosh Roman cmap, use it, + // as in case 1a. + // 2. If the PDF font does not have an encoding: + // 2a. If the TrueType font has a Macintosh Roman cmap, use it, + // and use char codes directly (possibly with an offset of + // 0xf000). + // 2b. If the TrueType font has a Microsoft Symbol cmap, use it, + // and use char codes directly (possible with an offset of + // 0xf000). + // 3. If none of these rules apply, use the first cmap and hope for + // the best (this shouldn't happen). + unicodeCmap = macRomanCmap = msSymbolCmap = -1; + for (i = 0; i < ff->getNumCmaps(); ++i) { + cmapPlatform = ff->getCmapPlatform(i); + cmapEncoding = ff->getCmapEncoding(i); + if ((cmapPlatform == 3 && cmapEncoding == 1) || + cmapPlatform == 0) { + unicodeCmap = i; + } else if (cmapPlatform == 1 && cmapEncoding == 0) { + macRomanCmap = i; + } else if (cmapPlatform == 3 && cmapEncoding == 0) { + msSymbolCmap = i; + } + } + cmap = 0; + useMacRoman = gFalse; + useUnicode = gFalse; + if (hasEncoding) { + if (usesMacRomanEnc && macRomanCmap >= 0) { + cmap = macRomanCmap; + useMacRoman = gTrue; + } else if (unicodeCmap >= 0) { + cmap = unicodeCmap; + useUnicode = gTrue; + } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { + cmap = msSymbolCmap; + } else if (macRomanCmap >= 0) { + cmap = macRomanCmap; + useMacRoman = gTrue; + } + } else { + if (macRomanCmap >= 0) { + cmap = macRomanCmap; + } else if (msSymbolCmap >= 0) { + cmap = msSymbolCmap; + } + } + + // reverse map the char names through MacRomanEncoding, then map the + // char codes through the cmap + if (useMacRoman) { + for (i = 0; i < 256; ++i) { + if ((charName = enc[i])) { + if ((code = globalParams->getMacRomanCharCode(charName))) { + map[i] = ff->mapCodeToGID(cmap, code); + } + } + } + + // map Unicode through the cmap + } else if (useUnicode) { + for (i = 0; i < 256; ++i) { + if ((n = ctu->mapToUnicode((CharCode)i, &u, 1))) { + map[i] = ff->mapCodeToGID(cmap, u); + } + } + + // map the char codes through the cmap, possibly with an offset of + // 0xf000 + } else { + for (i = 0; i < 256; ++i) { + if (!(map[i] = ff->mapCodeToGID(cmap, i))) { + map[i] = ff->mapCodeToGID(cmap, 0xf000 + i); + } + } + } + + // try the TrueType 'post' table to handle any unmapped characters + for (i = 0; i < 256; ++i) { + if (!map[i] && (charName = enc[i])) { + map[i] = (Gushort)(int)ff->mapNameToGID(charName); + } + } + + return map; +} + Dict *Gfx8BitFont::getCharProcs() { return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL; } Object *Gfx8BitFont::getCharProc(int code, Object *proc) { - if (charProcs.isDict()) { + if (enc[code] && charProcs.isDict()) { charProcs.dictLookup(enc[code], proc); } else { proc->initNull(); @@ -818,12 +1025,12 @@ Dict *Gfx8BitFont::getResources() { // GfxCIDFont //------------------------------------------------------------------------ -static int cmpWidthExcep(const void *w1, const void *w2) { +static int CDECL cmpWidthExcep(const void *w1, const void *w2) { return ((GfxFontCIDWidthExcep *)w1)->first - ((GfxFontCIDWidthExcep *)w2)->first; } -static int cmpWidthExcepV(const void *w1, const void *w2) { +static int CDECL cmpWidthExcepV(const void *w1, const void *w2) { return ((GfxFontCIDWidthExcepV *)w1)->first - ((GfxFontCIDWidthExcepV *)w2)->first; } @@ -908,7 +1115,7 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj1.free(); // look for a ToUnicode CMap - if (!(ctu = readToUnicodeCMap(fontDict, 16))) { + if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) { // the "Adobe-Identity" and "Adobe-UCS" collections don't have // cidToUnicode files @@ -947,7 +1154,7 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // CIDToGIDMap (for embedded TrueType fonts) if (type == fontCIDType2) { - fontDict->lookup("CIDToGIDMap", &obj1); + desFontDict->lookup("CIDToGIDMap", &obj1); if (obj1.isStream()) { cidToGIDLen = 0; i = 64; @@ -1036,11 +1243,11 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, if (desFontDict->lookup("DW2", &obj1)->isArray() && obj1.arrayGetLength() == 2) { if (obj1.arrayGet(0, &obj2)->isNum()) { - widths.defVY = obj1.getNum() * 0.001; + widths.defVY = obj2.getNum() * 0.001; } obj2.free(); if (obj1.arrayGet(1, &obj2)->isNum()) { - widths.defHeight = obj1.getNum() * 0.001; + widths.defHeight = obj2.getNum() * 0.001; } obj2.free(); } @@ -1051,8 +1258,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, excepsSize = 0; i = 0; while (i + 1 < obj1.arrayGetLength()) { - obj1.arrayGet(0, &obj2); - obj2.arrayGet(0, &obj3); + obj1.arrayGet(i, &obj2); + obj1.arrayGet(i+ 1, &obj3); if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) { if (obj1.arrayGet(i + 2, &obj4)->isNum() && obj1.arrayGet(i + 3, &obj5)->isNum() && @@ -1085,10 +1292,10 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, excepsSize * sizeof(GfxFontCIDWidthExcepV)); } j = obj2.getInt(); - for (k = 0; k < obj3.arrayGetLength(); ++k) { + for (k = 0; k < obj3.arrayGetLength(); k += 3) { if (obj3.arrayGet(k, &obj4)->isNum() && - obj3.arrayGet(k, &obj5)->isNum() && - obj3.arrayGet(k, &obj6)->isNum()) { + obj3.arrayGet(k+1, &obj5)->isNum() && + obj3.arrayGet(k+2, &obj6)->isNum()) { widths.excepsV[widths.nExceps].first = j; widths.excepsV[widths.nExceps].last = j; widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001; @@ -1225,7 +1432,9 @@ int GfxCIDFont::getWMode() { } CharCodeToUnicode *GfxCIDFont::getToUnicode() { - ctu->incRefCnt(); + if (ctu) { + ctu->incRefCnt(); + } return ctu; } @@ -1237,24 +1446,38 @@ GString *GfxCIDFont::getCollection() { // GfxFontDict //------------------------------------------------------------------------ -GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) { +GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { int i; Object obj1, obj2; + Ref r; numFonts = fontDict->getLength(); fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *)); for (i = 0; i < numFonts; ++i) { fontDict->getValNF(i, &obj1); obj1.fetch(xref, &obj2); - if (obj1.isRef() && obj2.isDict()) { + if (obj2.isDict()) { + if (obj1.isRef()) { + r = obj1.getRef(); + } else { + // no indirect reference for this font, so invent a unique one + // (legal generation numbers are five digits, so any 6-digit + // number would be safe) + r.num = i; + if (fontDictRef) { + r.gen = 100000 + fontDictRef->num; + } else { + r.gen = 999999; + } + } fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i), - obj1.getRef(), obj2.getDict()); + r, obj2.getDict()); if (fonts[i] && !fonts[i]->isOk()) { delete fonts[i]; fonts[i] = NULL; } } else { - error(-1, "font resource is not a dictionary reference"); + error(-1, "font resource is not a dictionary"); fonts[i] = NULL; } obj1.free(); diff --git a/pdf2swf/xpdf/GfxFont.h b/pdf2swf/xpdf/GfxFont.h index edd26e5..62dfd08 100644 --- a/pdf2swf/xpdf/GfxFont.h +++ b/pdf2swf/xpdf/GfxFont.h @@ -2,14 +2,16 @@ // // GfxFont.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GFXFONT_H #define GFXFONT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -21,6 +23,7 @@ class Dict; class CMap; class CharCodeToUnicode; +class FoFiTrueType; struct GfxFontCIDWidths; //------------------------------------------------------------------------ @@ -102,6 +105,10 @@ public: // Get base font name. GString *getName() { return name; } + // Get the original font name (ignornig any munging that might have + // been done to map to a canonical Base-14 font name). + GString *getOrigName() { return origName; } + // Get font type. GfxFontType getType() { return type; } virtual GBool isCIDFont() { return gFalse; } @@ -156,12 +163,14 @@ public: protected: void readFontDescriptor(XRef *xref, Dict *fontDict); - CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits); + CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits, + CharCodeToUnicode *ctu); void findExtFontFile(); GString *tag; // PDF font tag Ref id; // reference (used as unique ID) GString *name; // font name + GString *origName; // original font name GfxFontType type; // type of font int flags; // font descriptor flags GString *embFontName; // name of embedded font @@ -198,14 +207,21 @@ public: CharCodeToUnicode *getToUnicode(); // Return the character name associated with . - char *getCharName(int code) { return code>=256?0:enc[code]; } + char *getCharName(int code) { return enc[code]; } // Returns true if the PDF font specified an encoding. GBool getHasEncoding() { return hasEncoding; } - // Get width of a character or string. + // Returns true if the PDF font specified MacRomanEncoding. + GBool getUsesMacRomanEnc() { return usesMacRomanEnc; } + + // Get width of a character. double getWidth(Guchar c) { return widths[c]; } + // Return a char code-to-GID mapping for the provided font file. + // (This is only useful for TrueType fonts.) + Gushort *getCodeToGIDMap(FoFiTrueType *ff); + // Return the Type 3 CharProc dictionary, or NULL if none. Dict *getCharProcs(); @@ -222,6 +238,7 @@ private: // the string is malloc'ed CharCodeToUnicode *ctu; // char code --> Unicode GBool hasEncoding; + GBool usesMacRomanEnc; double widths[256]; // character widths Object charProcs; // Type 3 CharProcs dictionary Object resources; // Type 3 Resources dictionary @@ -277,7 +294,7 @@ class GfxFontDict { public: // Build the font dictionary, given the PDF font dictionary. - GfxFontDict(XRef *xref, Dict *fontDict); + GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict); // Destructor. ~GfxFontDict(); diff --git a/pdf2swf/xpdf/GfxState.cc b/pdf2swf/xpdf/GfxState.cc index d65bbba..65a1da8 100644 --- a/pdf2swf/xpdf/GfxState.cc +++ b/pdf2swf/xpdf/GfxState.cc @@ -2,15 +2,16 @@ // // GfxState.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include // for memcpy() @@ -28,6 +29,24 @@ static inline double clip01(double x) { } //------------------------------------------------------------------------ + +static char *gfxColorSpaceModeNames[] = { + "DeviceGray", + "CalGray", + "DeviceRGB", + "CalRGB", + "DeviceCMYK", + "Lab", + "ICCBased", + "Indexed", + "Separation", + "DeviceN", + "Pattern" +}; + +#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *))) + +//------------------------------------------------------------------------ // GfxColorSpace //------------------------------------------------------------------------ @@ -79,7 +98,7 @@ GfxColorSpace *GfxColorSpace::parse(Object *csObj) { } else if (obj1.isName("Pattern")) { cs = GfxPatternColorSpace::parse(csObj->getArray()); } else { - error(-1, "Bad color space '%s'", csObj->getName()); + error(-1, "Bad color space"); } obj1.free(); } else { @@ -98,6 +117,14 @@ void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, } } +int GfxColorSpace::getNumColorSpaceModes() { + return nGfxColorSpaceModes; +} + +char *GfxColorSpace::getColorSpaceModeName(int idx) { + return gfxColorSpaceModeNames[idx]; +} + //------------------------------------------------------------------------ // GfxDeviceGrayColorSpace //------------------------------------------------------------------------ @@ -733,12 +760,18 @@ void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel) { + alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel); + +#if 0 + // this is nominally correct, but some PDF files don't set the + // correct ranges in the ICCBased dict int i; for (i = 0; i < nComps; ++i) { decodeLow[i] = rangeMin[i]; decodeRange[i] = rangeMax[i] - rangeMin[i]; } +#endif } //------------------------------------------------------------------------ @@ -788,9 +821,19 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { obj1.free(); if (!arr->get(2, &obj1)->isInt()) { error(-1, "Bad Indexed color space (hival)"); + delete baseA; goto err2; } indexHighA = obj1.getInt(); + if (indexHighA < 0 || indexHighA > 255) { + // the PDF spec requires indexHigh to be in [0,255] -- allowing + // values larger than 255 creates a security hole: if nComps * + // indexHigh is greater than 2^31, the loop below may overwrite + // past the end of the array + error(-1, "Bad Indexed color space (invalid indexHigh value)"); + delete baseA; + goto err2; + } obj1.free(); cs = new GfxIndexedColorSpace(baseA, indexHighA); arr->get(3, &obj1); @@ -833,43 +876,37 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { return NULL; } -void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) { +GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color, + GfxColor *baseColor) { Guchar *p; - GfxColor color2; + double low[gfxColorMaxComps], range[gfxColorMaxComps]; int n, i; n = base->getNComps(); + base->getDefaultRanges(low, range, indexHigh); p = &lookup[(int)(color->c[0] + 0.5) * n]; for (i = 0; i < n; ++i) { - color2.c[i] = p[i] / 255.0; + baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i]; } - base->getGray(&color2, gray); + return baseColor; +} + +void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) { + GfxColor color2; + + base->getGray(mapColorToBase(color, &color2), gray); } void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - Guchar *p; GfxColor color2; - int n, i; - n = base->getNComps(); - p = &lookup[(int)(color->c[0] + 0.5) * n]; - for (i = 0; i < n; ++i) { - color2.c[i] = p[i] / 255.0; - } - base->getRGB(&color2, rgb); + base->getRGB(mapColorToBase(color, &color2), rgb); } void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - Guchar *p; GfxColor color2; - int n, i; - n = base->getNComps(); - p = &lookup[(int)(color->c[0] + 0.5) * n]; - for (i = 0; i < n; ++i) { - color2.c[i] = p[i] / 255.0; - } - base->getCMYK(&color2, cmyk); + base->getCMYK(mapColorToBase(color, &color2), cmyk); } void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow, @@ -1016,6 +1053,11 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { goto err2; } nCompsA = obj1.arrayGetLength(); + if (nCompsA > gfxColorMaxComps) { + error(-1, "DeviceN color space with more than %d > %d components", + nCompsA, gfxColorMaxComps); + nCompsA = gfxColorMaxComps; + } for (i = 0; i < nCompsA; ++i) { if (!obj1.arrayGet(i, &obj2)->isName()) { error(-1, "Bad DeviceN color space (names)"); @@ -1144,18 +1186,22 @@ GfxPattern::~GfxPattern() { GfxPattern *GfxPattern::parse(Object *obj) { GfxPattern *pattern; - Dict *dict; Object obj1; + if (obj->isDict()) { + obj->dictLookup("PatternType", &obj1); + } else if (obj->isStream()) { + obj->streamGetDict()->lookup("PatternType", &obj1); + } else { + return NULL; + } pattern = NULL; - if (obj->isStream()) { - dict = obj->streamGetDict(); - dict->lookup("PatternType", &obj1); - if (obj1.isInt() && obj1.getInt() == 1) { - pattern = new GfxTilingPattern(dict, obj); - } - obj1.free(); + if (obj1.isInt() && obj1.getInt() == 1) { + pattern = GfxTilingPattern::parse(obj); + } else if (obj1.isInt() && obj1.getInt() == 2) { + pattern = GfxShadingPattern::parse(obj); } + obj1.free(); return pattern; } @@ -1163,33 +1209,42 @@ GfxPattern *GfxPattern::parse(Object *obj) { // GfxTilingPattern //------------------------------------------------------------------------ -GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream): - GfxPattern(1) -{ +GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) { + GfxTilingPattern *pat; + Dict *dict; + int paintTypeA, tilingTypeA; + double bboxA[4], matrixA[6]; + double xStepA, yStepA; + Object resDictA; Object obj1, obj2; int i; - if (streamDict->lookup("PaintType", &obj1)->isInt()) { - paintType = obj1.getInt(); + if (!patObj->isStream()) { + return NULL; + } + dict = patObj->streamGetDict(); + + if (dict->lookup("PaintType", &obj1)->isInt()) { + paintTypeA = obj1.getInt(); } else { - paintType = 1; + paintTypeA = 1; error(-1, "Invalid or missing PaintType in pattern"); } obj1.free(); - if (streamDict->lookup("TilingType", &obj1)->isInt()) { - tilingType = obj1.getInt(); + if (dict->lookup("TilingType", &obj1)->isInt()) { + tilingTypeA = obj1.getInt(); } else { - tilingType = 1; + tilingTypeA = 1; error(-1, "Invalid or missing TilingType in pattern"); } obj1.free(); - bbox[0] = bbox[1] = 0; - bbox[2] = bbox[3] = 1; - if (streamDict->lookup("BBox", &obj1)->isArray() && + bboxA[0] = bboxA[1] = 0; + bboxA[2] = bboxA[3] = 1; + if (dict->lookup("BBox", &obj1)->isArray() && obj1.arrayGetLength() == 4) { for (i = 0; i < 4; ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { - bbox[i] = obj2.getNum(); + bboxA[i] = obj2.getNum(); } obj2.free(); } @@ -1197,39 +1252,65 @@ GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream): error(-1, "Invalid or missing BBox in pattern"); } obj1.free(); - if (streamDict->lookup("XStep", &obj1)->isNum()) { - xStep = obj1.getNum(); + if (dict->lookup("XStep", &obj1)->isNum()) { + xStepA = obj1.getNum(); } else { - xStep = 1; + xStepA = 1; error(-1, "Invalid or missing XStep in pattern"); } obj1.free(); - if (streamDict->lookup("YStep", &obj1)->isNum()) { - yStep = obj1.getNum(); + if (dict->lookup("YStep", &obj1)->isNum()) { + yStepA = obj1.getNum(); } else { - yStep = 1; + yStepA = 1; error(-1, "Invalid or missing YStep in pattern"); } obj1.free(); - if (!streamDict->lookup("Resources", &resDict)->isDict()) { - resDict.free(); - resDict.initNull(); + if (!dict->lookup("Resources", &resDictA)->isDict()) { + resDictA.free(); + resDictA.initNull(); error(-1, "Invalid or missing Resources in pattern"); } - matrix[0] = 1; matrix[1] = 0; - matrix[2] = 0; matrix[3] = 1; - matrix[4] = 0; matrix[5] = 0; - if (streamDict->lookup("Matrix", &obj1)->isArray() && + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && obj1.arrayGetLength() == 6) { for (i = 0; i < 6; ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { - matrix[i] = obj2.getNum(); + matrixA[i] = obj2.getNum(); } obj2.free(); } } obj1.free(); - stream->copy(&contentStream); + + pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA, + &resDictA, matrixA, patObj); + resDictA.free(); + return pat; +} + +GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA, + double *bboxA, double xStepA, double yStepA, + Object *resDictA, double *matrixA, + Object *contentStreamA): + GfxPattern(1) +{ + int i; + + paintType = paintTypeA; + tilingType = tilingTypeA; + for (i = 0; i < 4; ++i) { + bbox[i] = bboxA[i]; + } + xStep = xStepA; + yStep = yStepA; + resDictA->copy(&resDict); + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } + contentStreamA->copy(&contentStream); } GfxTilingPattern::~GfxTilingPattern() { @@ -1238,127 +1319,341 @@ GfxTilingPattern::~GfxTilingPattern() { } GfxPattern *GfxTilingPattern::copy() { - return new GfxTilingPattern(this); + return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep, + &resDict, matrix, &contentStream); } -GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat): - GfxPattern(1) +//------------------------------------------------------------------------ +// GfxShadingPattern +//------------------------------------------------------------------------ + +GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) { + Dict *dict; + GfxShading *shadingA; + double matrixA[6]; + Object obj1, obj2; + int i; + + if (!patObj->isDict()) { + return NULL; + } + dict = patObj->getDict(); + + dict->lookup("Shading", &obj1); + shadingA = GfxShading::parse(&obj1); + obj1.free(); + if (!shadingA) { + return NULL; + } + + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + for (i = 0; i < 6; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + matrixA[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + + return new GfxShadingPattern(shadingA, matrixA); +} + +GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA): + GfxPattern(2) { - memcpy(this, pat, sizeof(GfxTilingPattern)); - pat->resDict.copy(&resDict); - pat->contentStream.copy(&contentStream); + int i; + + shading = shadingA; + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } +} + +GfxShadingPattern::~GfxShadingPattern() { + delete shading; +} + +GfxPattern *GfxShadingPattern::copy() { + return new GfxShadingPattern(shading->copy(), matrix); } //------------------------------------------------------------------------ // GfxShading //------------------------------------------------------------------------ -GfxShading::GfxShading() { +GfxShading::GfxShading(int typeA) { + type = typeA; + colorSpace = NULL; +} + +GfxShading::GfxShading(GfxShading *shading) { + int i; + + type = shading->type; + colorSpace = shading->colorSpace->copy(); + for (i = 0; i < gfxColorMaxComps; ++i) { + background.c[i] = shading->background.c[i]; + } + hasBackground = shading->hasBackground; + xMin = shading->xMin; + yMin = shading->yMin; + xMax = shading->xMax; + yMax = shading->yMax; + hasBBox = shading->hasBBox; } GfxShading::~GfxShading() { - delete colorSpace; + if (colorSpace) { + delete colorSpace; + } } GfxShading *GfxShading::parse(Object *obj) { GfxShading *shading; + Dict *dict; int typeA; - GfxColorSpace *colorSpaceA; - GfxColor backgroundA; - GBool hasBackgroundA; - double xMinA, yMinA, xMaxA, yMaxA; - GBool hasBBoxA; - Object obj1, obj2; - int i; + Object obj1; - shading = NULL; if (obj->isDict()) { + dict = obj->getDict(); + } else if (obj->isStream()) { + dict = obj->streamGetDict(); + } else { + return NULL; + } - if (!obj->dictLookup("ShadingType", &obj1)->isInt()) { - error(-1, "Invalid ShadingType in shading dictionary"); - obj1.free(); - goto err1; - } - typeA = obj1.getInt(); + if (!dict->lookup("ShadingType", &obj1)->isInt()) { + error(-1, "Invalid ShadingType in shading dictionary"); obj1.free(); + return NULL; + } + typeA = obj1.getInt(); + obj1.free(); - obj->dictLookup("ColorSpace", &obj1); - if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) { - error(-1, "Bad color space in shading dictionary"); - obj1.free(); - goto err1; - } - obj1.free(); + switch (typeA) { + case 1: + shading = GfxFunctionShading::parse(dict); + break; + case 2: + shading = GfxAxialShading::parse(dict); + break; + case 3: + shading = GfxRadialShading::parse(dict); + break; + default: + error(-1, "Unimplemented shading type %d", typeA); + goto err1; + } - for (i = 0; i < gfxColorMaxComps; ++i) { - backgroundA.c[i] = 0; - } - hasBackgroundA = gFalse; - if (obj->dictLookup("Background", &obj1)->isArray()) { - if (obj1.arrayGetLength() == colorSpaceA->getNComps()) { - hasBackgroundA = gTrue; - for (i = 0; i < colorSpaceA->getNComps(); ++i) { - backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum(); - obj2.free(); - } - } else { - error(-1, "Bad Background in shading dictionary"); - } - } + return shading; + + err1: + return NULL; +} + +GBool GfxShading::init(Dict *dict) { + Object obj1, obj2; + int i; + + dict->lookup("ColorSpace", &obj1); + if (!(colorSpace = GfxColorSpace::parse(&obj1))) { + error(-1, "Bad color space in shading dictionary"); obj1.free(); + return gFalse; + } + obj1.free(); - xMinA = yMinA = xMaxA = yMaxA = 0; - hasBBoxA = gFalse; - if (obj->dictLookup("BBox", &obj1)->isArray()) { - if (obj1.arrayGetLength() == 4) { - hasBBoxA = gTrue; - xMinA = obj1.arrayGet(0, &obj2)->getNum(); - obj2.free(); - yMinA = obj1.arrayGet(1, &obj2)->getNum(); - obj2.free(); - xMaxA = obj1.arrayGet(2, &obj2)->getNum(); - obj2.free(); - yMaxA = obj1.arrayGet(3, &obj2)->getNum(); + for (i = 0; i < gfxColorMaxComps; ++i) { + background.c[i] = 0; + } + hasBackground = gFalse; + if (dict->lookup("Background", &obj1)->isArray()) { + if (obj1.arrayGetLength() == colorSpace->getNComps()) { + hasBackground = gTrue; + for (i = 0; i < colorSpace->getNComps(); ++i) { + background.c[i] = obj1.arrayGet(i, &obj2)->getNum(); obj2.free(); - } else { - error(-1, "Bad BBox in shading dictionary"); } + } else { + error(-1, "Bad Background in shading dictionary"); } - obj1.free(); + } + obj1.free(); - switch (typeA) { - case 2: - shading = GfxAxialShading::parse(obj->getDict()); - break; - case 3: - shading = GfxRadialShading::parse(obj->getDict()); - break; - default: - error(-1, "Unimplemented shading type %d", typeA); - goto err1; + xMin = yMin = xMax = yMax = 0; + hasBBox = gFalse; + if (dict->lookup("BBox", &obj1)->isArray()) { + if (obj1.arrayGetLength() == 4) { + hasBBox = gTrue; + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + yMin = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + } else { + error(-1, "Bad BBox in shading dictionary"); } + } + obj1.free(); - if (shading) { - shading->type = typeA; - shading->colorSpace = colorSpaceA; - shading->background = backgroundA; - shading->hasBackground = hasBackgroundA; - shading->xMin = xMinA; - shading->yMin = yMinA; - shading->xMax = xMaxA; - shading->yMax = yMaxA; - shading->hasBBox = hasBBoxA; - } else { - delete colorSpaceA; + return gTrue; +} + +//------------------------------------------------------------------------ +// GfxFunctionShading +//------------------------------------------------------------------------ + +GfxFunctionShading::GfxFunctionShading(double x0A, double y0A, + double x1A, double y1A, + double *matrixA, + Function **funcsA, int nFuncsA): + GfxShading(1) +{ + int i; + + x0 = x0A; + y0 = y0A; + x1 = x1A; + y1 = y1A; + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + x1 = shading->x1; + y1 = shading->y1; + for (i = 0; i < 6; ++i) { + matrix[i] = shading->matrix[i]; + } + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxFunctionShading::~GfxFunctionShading() { + int i; + + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) { + GfxFunctionShading *shading; + double x0A, y0A, x1A, y1A; + double matrixA[6]; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + Object obj1, obj2; + int i; + + x0A = y0A = 0; + x1A = y1A = 1; + if (dict->lookup("Domain", &obj1)->isArray() && + obj1.arrayGetLength() == 4) { + x0A = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + y0A = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + x1A = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + y1A = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + } + obj1.free(); + + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + matrixA[0] = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + matrixA[1] = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + matrixA[2] = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + matrixA[3] = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + matrixA[4] = obj1.arrayGet(4, &obj2)->getNum(); + obj2.free(); + matrixA[5] = obj1.arrayGet(5, &obj2)->getNum(); + obj2.free(); + } + obj1.free(); + + dict->lookup("Function", &obj1); + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + goto err2; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + goto err1; } } + obj1.free(); + shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } return shading; + err2: + obj2.free(); err1: + obj1.free(); return NULL; } +GfxShading *GfxFunctionShading::copy() { + return new GfxFunctionShading(this); +} + +void GfxFunctionShading::getColor(double x, double y, GfxColor *color) { + double in[2]; + int i; + + in[0] = x; + in[1] = y; + for (i = 0; i < nFuncs; ++i) { + funcs[i]->transform(in, &color->c[i]); + } +} + //------------------------------------------------------------------------ // GfxAxialShading //------------------------------------------------------------------------ @@ -1367,7 +1662,9 @@ GfxAxialShading::GfxAxialShading(double x0A, double y0A, double x1A, double y1A, double t0A, double t1A, Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A) { + GBool extend0A, GBool extend1A): + GfxShading(2) +{ int i; x0 = x0A; @@ -1384,6 +1681,25 @@ GfxAxialShading::GfxAxialShading(double x0A, double y0A, extend1 = extend1A; } +GfxAxialShading::GfxAxialShading(GfxAxialShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + x1 = shading->x1; + y1 = shading->y1; + t0 = shading->t0; + y1 = shading->t1; + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } + extend0 = shading->extend0; + extend1 = shading->extend1; +} + GfxAxialShading::~GfxAxialShading() { int i; @@ -1393,6 +1709,7 @@ GfxAxialShading::~GfxAxialShading() { } GfxAxialShading *GfxAxialShading::parse(Dict *dict) { + GfxAxialShading *shading; double x0A, y0A, x1A, y1A; double t0A, t1A; Function *funcsA[gfxColorMaxComps]; @@ -1432,6 +1749,10 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict) { dict->lookup("Function", &obj1); if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); if (!(funcsA[i] = Function::parse(&obj2))) { @@ -1460,16 +1781,27 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict) { } obj1.free(); - return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, - funcsA, nFuncsA, extend0A, extend1A); + shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, + funcsA, nFuncsA, extend0A, extend1A); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; err1: return NULL; } +GfxShading *GfxAxialShading::copy() { + return new GfxAxialShading(this); +} + void GfxAxialShading::getColor(double t, GfxColor *color) { int i; + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) for (i = 0; i < nFuncs; ++i) { funcs[i]->transform(&t, &color->c[i]); } @@ -1483,7 +1815,9 @@ GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A, double x1A, double y1A, double r1A, double t0A, double t1A, Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A) { + GBool extend0A, GBool extend1A): + GfxShading(3) +{ int i; x0 = x0A; @@ -1502,6 +1836,27 @@ GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A, extend1 = extend1A; } +GfxRadialShading::GfxRadialShading(GfxRadialShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + r0 = shading->r0; + x1 = shading->x1; + y1 = shading->y1; + r1 = shading->r1; + t0 = shading->t0; + y1 = shading->t1; + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } + extend0 = shading->extend0; + extend1 = shading->extend1; +} + GfxRadialShading::~GfxRadialShading() { int i; @@ -1511,6 +1866,7 @@ GfxRadialShading::~GfxRadialShading() { } GfxRadialShading *GfxRadialShading::parse(Dict *dict) { + GfxRadialShading *shading; double x0A, y0A, r0A, x1A, y1A, r1A; double t0A, t1A; Function *funcsA[gfxColorMaxComps]; @@ -1554,6 +1910,10 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict) { dict->lookup("Function", &obj1); if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); if (!(funcsA[i] = Function::parse(&obj2))) { @@ -1582,16 +1942,27 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict) { } obj1.free(); - return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, - funcsA, nFuncsA, extend0A, extend1A); + shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, + funcsA, nFuncsA, extend0A, extend1A); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; err1: return NULL; } +GfxShading *GfxRadialShading::copy() { + return new GfxRadialShading(this); +} + void GfxRadialShading::getColor(double t, GfxColor *color) { int i; + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) for (i = 0; i < nFuncs; ++i) { funcs[i]->transform(&t, &color->c[i]); } @@ -1612,14 +1983,12 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, double x[gfxColorMaxComps]; double y[gfxColorMaxComps]; int i, j, k; - int maxPixelForAlloc; ok = gTrue; // bits per component and color space bits = bitsA; maxPixel = (1 << bits) - 1; - maxPixelForAlloc = (1 << (bits>8?bits:8)); colorSpace = colorSpaceA; // get decode map @@ -1666,19 +2035,25 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, colorSpace2 = indexedCS->getBase(); indexHigh = indexedCS->getIndexHigh(); nComps2 = colorSpace2->getNComps(); - lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double)); + lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double)); lookup2 = indexedCS->getLookup(); - for (i = 0; i <= indexHigh; ++i) { - j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5); + colorSpace2->getDefaultRanges(x, y, indexHigh); + for (i = 0; i <= maxPixel; ++i) { + j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); + if (j < 0) { + j = 0; + } else if (j > indexHigh) { + j = indexHigh; + } for (k = 0; k < nComps2; ++k) { - lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0; + lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]; } } } else if (colorSpace->getMode() == csSeparation) { sepCS = (GfxSeparationColorSpace *)colorSpace; colorSpace2 = sepCS->getAlt(); nComps2 = colorSpace2->getNComps(); - lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double)); + lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double)); sepFunc = sepCS->getFunc(); for (i = 0; i <= maxPixel; ++i) { x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; @@ -1688,7 +2063,7 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, } } } else { - lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps * sizeof(double)); + lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double)); for (i = 0; i <= maxPixel; ++i) { for (k = 0; k < nComps; ++k) { lookup[i*nComps + k] = decodeLow[k] + @@ -1705,6 +2080,34 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, ok = gFalse; } +GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { + int n, i; + + colorSpace = colorMap->colorSpace->copy(); + bits = colorMap->bits; + nComps = colorMap->nComps; + nComps2 = colorMap->nComps2; + colorSpace2 = NULL; + lookup = NULL; + n = 1 << bits; + if (colorSpace->getMode() == csIndexed) { + colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase(); + n = n * nComps2 * sizeof(double); + } else if (colorSpace->getMode() == csSeparation) { + colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt(); + n = n * nComps2 * sizeof(double); + } else { + n = n * nComps * sizeof(double); + } + lookup = (double *)gmalloc(n); + memcpy(lookup, colorMap->lookup, n); + for (i = 0; i < nComps; ++i) { + decodeLow[i] = colorMap->decodeLow[i]; + decodeRange[i] = colorMap->decodeRange[i]; + } + ok = gTrue; +} + GfxImageColorMap::~GfxImageColorMap() { delete colorSpace; gfree(lookup); @@ -1730,20 +2133,17 @@ void GfxImageColorMap::getGray(Guchar *x, double *gray) { } void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { - GfxColor color; double *p; int i; if (colorSpace2) { - //printf("lookup[%d] bits=%d\n",x[0],bits);fflush(stdout); p = &lookup[x[0] * nComps2]; for (i = 0; i < nComps2; ++i) { color.c[i] = *p++; } colorSpace2->getRGB(&color, rgb); } else { - //printf("for i=0,i<%d, bits=%d\n",nComps,bits);fflush(stdout); for (i = 0; i < nComps; ++i) { color.c[i] = lookup[x[i] * nComps + i]; } @@ -1770,6 +2170,15 @@ void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { } } +void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { + int maxPixel, i; + + maxPixel = (1 << bits) - 1; + for (i = 0; i < nComps; ++i) { + color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel; + } +} + //------------------------------------------------------------------------ // GfxSubpath and GfxPath //------------------------------------------------------------------------ @@ -1844,6 +2253,15 @@ void GfxSubpath::close() { closed = gTrue; } +void GfxSubpath::offset(double dx, double dy) { + int i; + + for (i = 0; i < n; ++i) { + x[i] += dx; + y[i] += dy; + } +} + GfxPath::GfxPath() { justMoved = gFalse; size = 16; @@ -1926,55 +2344,78 @@ void GfxPath::close() { subpaths[n-1]->close(); } +void GfxPath::append(GfxPath *path) { + int i; + + if (n + path->n > size) { + size = n + path->n; + subpaths = (GfxSubpath **) + grealloc(subpaths, size * sizeof(GfxSubpath *)); + } + for (i = 0; i < path->n; ++i) { + subpaths[n++] = path->subpaths[i]->copy(); + } + justMoved = gFalse; +} + +void GfxPath::offset(double dx, double dy) { + int i; + + for (i = 0; i < n; ++i) { + subpaths[i]->offset(dx, dy); + } +} + //------------------------------------------------------------------------ // GfxState //------------------------------------------------------------------------ -GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate, - GBool upsideDown) { - double k; +GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, + int rotate, GBool upsideDown) { + double kx, ky; px1 = pageBox->x1; py1 = pageBox->y1; px2 = pageBox->x2; py2 = pageBox->y2; - k = dpi / 72.0; + kx = hDPI / 72.0; + ky = vDPI / 72.0; if (rotate == 90) { ctm[0] = 0; - ctm[1] = upsideDown ? k : -k; - ctm[2] = k; + ctm[1] = upsideDown ? ky : -ky; + ctm[2] = kx; ctm[3] = 0; - ctm[4] = -k * py1; - ctm[5] = k * (upsideDown ? -px1 : px2); - pageWidth = k * (py2 - py1); - pageHeight = k * (px2 - px1); + ctm[4] = -kx * py1; + ctm[5] = ky * (upsideDown ? -px1 : px2); + pageWidth = kx * (py2 - py1); + pageHeight = ky * (px2 - px1); } else if (rotate == 180) { - ctm[0] = -k; + ctm[0] = -kx; ctm[1] = 0; ctm[2] = 0; - ctm[3] = upsideDown ? k : -k; - ctm[4] = k * px2; - ctm[5] = k * (upsideDown ? -py1 : py2); - pageWidth = k * (px2 - px1); - pageHeight = k * (py2 - py1); + ctm[3] = upsideDown ? ky : -ky; + ctm[4] = kx * px2; + ctm[5] = ky * (upsideDown ? -py1 : py2); + pageWidth = kx * (px2 - px1); + pageHeight = ky * (py2 - py1); } else if (rotate == 270) { ctm[0] = 0; - ctm[1] = upsideDown ? -k : k; - ctm[2] = -k; + ctm[1] = upsideDown ? -ky : ky; + ctm[2] = -kx; ctm[3] = 0; - ctm[4] = k * py2; - ctm[5] = k * (upsideDown ? px2 : -px1); - pageWidth = k * (py2 - py1); - pageHeight = k * (px2 - px1); + ctm[4] = kx * py2; + ctm[5] = ky * (upsideDown ? px2 : -px1); + pageWidth = kx * (py2 - py1); + pageHeight = ky * (px2 - px1); } else { - ctm[0] = k; + ctm[0] = kx; ctm[1] = 0; ctm[2] = 0; - ctm[3] = upsideDown ? -k : k; - ctm[4] = -k * px1; - ctm[5] = k * (upsideDown ? py2 : -py1); - pageWidth = k * (px2 - px1); - pageHeight = k * (py2 - py1); + ctm[3] = upsideDown ? -ky : ky; + ctm[4] = -kx * px1; + ctm[5] = ky * (upsideDown ? py2 : -py1); + pageWidth = kx * (px2 - px1); + pageHeight = ky * (py2 - py1); } fillColorSpace = new GfxDeviceGrayColorSpace(); @@ -1990,7 +2431,7 @@ GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate, lineDash = NULL; lineDashLength = 0; lineDashStart = 0; - flatness = 0; + flatness = 1; lineJoin = 0; lineCap = 0; miterLimit = 10; @@ -2064,6 +2505,11 @@ GfxState::GfxState(GfxState *state) { saved = NULL; } +void GfxState::setPath(GfxPath *pathA) { + delete path; + path = pathA; +} + void GfxState::getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax) { double ictm[6]; diff --git a/pdf2swf/xpdf/GfxState.h b/pdf2swf/xpdf/GfxState.h index b1f6f28..f747a83 100644 --- a/pdf2swf/xpdf/GfxState.h +++ b/pdf2swf/xpdf/GfxState.h @@ -2,14 +2,16 @@ // // GfxState.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GFXSTATE_H #define GFXSTATE_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -19,7 +21,8 @@ class Array; class GfxFont; -struct PDFRectangle; +class PDFRectangle; +class GfxShading; //------------------------------------------------------------------------ // GfxColor @@ -51,6 +54,8 @@ struct GfxCMYK { // GfxColorSpace //------------------------------------------------------------------------ +// NB: The nGfxColorSpaceModes constant and the gfxColorSpaceModeNames +// array defined in GfxState.cc must match this enum. enum GfxColorSpaceMode { csDeviceGray, csCalGray, @@ -89,6 +94,12 @@ public: virtual void getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel); + // Return the number of color space modes + static int getNumColorSpaceModes(); + + // Return the name of the th color space mode. + static char *getColorSpaceModeName(int idx); + private: }; @@ -342,6 +353,7 @@ public: GfxColorSpace *getBase() { return base; } int getIndexHigh() { return indexHigh; } Guchar *getLookup() { return lookup; } + GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor); private: @@ -391,7 +403,7 @@ private: class GfxDeviceNColorSpace: public GfxColorSpace { public: - GfxDeviceNColorSpace(int nComps, GfxColorSpace *alt, Function *func); + GfxDeviceNColorSpace(int nCompsA, GfxColorSpace *alt, Function *func); virtual ~GfxDeviceNColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceN; } @@ -406,7 +418,9 @@ public: virtual int getNComps() { return nComps; } // DeviceN-specific access. + GString *getColorantName(int i) { return names[i]; } GfxColorSpace *getAlt() { return alt; } + Function *getTintTransformFunc() { return func; } private: @@ -415,7 +429,6 @@ private: *names[gfxColorMaxComps]; GfxColorSpace *alt; // alternate color space Function *func; // tint transform (into alternate color space) - }; //------------------------------------------------------------------------ @@ -476,7 +489,7 @@ private: class GfxTilingPattern: public GfxPattern { public: - GfxTilingPattern(Dict *streamDict, Object *stream); + static GfxTilingPattern *parse(Object *patObj); virtual ~GfxTilingPattern(); virtual GfxPattern *copy(); @@ -493,7 +506,10 @@ public: private: - GfxTilingPattern(GfxTilingPattern *pat); + GfxTilingPattern(int paintTypeA, int tilingTypeA, + double *bboxA, double xStepA, double yStepA, + Object *resDictA, double *matrixA, + Object *contentStreamA); int paintType; int tilingType; @@ -505,17 +521,43 @@ private: }; //------------------------------------------------------------------------ +// GfxShadingPattern +//------------------------------------------------------------------------ + +class GfxShadingPattern: public GfxPattern { +public: + + static GfxShadingPattern *parse(Object *patObj); + virtual ~GfxShadingPattern(); + + virtual GfxPattern *copy(); + + GfxShading *getShading() { return shading; } + double *getMatrix() { return matrix; } + +private: + + GfxShadingPattern(GfxShading *shadingA, double *matrixA); + + GfxShading *shading; + double matrix[6]; +}; + +//------------------------------------------------------------------------ // GfxShading //------------------------------------------------------------------------ class GfxShading { public: - GfxShading(); + GfxShading(int typeA); + GfxShading(GfxShading *shading); virtual ~GfxShading(); static GfxShading *parse(Object *obj); + virtual GfxShading *copy() = 0; + int getType() { return type; } GfxColorSpace *getColorSpace() { return colorSpace; } GfxColor *getBackground() { return &background; } @@ -524,7 +566,9 @@ public: { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } GBool getHasBBox() { return hasBBox; } -private: +protected: + + GBool init(Dict *dict); int type; GfxColorSpace *colorSpace; @@ -535,6 +579,37 @@ private: }; //------------------------------------------------------------------------ +// GfxFunctionShading +//------------------------------------------------------------------------ + +class GfxFunctionShading: public GfxShading { +public: + + GfxFunctionShading(double x0A, double y0A, + double x1A, double y1A, + double *matrixA, + Function **funcsA, int nFuncsA); + GfxFunctionShading(GfxFunctionShading *shading); + virtual ~GfxFunctionShading(); + + static GfxFunctionShading *parse(Dict *dict); + + virtual GfxShading *copy(); + + void getDomain(double *x0A, double *y0A, double *x1A, double *y1A) + { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } + double *getMatrix() { return matrix; } + void getColor(double x, double y, GfxColor *color); + +private: + + double x0, y0, x1, y1; + double matrix[6]; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ // GfxAxialShading //------------------------------------------------------------------------ @@ -546,10 +621,13 @@ public: double t0A, double t1A, Function **funcsA, int nFuncsA, GBool extend0A, GBool extend1A); + GfxAxialShading(GfxAxialShading *shading); virtual ~GfxAxialShading(); static GfxAxialShading *parse(Dict *dict); + virtual GfxShading *copy(); + void getCoords(double *x0A, double *y0A, double *x1A, double *y1A) { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } double getDomain0() { return t0; } @@ -579,10 +657,13 @@ public: double t0A, double t1A, Function **funcsA, int nFuncsA, GBool extend0A, GBool extend1A); + GfxRadialShading(GfxRadialShading *shading); virtual ~GfxRadialShading(); static GfxRadialShading *parse(Dict *dict); + virtual GfxShading *copy(); + void getCoords(double *x0A, double *y0A, double *r0A, double *x1A, double *y1A, double *r1A) { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; } @@ -614,6 +695,9 @@ public: // Destructor. ~GfxImageColorMap(); + // Return a copy of this color map. + GfxImageColorMap *copy() { return new GfxImageColorMap(this); } + // Is color map valid? GBool isOk() { return ok; } @@ -632,9 +716,12 @@ public: void getGray(Guchar *x, double *gray); void getRGB(Guchar *x, GfxRGB *rgb); void getCMYK(Guchar *x, GfxCMYK *cmyk); + void getColor(Guchar *x, GfxColor *color); private: + GfxImageColorMap(GfxImageColorMap *colorMap); + GfxColorSpace *colorSpace; // the image color space int bits; // bits per component int nComps; // number of components in a pixel @@ -685,6 +772,9 @@ public: void close(); GBool isClosed() { return closed; } + // Add (, ) to each point in the subpath. + void offset(double dx, double dy); + private: double *x, *y; // points @@ -737,6 +827,12 @@ public: // Close the last subpath. void close(); + // Append to . + void append(GfxPath *path); + + // Add (, ) to each point in the path. + void offset(double dx, double dy); + private: GBool justMoved; // set if a new subpath was just started @@ -756,11 +852,11 @@ private: class GfxState { public: - // Construct a default GfxState, for a device with resolution , - // page box , page rotation , and coordinate system - // specified by . - GfxState(double dpi, PDFRectangle *pageBox, int rotate, - GBool upsideDown); + // Construct a default GfxState, for a device with resolution + // x , page box , page rotation , and + // coordinate system specified by . + GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, + int rotate, GBool upsideDown); // Destructor. ~GfxState(); @@ -781,7 +877,7 @@ public: void getFillGray(double *gray) { fillColorSpace->getGray(&fillColor, gray); } void getStrokeGray(double *gray) - { strokeColorSpace->getGray(&fillColor, gray); } + { strokeColorSpace->getGray(&strokeColor, gray); } void getFillRGB(GfxRGB *rgb) { fillColorSpace->getRGB(&fillColor, rgb); } void getStrokeRGB(GfxRGB *rgb) @@ -813,6 +909,7 @@ public: double getRise() { return rise; } int getRender() { return render; } GfxPath *getPath() { return path; } + void setPath(GfxPath *pathA); double getCurX() { return curX; } double getCurY() { return curY; } void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax) @@ -898,6 +995,7 @@ public: void clip(); // Text position. + void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; } void textMoveTo(double tx, double ty) { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); } void textShift(double tx, double ty); diff --git a/pdf2swf/xpdf/GlobalParams.cc b/pdf2swf/xpdf/GlobalParams.cc index 0bc908e..c125430 100644 --- a/pdf2swf/xpdf/GlobalParams.cc +++ b/pdf2swf/xpdf/GlobalParams.cc @@ -2,16 +2,18 @@ // // GlobalParams.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include +#include #include #if HAVE_PAPER_H #include @@ -30,13 +32,63 @@ #include "FontEncodingTables.h" #include "GlobalParams.h" +#if MULTITHREADED +# define lockGlobalParams gLockMutex(&mutex) +# define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex) +# define lockCMapCache gLockMutex(&cMapCacheMutex) +# define unlockGlobalParams gUnlockMutex(&mutex) +# define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex) +# define unlockCMapCache gUnlockMutex(&cMapCacheMutex) +#else +# define lockGlobalParams +# define lockUnicodeMapCache +# define lockCMapCache +# define unlockGlobalParams +# define unlockUnicodeMapCache +# define unlockCMapCache +#endif + #include "NameToUnicodeTable.h" #include "UnicodeMapTables.h" -#include "DisplayFontTable.h" #include "UTF8.h" //------------------------------------------------------------------------ +#define cidToUnicodeCacheSize 4 +#define unicodeToUnicodeCacheSize 4 + +//------------------------------------------------------------------------ + +static struct { + char *name; + char *fileName; +} displayFontTab[] = { + {"Courier", "n022003l.pfb"}, + {"Courier-Bold", "n022004l.pfb"}, + {"Courier-BoldOblique", "n022024l.pfb"}, + {"Courier-Oblique", "n022023l.pfb"}, + {"Helvetica", "n019003l.pfb"}, + {"Helvetica-Bold", "n019004l.pfb"}, + {"Helvetica-BoldOblique", "n019024l.pfb"}, + {"Helvetica-Oblique", "n019023l.pfb"}, + {"Symbol", "s050000l.pfb"}, + {"Times-Bold", "n021004l.pfb"}, + {"Times-BoldItalic", "n021024l.pfb"}, + {"Times-Italic", "n021023l.pfb"}, + {"Times-Roman", "n021003l.pfb"}, + {"ZapfDingbats", "d050000l.pfb"}, + {NULL} +}; + +static char *displayFontDirs[] = { + "/usr/share/ghostscript/fonts", + "/usr/local/share/ghostscript/fonts", + "/usr/share/fonts/default/Type1", + NULL +}; + +//------------------------------------------------------------------------ + GlobalParams *globalParams = NULL; //------------------------------------------------------------------------ @@ -48,10 +100,6 @@ DisplayFontParam::DisplayFontParam(GString *nameA, name = nameA; kind = kindA; switch (kind) { - case displayFontX: - x.xlfd = NULL; - x.encoding = NULL; - break; case displayFontT1: t1.fileName = NULL; break; @@ -61,24 +109,9 @@ DisplayFontParam::DisplayFontParam(GString *nameA, } } -DisplayFontParam::DisplayFontParam(char *nameA, char *xlfdA, char *encodingA) { - name = new GString(nameA); - kind = displayFontX; - x.xlfd = new GString(xlfdA); - x.encoding = new GString(encodingA); -} - DisplayFontParam::~DisplayFontParam() { delete name; switch (kind) { - case displayFontX: - if (x.xlfd) { - delete x.xlfd; - } - if (x.encoding) { - delete x.encoding; - } - break; case displayFontT1: if (t1.fileName) { delete t1.fileName; @@ -118,11 +151,16 @@ PSFontParam::~PSFontParam() { GlobalParams::GlobalParams(char *cfgFileName) { UnicodeMap *map; - DisplayFontParam *dfp; GString *fileName; FILE *f; int i; +#if MULTITHREADED + gInitMutex(&mutex); + gInitMutex(&unicodeMapCacheMutex); + gInitMutex(&cMapCacheMutex); +#endif + initBuiltinFontTables(); // scan the encoding in reverse because we want the lowest-numbered @@ -136,6 +174,7 @@ GlobalParams::GlobalParams(char *cfgFileName) { nameToUnicode = new NameToCharCode(); cidToUnicodes = new GHash(gTrue); + unicodeToUnicodes = new GHash(gTrue); residentUnicodeMaps = new GHash(); unicodeMaps = new GHash(gTrue); cMapDirs = new GHash(gTrue); @@ -144,16 +183,30 @@ GlobalParams::GlobalParams(char *cfgFileName) { displayCIDFonts = new GHash(); displayNamedCIDFonts = new GHash(); #if HAVE_PAPER_H + char *paperName; const struct paper *paperType; paperinit(); - paperType = paperinfo(systempapername()); - psPaperWidth = (int)paperpswidth(paperType); - psPaperHeight = (int)paperpsheight(paperType); + if ((paperName = systempapername())) { + paperType = paperinfo(paperName); + psPaperWidth = (int)paperpswidth(paperType); + psPaperHeight = (int)paperpsheight(paperType); + } else { + error(-1, "No paper information available - using defaults"); + psPaperWidth = defPaperWidth; + psPaperHeight = defPaperHeight; + } paperdone(); #else psPaperWidth = defPaperWidth; psPaperHeight = defPaperHeight; #endif + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + psCrop = gTrue; + psExpandSmaller = gFalse; + psShrinkLarger = gTrue; + psCenter = gTrue; psDuplex = gFalse; psLevel = psLevel2; psFile = NULL; @@ -174,15 +227,22 @@ GlobalParams::GlobalParams(char *cfgFileName) { #else textEOL = eolUnix; #endif + textPageBreaks = gTrue; + textKeepTinyChars = gFalse; fontDirs = new GList(); - initialZoom = new GString("1"); - t1libControl = fontRastAALow; - freetypeControl = fontRastAALow; + initialZoom = new GString("125"); + enableT1lib = gTrue; + enableFreeType = gTrue; + antialias = gTrue; urlCommand = NULL; + movieCommand = NULL; mapNumericCharNames = gTrue; + printCommands = gFalse; errQuiet = gFalse; - cidToUnicodeCache = new CIDToUnicodeCache(); + cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize); + unicodeToUnicodeCache = + new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize); unicodeMapCache = new UnicodeMapCache(); cMapCache = new CMapCache(); @@ -192,28 +252,23 @@ GlobalParams::GlobalParams(char *cfgFileName) { } // set up the residentUnicodeMaps table - map = new UnicodeMap("Latin1", latin1UnicodeMapRanges, latin1UnicodeMapLen); + map = new UnicodeMap("Latin1", gFalse, + latin1UnicodeMapRanges, latin1UnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("ASCII7", ascii7UnicodeMapRanges, ascii7UnicodeMapLen); + map = new UnicodeMap("ASCII7", gFalse, + ascii7UnicodeMapRanges, ascii7UnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("Symbol", symbolUnicodeMapRanges, symbolUnicodeMapLen); + map = new UnicodeMap("Symbol", gFalse, + symbolUnicodeMapRanges, symbolUnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("ZapfDingbats", zapfDingbatsUnicodeMapRanges, + map = new UnicodeMap("ZapfDingbats", gFalse, zapfDingbatsUnicodeMapRanges, zapfDingbatsUnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("UTF-8", &mapUTF8); + map = new UnicodeMap("UTF-8", gTrue, &mapUTF8); residentUnicodeMaps->add(map->getEncodingName(), map); - map = new UnicodeMap("UCS-2", &mapUCS2); + map = new UnicodeMap("UCS-2", gTrue, &mapUCS2); residentUnicodeMaps->add(map->getEncodingName(), map); - // default displayFonts table - for (i = 0; displayFontTab[i].name; ++i) { - dfp = new DisplayFontParam(displayFontTab[i].name, - displayFontTab[i].xlfd, - displayFontTab[i].encoding); - displayFonts->add(dfp->name, dfp); - } - // look for a user config file, then a system-wide config file f = NULL; fileName = NULL; @@ -235,7 +290,7 @@ GlobalParams::GlobalParams(char *cfgFileName) { i = GetModuleFileName(NULL, buf, sizeof(buf)); if (i <= 0 || i >= sizeof(buf)) { // error or path too long for buffer - just use the current dir - buf[i] = '\0'; + buf[0] = '\0'; } fileName = grabPath(buf); appendToPath(fileName, xpdfSysConfigFile); @@ -249,6 +304,7 @@ GlobalParams::GlobalParams(char *cfgFileName) { if (f) { parseFile(fileName, f); delete fileName; + fclose(f); } } @@ -261,7 +317,7 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { FILE *f2; line = 1; - while (fgets(buf, sizeof(buf) - 1, f)) { + while (getLine(buf, sizeof(buf) - 1, f)) { // break the line into tokens tokens = new GList(); @@ -278,7 +334,7 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ; } tokens->append(new GString(p1, p2 - p1)); - p1 = p2 + 1; + p1 = *p2 ? p2 + 1 : p2; } if (tokens->getLength() > 0 && @@ -302,24 +358,30 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { parseNameToUnicode(tokens, fileName, line); } else if (!cmd->cmp("cidToUnicode")) { parseCIDToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("unicodeToUnicode")) { + parseUnicodeToUnicode(tokens, fileName, line); } else if (!cmd->cmp("unicodeMap")) { parseUnicodeMap(tokens, fileName, line); } else if (!cmd->cmp("cMapDir")) { parseCMapDir(tokens, fileName, line); } else if (!cmd->cmp("toUnicodeDir")) { parseToUnicodeDir(tokens, fileName, line); - } else if (!cmd->cmp("displayFontX")) { - parseDisplayFont(tokens, displayFonts, displayFontX, fileName, line); } else if (!cmd->cmp("displayFontT1")) { parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line); } else if (!cmd->cmp("displayFontTT")) { parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line); - } else if (!cmd->cmp("displayCIDFontX")) { + } else if (!cmd->cmp("displayNamedCIDFontT1")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontT1, fileName, line); + } else if (!cmd->cmp("displayCIDFontT1")) { parseDisplayFont(tokens, displayCIDFonts, - displayFontX, fileName, line); - } else if (!cmd->cmp("displayNamedCIDFontX")) { + displayFontT1, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontTT")) { parseDisplayFont(tokens, displayNamedCIDFonts, - displayFontX, fileName, line); + displayFontTT, fileName, line); + } else if (!cmd->cmp("displayCIDFontTT")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontTT, fileName, line); } else if (!cmd->cmp("psFile")) { parsePSFile(tokens, fileName, line); } else if (!cmd->cmp("psFont")) { @@ -331,6 +393,17 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { parsePSFont16("psFont16", psFonts16, tokens, fileName, line); } else if (!cmd->cmp("psPaperSize")) { parsePSPaperSize(tokens, fileName, line); + } else if (!cmd->cmp("psImageableArea")) { + parsePSImageableArea(tokens, fileName, line); + } else if (!cmd->cmp("psCrop")) { + parseYesNo("psCrop", &psCrop, tokens, fileName, line); + } else if (!cmd->cmp("psExpandSmaller")) { + parseYesNo("psExpandSmaller", &psExpandSmaller, + tokens, fileName, line); + } else if (!cmd->cmp("psShrinkLarger")) { + parseYesNo("psShrinkLarger", &psShrinkLarger, tokens, fileName, line); + } else if (!cmd->cmp("psCenter")) { + parseYesNo("psCenter", &psCenter, tokens, fileName, line); } else if (!cmd->cmp("psDuplex")) { parseYesNo("psDuplex", &psDuplex, tokens, fileName, line); } else if (!cmd->cmp("psLevel")) { @@ -354,29 +427,46 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { parseTextEncoding(tokens, fileName, line); } else if (!cmd->cmp("textEOL")) { parseTextEOL(tokens, fileName, line); + } else if (!cmd->cmp("textPageBreaks")) { + parseYesNo("textPageBreaks", &textPageBreaks, + tokens, fileName, line); + } else if (!cmd->cmp("textKeepTinyChars")) { + parseYesNo("textKeepTinyChars", &textKeepTinyChars, + tokens, fileName, line); } else if (!cmd->cmp("fontDir")) { parseFontDir(tokens, fileName, line); } else if (!cmd->cmp("initialZoom")) { parseInitialZoom(tokens, fileName, line); - } else if (!cmd->cmp("t1libControl")) { - parseFontRastControl("t1libControl", &t1libControl, - tokens, fileName, line); - } else if (!cmd->cmp("freetypeControl")) { - parseFontRastControl("freetypeControl", &freetypeControl, - tokens, fileName, line); + } else if (!cmd->cmp("enableT1lib")) { + parseYesNo("enableT1lib", &enableT1lib, tokens, fileName, line); + } else if (!cmd->cmp("enableFreeType")) { + parseYesNo("enableFreeType", &enableFreeType, tokens, fileName, line); + } else if (!cmd->cmp("antialias")) { + parseYesNo("antialias", &antialias, tokens, fileName, line); } else if (!cmd->cmp("urlCommand")) { - parseURLCommand(tokens, fileName, line); + parseCommand("urlCommand", &urlCommand, tokens, fileName, line); + } else if (!cmd->cmp("movieCommand")) { + parseCommand("movieCommand", &movieCommand, tokens, fileName, line); } else if (!cmd->cmp("mapNumericCharNames")) { parseYesNo("mapNumericCharNames", &mapNumericCharNames, tokens, fileName, line); + } else if (!cmd->cmp("printCommands")) { + parseYesNo("printCommands", &printCommands, tokens, fileName, line); } else if (!cmd->cmp("errQuiet")) { parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); - } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { - error(-1, "Unknown config file command"); - error(-1, "-- the config file format has changed since Xpdf 0.9x"); } else { error(-1, "Unknown config file command '%s' (%s:%d)", cmd->getCString(), fileName->getCString(), line); + if (!cmd->cmp("displayFontX") || + !cmd->cmp("displayNamedCIDFontX") || + !cmd->cmp("displayCIDFontX")) { + error(-1, "-- Xpdf no longer supports X fonts"); + } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) { + error(-1, "-- The t1libControl and freetypeControl options have been replaced"); + error(-1, " by the enableT1lib, enableFreeType, and antialias options"); + } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { + error(-1, "-- the config file format has changed since Xpdf 0.9x"); + } } } @@ -406,7 +496,7 @@ void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName, return; } line2 = 1; - while (fgets(buf, sizeof(buf), f)) { + while (getLine(buf, sizeof(buf), f)) { tok1 = strtok(buf, " \t\r\n"); tok2 = strtok(NULL, " \t\r\n"); if (tok1 && tok2) { @@ -437,6 +527,23 @@ void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName, cidToUnicodes->add(collection->copy(), name->copy()); } +void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName, + int line) { + GString *font, *file, *old; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'unicodeToUnicode' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + font = (GString *)tokens->get(1); + file = (GString *)tokens->get(2); + if ((old = (GString *)unicodeToUnicodes->remove(font))) { + delete old; + } + unicodeToUnicodes->add(font->copy(), file->copy()); +} + void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName, int line) { GString *encodingName, *name, *old; @@ -493,13 +600,6 @@ void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash, param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind); switch (kind) { - case displayFontX: - if (tokens->getLength() != 4) { - goto err2; - } - param->x.xlfd = ((GString *)tokens->get(2))->copy(); - param->x.encoding = ((GString *)tokens->get(3))->copy(); - break; case displayFontT1: if (tokens->getLength() != 3) { goto err2; @@ -542,12 +642,28 @@ void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName, psPaperWidth = atoi(tok->getCString()); tok = (GString *)tokens->get(2); psPaperHeight = atoi(tok->getCString()); + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; } else { error(-1, "Bad 'psPaperSize' config file command (%s:%d)", fileName->getCString(), line); } } +void GlobalParams::parsePSImageableArea(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 5) { + error(-1, "Bad 'psImageableArea' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + psImageableLLX = atoi(((GString *)tokens->get(1))->getCString()); + psImageableLLY = atoi(((GString *)tokens->get(2))->getCString()); + psImageableURX = atoi(((GString *)tokens->get(3))->getCString()); + psImageableURY = atoi(((GString *)tokens->get(4))->getCString()); +} + void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) { GString *tok; @@ -680,34 +796,17 @@ void GlobalParams::parseInitialZoom(GList *tokens, initialZoom = ((GString *)tokens->get(1))->copy(); } -void GlobalParams::parseFontRastControl(char *cmdName, FontRastControl *val, - GList *tokens, GString *fileName, - int line) { - GString *tok; - +void GlobalParams::parseCommand(char *cmdName, GString **val, + GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(-1, "Bad '%s' config file command (%s:%d)", cmdName, fileName->getCString(), line); return; } - tok = (GString *)tokens->get(1); - if (!setFontRastControl(val, tok->getCString())) { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); + if (*val) { + delete *val; } -} - -void GlobalParams::parseURLCommand(GList *tokens, GString *fileName, - int line) { - if (tokens->getLength() != 2) { - error(-1, "Bad 'urlCommand' config file command (%s:%d)", - fileName->getCString(), line); - return; - } - if (urlCommand) { - delete urlCommand; - } - urlCommand = ((GString *)tokens->get(1))->copy(); + *val = ((GString *)tokens->get(1))->copy(); } void GlobalParams::parseYesNo(char *cmdName, GBool *flag, @@ -720,14 +819,21 @@ void GlobalParams::parseYesNo(char *cmdName, GBool *flag, return; } tok = (GString *)tokens->get(1); - if (!tok->cmp("yes")) { + if (!parseYesNo2(tok->getCString(), flag)) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + } +} + +GBool GlobalParams::parseYesNo2(char *token, GBool *flag) { + if (!strcmp(token, "yes")) { *flag = gTrue; - } else if (!tok->cmp("no")) { + } else if (!strcmp(token, "no")) { *flag = gFalse; } else { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); + return gFalse; } + return gTrue; } GlobalParams::~GlobalParams() { @@ -741,6 +847,7 @@ GlobalParams::~GlobalParams() { delete nameToUnicode; deleteGHash(cidToUnicodes, GString); + deleteGHash(unicodeToUnicodes, GString); deleteGHash(residentUnicodeMaps, UnicodeMap); deleteGHash(unicodeMaps, GString); deleteGList(toUnicodeDirs, GString); @@ -759,6 +866,9 @@ GlobalParams::~GlobalParams() { if (urlCommand) { delete urlCommand; } + if (movieCommand) { + delete movieCommand; + } cMapDirs->startIter(&iter); while (cMapDirs->getNext(&iter, &key, (void **)&list)) { @@ -767,8 +877,63 @@ GlobalParams::~GlobalParams() { delete cMapDirs; delete cidToUnicodeCache; + delete unicodeToUnicodeCache; delete unicodeMapCache; delete cMapCache; + +#if MULTITHREADED + gDestroyMutex(&mutex); + gDestroyMutex(&unicodeMapCacheMutex); + gDestroyMutex(&cMapCacheMutex); +#endif +} + +//------------------------------------------------------------------------ + +void GlobalParams::setupBaseFonts(char *dir) { + GString *fontName; + GString *fileName; + FILE *f; + DisplayFontParam *dfp; + int i, j; + + for (i = 0; displayFontTab[i].name; ++i) { + fontName = new GString(displayFontTab[i].name); + if (getDisplayFont(fontName)) { + delete fontName; + continue; + } + fileName = NULL; + if (dir) { + fileName = appendToPath(new GString(dir), displayFontTab[i].fileName); + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } +#ifndef WIN32 + for (j = 0; !fileName && displayFontDirs[j]; ++j) { + fileName = appendToPath(new GString(displayFontDirs[j]), + displayFontTab[i].fileName); + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } +#endif + if (!fileName) { + error(-1, "No display font for '%s'", displayFontTab[i].name); + delete fontName; + continue; + } + dfp = new DisplayFontParam(fontName, displayFontT1); + dfp->t1.fileName = fileName; + globalParams->addDisplayFont(dfp); + } } //------------------------------------------------------------------------ @@ -776,33 +941,39 @@ GlobalParams::~GlobalParams() { //------------------------------------------------------------------------ CharCode GlobalParams::getMacRomanCharCode(char *charName) { + // no need to lock - macRomanReverseMap is constant return macRomanReverseMap->lookup(charName); } Unicode GlobalParams::mapNameToUnicode(char *charName) { + // no need to lock - nameToUnicode is constant return nameToUnicode->lookup(charName); } -FILE *GlobalParams::getCIDToUnicodeFile(GString *collection) { - GString *fileName; +UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) { + UnicodeMap *map; - if (!(fileName = (GString *)cidToUnicodes->lookup(collection))) { - return NULL; + lockGlobalParams; + map = (UnicodeMap *)residentUnicodeMaps->lookup(encodingName); + unlockGlobalParams; + if (map) { + map->incRefCnt(); } - return fopen(fileName->getCString(), "r"); -} - -UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) { - return (UnicodeMap *)residentUnicodeMaps->lookup(encodingName); + return map; } FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) { GString *fileName; + FILE *f; - if (!(fileName = (GString *)unicodeMaps->lookup(encodingName))) { - return NULL; + lockGlobalParams; + if ((fileName = (GString *)unicodeMaps->lookup(encodingName))) { + f = fopen(fileName->getCString(), "r"); + } else { + f = NULL; } - return fopen(fileName->getCString(), "r"); + unlockGlobalParams; + return f; } FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { @@ -812,7 +983,9 @@ FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { FILE *f; int i; + lockGlobalParams; if (!(list = (GList *)cMapDirs->lookup(collection))) { + unlockGlobalParams; return NULL; } for (i = 0; i < list->getLength(); ++i) { @@ -821,9 +994,11 @@ FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { f = fopen(fileName->getCString(), "r"); delete fileName; if (f) { + unlockGlobalParams; return f; } } + unlockGlobalParams; return NULL; } @@ -832,35 +1007,140 @@ FILE *GlobalParams::findToUnicodeFile(GString *name) { FILE *f; int i; + lockGlobalParams; for (i = 0; i < toUnicodeDirs->getLength(); ++i) { dir = (GString *)toUnicodeDirs->get(i); fileName = appendToPath(dir->copy(), name->getCString()); f = fopen(fileName->getCString(), "r"); delete fileName; if (f) { + unlockGlobalParams; return f; } } + unlockGlobalParams; return NULL; } DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { - return (DisplayFontParam *)displayFonts->lookup(fontName); + DisplayFontParam *dfp; + + lockGlobalParams; + dfp = (DisplayFontParam *)displayFonts->lookup(fontName); + unlockGlobalParams; + return dfp; } DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName, GString *collection) { DisplayFontParam *dfp; + lockGlobalParams; if (!fontName || !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) { dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection); } + unlockGlobalParams; return dfp; } +GString *GlobalParams::getPSFile() { + GString *s; + + lockGlobalParams; + s = psFile ? psFile->copy() : (GString *)NULL; + unlockGlobalParams; + return s; +} + +int GlobalParams::getPSPaperWidth() { + int w; + + lockGlobalParams; + w = psPaperWidth; + unlockGlobalParams; + return w; +} + +int GlobalParams::getPSPaperHeight() { + int h; + + lockGlobalParams; + h = psPaperHeight; + unlockGlobalParams; + return h; +} + +void GlobalParams::getPSImageableArea(int *llx, int *lly, int *urx, int *ury) { + lockGlobalParams; + *llx = psImageableLLX; + *lly = psImageableLLY; + *urx = psImageableURX; + *ury = psImageableURY; + unlockGlobalParams; +} + +GBool GlobalParams::getPSCrop() { + GBool f; + + lockGlobalParams; + f = psCrop; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSExpandSmaller() { + GBool f; + + lockGlobalParams; + f = psExpandSmaller; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSShrinkLarger() { + GBool f; + + lockGlobalParams; + f = psShrinkLarger; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSCenter() { + GBool f; + + lockGlobalParams; + f = psCenter; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSDuplex() { + GBool d; + + lockGlobalParams; + d = psDuplex; + unlockGlobalParams; + return d; +} + +PSLevel GlobalParams::getPSLevel() { + PSLevel level; + + lockGlobalParams; + level = psLevel; + unlockGlobalParams; + return level; +} + PSFontParam *GlobalParams::getPSFont(GString *fontName) { - return (PSFontParam *)psFonts->lookup(fontName); + PSFontParam *p; + + lockGlobalParams; + p = (PSFontParam *)psFonts->lookup(fontName); + unlockGlobalParams; + return p; } PSFontParam *GlobalParams::getPSFont16(GString *fontName, @@ -868,6 +1148,7 @@ PSFontParam *GlobalParams::getPSFont16(GString *fontName, PSFontParam *p; int i; + lockGlobalParams; p = NULL; if (fontName) { for (i = 0; i < psNamedFonts16->getLength(); ++i) { @@ -889,74 +1170,288 @@ PSFontParam *GlobalParams::getPSFont16(GString *fontName, p = NULL; } } + unlockGlobalParams; return p; } -GString *GlobalParams::findFontFile(GString *fontName, - char *ext1, char *ext2) { +GBool GlobalParams::getPSEmbedType1() { + GBool e; + + lockGlobalParams; + e = psEmbedType1; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedTrueType() { + GBool e; + + lockGlobalParams; + e = psEmbedTrueType; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedCIDPostScript() { + GBool e; + + lockGlobalParams; + e = psEmbedCIDPostScript; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedCIDTrueType() { + GBool e; + + lockGlobalParams; + e = psEmbedCIDTrueType; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSOPI() { + GBool opi; + + lockGlobalParams; + opi = psOPI; + unlockGlobalParams; + return opi; +} + +GBool GlobalParams::getPSASCIIHex() { + GBool ah; + + lockGlobalParams; + ah = psASCIIHex; + unlockGlobalParams; + return ah; +} + +GString *GlobalParams::getTextEncodingName() { + GString *s; + + lockGlobalParams; + s = textEncoding->copy(); + unlockGlobalParams; + return s; +} + +EndOfLineKind GlobalParams::getTextEOL() { + EndOfLineKind eol; + + lockGlobalParams; + eol = textEOL; + unlockGlobalParams; + return eol; +} + +GBool GlobalParams::getTextPageBreaks() { + GBool pageBreaks; + + lockGlobalParams; + pageBreaks = textPageBreaks; + unlockGlobalParams; + return pageBreaks; +} + +GBool GlobalParams::getTextKeepTinyChars() { + GBool tiny; + + lockGlobalParams; + tiny = textKeepTinyChars; + unlockGlobalParams; + return tiny; +} + +GString *GlobalParams::findFontFile(GString *fontName, char **exts) { GString *dir, *fileName; + char **ext; FILE *f; int i; + lockGlobalParams; for (i = 0; i < fontDirs->getLength(); ++i) { dir = (GString *)fontDirs->get(i); - if (ext1) { - fileName = appendToPath(dir->copy(), fontName->getCString()); - fileName->append(ext1); - if ((f = fopen(fileName->getCString(), "r"))) { - fclose(f); - return fileName; - } - delete fileName; - } - if (ext2) { + for (ext = exts; *ext; ++ext) { fileName = appendToPath(dir->copy(), fontName->getCString()); - fileName->append(ext2); - if ((f = fopen(fileName->getCString(), "r"))) { + fileName->append(*ext); + if ((f = fopen(fileName->getCString(), "rb"))) { fclose(f); + unlockGlobalParams; return fileName; } delete fileName; } } + unlockGlobalParams; return NULL; } +GString *GlobalParams::getInitialZoom() { + GString *s; + + lockGlobalParams; + s = initialZoom->copy(); + unlockGlobalParams; + return s; +} + +GBool GlobalParams::getEnableT1lib() { + GBool f; + + lockGlobalParams; + f = enableT1lib; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getEnableFreeType() { + GBool f; + + lockGlobalParams; + f = enableFreeType; + unlockGlobalParams; + return f; +} + + +GBool GlobalParams::getAntialias() { + GBool f; + + lockGlobalParams; + f = antialias; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getMapNumericCharNames() { + GBool map; + + lockGlobalParams; + map = mapNumericCharNames; + unlockGlobalParams; + return map; +} + +GBool GlobalParams::getPrintCommands() { + GBool p; + + lockGlobalParams; + p = printCommands; + unlockGlobalParams; + return p; +} + +GBool GlobalParams::getErrQuiet() { + GBool q; + + lockGlobalParams; + q = errQuiet; + unlockGlobalParams; + return q; +} + CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) { - return cidToUnicodeCache->getCIDToUnicode(collection); + GString *fileName; + CharCodeToUnicode *ctu; + + lockGlobalParams; + if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) { + if ((fileName = (GString *)cidToUnicodes->lookup(collection)) && + (ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) { + cidToUnicodeCache->add(ctu); + } + } + unlockGlobalParams; + return ctu; +} + +CharCodeToUnicode *GlobalParams::getUnicodeToUnicode(GString *fontName) { + CharCodeToUnicode *ctu; + GHashIter *iter; + GString *fontPattern, *fileName; + + lockGlobalParams; + fileName = NULL; + unicodeToUnicodes->startIter(&iter); + while (unicodeToUnicodes->getNext(&iter, &fontPattern, (void **)&fileName)) { + if (strstr(fontName->getCString(), fontPattern->getCString())) { + unicodeToUnicodes->killIter(&iter); + break; + } + fileName = NULL; + } + if (fileName) { + if (!(ctu = unicodeToUnicodeCache->getCharCodeToUnicode(fileName))) { + if ((ctu = CharCodeToUnicode::parseUnicodeToUnicode(fileName))) { + unicodeToUnicodeCache->add(ctu); + } + } + } else { + ctu = NULL; + } + unlockGlobalParams; + return ctu; } UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) { + return getUnicodeMap2(encodingName); +} + +UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) { UnicodeMap *map; - if ((map = getResidentUnicodeMap(encodingName))) { - map->incRefCnt(); - return map; + if (!(map = getResidentUnicodeMap(encodingName))) { + lockUnicodeMapCache; + map = unicodeMapCache->getUnicodeMap(encodingName); + unlockUnicodeMapCache; } - return unicodeMapCache->getUnicodeMap(encodingName); + return map; } CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) { - return cMapCache->getCMap(collection, cMapName); + CMap *cMap; + + lockCMapCache; + cMap = cMapCache->getCMap(collection, cMapName); + unlockCMapCache; + return cMap; } UnicodeMap *GlobalParams::getTextEncoding() { - return getUnicodeMap(textEncoding); + return getUnicodeMap2(textEncoding); } //------------------------------------------------------------------------ // functions to set parameters //------------------------------------------------------------------------ +void GlobalParams::addDisplayFont(DisplayFontParam *param) { + DisplayFontParam *old; + + lockGlobalParams; + if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) { + delete old; + } + displayFonts->add(param->name, param); + unlockGlobalParams; +} + void GlobalParams::setPSFile(char *file) { + lockGlobalParams; if (psFile) { delete psFile; } psFile = new GString(file); + unlockGlobalParams; } GBool GlobalParams::setPSPaperSize(char *size) { - if (!strcmp(size, "letter")) { + lockGlobalParams; + if (!strcmp(size, "match")) { + psPaperWidth = psPaperHeight = -1; + } else if (!strcmp(size, "letter")) { psPaperWidth = 612; psPaperHeight = 792; } else if (!strcmp(size, "legal")) { @@ -969,57 +1464,122 @@ GBool GlobalParams::setPSPaperSize(char *size) { psPaperWidth = 842; psPaperHeight = 1190; } else { + unlockGlobalParams; return gFalse; } + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + unlockGlobalParams; return gTrue; } void GlobalParams::setPSPaperWidth(int width) { + lockGlobalParams; psPaperWidth = width; + psImageableLLX = 0; + psImageableURX = psPaperWidth; + unlockGlobalParams; } void GlobalParams::setPSPaperHeight(int height) { + lockGlobalParams; psPaperHeight = height; + psImageableLLY = 0; + psImageableURY = psPaperHeight; + unlockGlobalParams; +} + +void GlobalParams::setPSImageableArea(int llx, int lly, int urx, int ury) { + lockGlobalParams; + psImageableLLX = llx; + psImageableLLY = lly; + psImageableURX = urx; + psImageableURY = ury; + unlockGlobalParams; +} + +void GlobalParams::setPSCrop(GBool crop) { + lockGlobalParams; + psCrop = crop; + unlockGlobalParams; +} + +void GlobalParams::setPSExpandSmaller(GBool expand) { + lockGlobalParams; + psExpandSmaller = expand; + unlockGlobalParams; +} + +void GlobalParams::setPSShrinkLarger(GBool shrink) { + lockGlobalParams; + psShrinkLarger = shrink; + unlockGlobalParams; +} + +void GlobalParams::setPSCenter(GBool center) { + lockGlobalParams; + psCenter = center; + unlockGlobalParams; } void GlobalParams::setPSDuplex(GBool duplex) { + lockGlobalParams; psDuplex = duplex; + unlockGlobalParams; } void GlobalParams::setPSLevel(PSLevel level) { + lockGlobalParams; psLevel = level; + unlockGlobalParams; } void GlobalParams::setPSEmbedType1(GBool embed) { + lockGlobalParams; psEmbedType1 = embed; + unlockGlobalParams; } void GlobalParams::setPSEmbedTrueType(GBool embed) { + lockGlobalParams; psEmbedTrueType = embed; + unlockGlobalParams; } void GlobalParams::setPSEmbedCIDPostScript(GBool embed) { + lockGlobalParams; psEmbedCIDPostScript = embed; + unlockGlobalParams; } void GlobalParams::setPSEmbedCIDTrueType(GBool embed) { + lockGlobalParams; psEmbedCIDTrueType = embed; + unlockGlobalParams; } void GlobalParams::setPSOPI(GBool opi) { + lockGlobalParams; psOPI = opi; + unlockGlobalParams; } void GlobalParams::setPSASCIIHex(GBool hex) { + lockGlobalParams; psASCIIHex = hex; + unlockGlobalParams; } void GlobalParams::setTextEncoding(char *encodingName) { + lockGlobalParams; delete textEncoding; textEncoding = new GString(encodingName); + unlockGlobalParams; } GBool GlobalParams::setTextEOL(char *s) { + lockGlobalParams; if (!strcmp(s, "unix")) { textEOL = eolUnix; } else if (!strcmp(s, "dos")) { @@ -1027,39 +1587,74 @@ GBool GlobalParams::setTextEOL(char *s) { } else if (!strcmp(s, "mac")) { textEOL = eolMac; } else { + unlockGlobalParams; return gFalse; } + unlockGlobalParams; return gTrue; } +void GlobalParams::setTextPageBreaks(GBool pageBreaks) { + lockGlobalParams; + textPageBreaks = pageBreaks; + unlockGlobalParams; +} + +void GlobalParams::setTextKeepTinyChars(GBool keep) { + lockGlobalParams; + textKeepTinyChars = keep; + unlockGlobalParams; +} + void GlobalParams::setInitialZoom(char *s) { + lockGlobalParams; delete initialZoom; initialZoom = new GString(s); + unlockGlobalParams; } -GBool GlobalParams::setT1libControl(char *s) { - return setFontRastControl(&t1libControl, s); +GBool GlobalParams::setEnableT1lib(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &enableT1lib); + unlockGlobalParams; + return ok; } -GBool GlobalParams::setFreeTypeControl(char *s) { - return setFontRastControl(&freetypeControl, s); +GBool GlobalParams::setEnableFreeType(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &enableFreeType); + unlockGlobalParams; + return ok; } -GBool GlobalParams::setFontRastControl(FontRastControl *val, char *s) { - if (!strcmp(s, "none")) { - *val = fontRastNone; - } else if (!strcmp(s, "plain")) { - *val = fontRastPlain; - } else if (!strcmp(s, "low")) { - *val = fontRastAALow; - } else if (!strcmp(s, "high")) { - *val = fontRastAAHigh; - } else { - return gFalse; - } - return gTrue; + +GBool GlobalParams::setAntialias(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &antialias); + unlockGlobalParams; + return ok; +} + +void GlobalParams::setMapNumericCharNames(GBool map) { + lockGlobalParams; + mapNumericCharNames = map; + unlockGlobalParams; +} + +void GlobalParams::setPrintCommands(GBool printCommandsA) { + lockGlobalParams; + printCommands = printCommandsA; + unlockGlobalParams; } void GlobalParams::setErrQuiet(GBool errQuietA) { + lockGlobalParams; errQuiet = errQuietA; + unlockGlobalParams; } diff --git a/pdf2swf/xpdf/GlobalParams.h b/pdf2swf/xpdf/GlobalParams.h index b651110..93ec06a 100644 --- a/pdf2swf/xpdf/GlobalParams.h +++ b/pdf2swf/xpdf/GlobalParams.h @@ -2,14 +2,16 @@ // // GlobalParams.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GLOBALPARAMS_H #define GLOBALPARAMS_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -17,12 +19,16 @@ #include "gtypes.h" #include "CharTypes.h" +#if MULTITHREADED +#include "GMutex.h" +#endif + class GString; class GList; class GHash; class NameToCharCode; class CharCodeToUnicode; -class CIDToUnicodeCache; +class CharCodeToUnicodeCache; class UnicodeMap; class UnicodeMapCache; class CMap; @@ -37,7 +43,6 @@ extern GlobalParams *globalParams; //------------------------------------------------------------------------ enum DisplayFontParamKind { - displayFontX, displayFontT1, displayFontTT }; @@ -51,10 +56,6 @@ public: DisplayFontParamKind kind; union { struct { - GString *xlfd; - GString *encoding; - } x; - struct { GString *fileName; } t1; struct { @@ -63,18 +64,9 @@ public: }; DisplayFontParam(GString *nameA, DisplayFontParamKind kindA); - DisplayFontParam(char *nameA, char *xlfdA, char *encodingA); ~DisplayFontParam(); }; -// Font rasterizer control. -enum FontRastControl { - fontRastNone, // don't use this rasterizer - fontRastPlain, // use it, without anti-aliasing - fontRastAALow, // use it, with low-level anti-aliasing - fontRastAAHigh // use it, with high-level anti-aliasing -}; - //------------------------------------------------------------------------ class PSFontParam { @@ -123,53 +115,71 @@ public: ~GlobalParams(); + void setupBaseFonts(char *dir); + //----- accessors CharCode getMacRomanCharCode(char *charName); Unicode mapNameToUnicode(char *charName); - FILE *getCIDToUnicodeFile(GString *collection); UnicodeMap *getResidentUnicodeMap(GString *encodingName); FILE *getUnicodeMapFile(GString *encodingName); FILE *findCMapFile(GString *collection, GString *cMapName); FILE *findToUnicodeFile(GString *name); DisplayFontParam *getDisplayFont(GString *fontName); DisplayFontParam *getDisplayCIDFont(GString *fontName, GString *collection); - GString *getPSFile() { return psFile; } - int getPSPaperWidth() { return psPaperWidth; } - int getPSPaperHeight() { return psPaperHeight; } - GBool getPSDuplex() { return psDuplex; } - PSLevel getPSLevel() { return psLevel; } + GString *getPSFile(); + int getPSPaperWidth(); + int getPSPaperHeight(); + void getPSImageableArea(int *llx, int *lly, int *urx, int *ury); + GBool getPSDuplex(); + GBool getPSCrop(); + GBool getPSExpandSmaller(); + GBool getPSShrinkLarger(); + GBool getPSCenter(); + PSLevel getPSLevel(); PSFontParam *getPSFont(GString *fontName); PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode); - GBool getPSEmbedType1() { return psEmbedType1; } - GBool getPSEmbedTrueType() { return psEmbedTrueType; } - GBool getPSEmbedCIDPostScript() { return psEmbedCIDPostScript; } - GBool getPSEmbedCIDTrueType() { return psEmbedCIDTrueType; } - GBool getPSOPI() { return psOPI; } - GBool getPSASCIIHex() { return psASCIIHex; } - GString *getTextEncodingName() { return textEncoding; } - EndOfLineKind getTextEOL() { return textEOL; } - GString *findFontFile(GString *fontName, char *ext1, char *ext2); - GString *getInitialZoom() { return initialZoom; } - FontRastControl getT1libControl() { return t1libControl; } - FontRastControl getFreeTypeControl() { return freetypeControl; } + GBool getPSEmbedType1(); + GBool getPSEmbedTrueType(); + GBool getPSEmbedCIDPostScript(); + GBool getPSEmbedCIDTrueType(); + GBool getPSOPI(); + GBool getPSASCIIHex(); + GString *getTextEncodingName(); + EndOfLineKind getTextEOL(); + GBool getTextPageBreaks(); + GBool getTextKeepTinyChars(); + GString *findFontFile(GString *fontName, char **exts); + GString *getInitialZoom(); + GBool getEnableT1lib(); + GBool getEnableFreeType(); + GBool getAntialias(); GString *getURLCommand() { return urlCommand; } - GBool getMapNumericCharNames() { return mapNumericCharNames; } - GBool getErrQuiet() { return errQuiet; } + GString *getMovieCommand() { return movieCommand; } + GBool getMapNumericCharNames(); + GBool getPrintCommands(); + GBool getErrQuiet(); CharCodeToUnicode *getCIDToUnicode(GString *collection); + CharCodeToUnicode *getUnicodeToUnicode(GString *fontName); UnicodeMap *getUnicodeMap(GString *encodingName); CMap *getCMap(GString *collection, GString *cMapName); UnicodeMap *getTextEncoding(); //----- functions to set parameters + void addDisplayFont(DisplayFontParam *param); void setPSFile(char *file); GBool setPSPaperSize(char *size); void setPSPaperWidth(int width); void setPSPaperHeight(int height); + void setPSImageableArea(int llx, int lly, int urx, int ury); void setPSDuplex(GBool duplex); + void setPSCrop(GBool crop); + void setPSExpandSmaller(GBool expand); + void setPSShrinkLarger(GBool shrink); + void setPSCenter(GBool center); void setPSLevel(PSLevel level); void setPSEmbedType1(GBool embed); void setPSEmbedTrueType(GBool embed); @@ -179,9 +189,14 @@ public: void setPSASCIIHex(GBool hex); void setTextEncoding(char *encodingName); GBool setTextEOL(char *s); + void setTextPageBreaks(GBool pageBreaks); + void setTextKeepTinyChars(GBool keep); void setInitialZoom(char *s); - GBool setT1libControl(char *s); - GBool setFreeTypeControl(char *s); + GBool setEnableT1lib(char *s); + GBool setEnableFreeType(char *s); + GBool setAntialias(char *s); + void setMapNumericCharNames(GBool map); + void setPrintCommands(GBool printCommandsA); void setErrQuiet(GBool errQuietA); private: @@ -189,6 +204,7 @@ private: void parseFile(GString *fileName, FILE *f); void parseNameToUnicode(GList *tokens, GString *fileName, int line); void parseCIDToUnicode(GList *tokens, GString *fileName, int line); + void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line); void parseUnicodeMap(GList *tokens, GString *fileName, int line); void parseCMapDir(GList *tokens, GString *fileName, int line); void parseToUnicodeDir(GList *tokens, GString *fileName, int line); @@ -197,6 +213,7 @@ private: GString *fileName, int line); void parsePSFile(GList *tokens, GString *fileName, int line); void parsePSPaperSize(GList *tokens, GString *fileName, int line); + void parsePSImageableArea(GList *tokens, GString *fileName, int line); void parsePSLevel(GList *tokens, GString *fileName, int line); void parsePSFont(GList *tokens, GString *fileName, int line); void parsePSFont16(char *cmdName, GList *fontList, @@ -205,12 +222,12 @@ private: void parseTextEOL(GList *tokens, GString *fileName, int line); void parseFontDir(GList *tokens, GString *fileName, int line); void parseInitialZoom(GList *tokens, GString *fileName, int line); - void parseFontRastControl(char *cmdName, FontRastControl *val, - GList *tokens, GString *fileName, int line); - void parseURLCommand(GList *tokens, GString *fileName, int line); + void parseCommand(char *cmdName, GString **val, + GList *tokens, GString *fileName, int line); void parseYesNo(char *cmdName, GBool *flag, GList *tokens, GString *fileName, int line); - GBool setFontRastControl(FontRastControl *val, char *s); + GBool parseYesNo2(char *token, GBool *flag); + UnicodeMap *getUnicodeMap2(GString *encodingName); //----- static tables @@ -224,6 +241,8 @@ private: GHash *cidToUnicodes; // files for mappings from char collections // to Unicode, indexed by collection name // [GString] + GHash *unicodeToUnicodes; // files for Unicode-to-Unicode mappings, + // indexed by font name pattern [GString] GHash *residentUnicodeMaps; // mappings from Unicode to char codes, // indexed by encoding name [UnicodeMap] GHash *unicodeMaps; // files for mappings from Unicode to char @@ -240,6 +259,14 @@ private: GString *psFile; // PostScript file or command (for xpdf) int psPaperWidth; // paper size, in PostScript points, for int psPaperHeight; // PostScript output + int psImageableLLX, // imageable area, in PostScript points, + psImageableLLY, // for PostScript output + psImageableURX, + psImageableURY; + GBool psCrop; // crop PS output to CropBox + GBool psExpandSmaller; // expand smaller pages to fill paper + GBool psShrinkLarger; // shrink larger pages to fit paper + GBool psCenter; // center pages on the paper GBool psDuplex; // enable duplexing in PostScript? PSLevel psLevel; // PostScript level to generate GHash *psFonts; // PostScript font info, indexed by PDF @@ -256,18 +283,29 @@ private: // output EndOfLineKind textEOL; // type of EOL marker to use for text // output + GBool textPageBreaks; // insert end-of-page markers? + GBool textKeepTinyChars; // keep all characters in text output GList *fontDirs; // list of font dirs [GString] GString *initialZoom; // initial zoom level - FontRastControl t1libControl; // t1lib rasterization mode - FontRastControl // FreeType rasterization mode - freetypeControl; + GBool enableT1lib; // t1lib enable flag + GBool enableFreeType; // FreeType enable flag + GBool antialias; // anti-aliasing enable flag GString *urlCommand; // command executed for URL links + GString *movieCommand; // command executed for movie annotations GBool mapNumericCharNames; // map numeric char names (from font subsets)? + GBool printCommands; // print the drawing commands GBool errQuiet; // suppress error messages? - CIDToUnicodeCache *cidToUnicodeCache; + CharCodeToUnicodeCache *cidToUnicodeCache; + CharCodeToUnicodeCache *unicodeToUnicodeCache; UnicodeMapCache *unicodeMapCache; CMapCache *cMapCache; + +#if MULTITHREADED + GMutex mutex; + GMutex unicodeMapCacheMutex; + GMutex cMapCacheMutex; +#endif }; #endif diff --git a/pdf2swf/xpdf/JArithmeticDecoder.cc b/pdf2swf/xpdf/JArithmeticDecoder.cc new file mode 100644 index 0000000..fd29744 --- /dev/null +++ b/pdf2swf/xpdf/JArithmeticDecoder.cc @@ -0,0 +1,300 @@ +//======================================================================== +// +// JArithmeticDecoder.cc +// +// Copyright 2002-2004 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "Object.h" +#include "Stream.h" +#include "JArithmeticDecoder.h" + +//------------------------------------------------------------------------ +// JArithmeticDecoderStates +//------------------------------------------------------------------------ + +JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) { + contextSize = contextSizeA; + cxTab = (Guchar *)gmalloc(contextSize * sizeof(Guchar)); + reset(); +} + +JArithmeticDecoderStats::~JArithmeticDecoderStats() { + gfree(cxTab); +} + +JArithmeticDecoderStats *JArithmeticDecoderStats::copy() { + JArithmeticDecoderStats *stats; + + stats = new JArithmeticDecoderStats(contextSize); + memcpy(stats->cxTab, cxTab, contextSize); + return stats; +} + +void JArithmeticDecoderStats::reset() { + memset(cxTab, 0, contextSize); +} + +void JArithmeticDecoderStats::copyFrom(JArithmeticDecoderStats *stats) { + memcpy(cxTab, stats->cxTab, contextSize); +} + +void JArithmeticDecoderStats::setEntry(Guint cx, int i, int mps) { + cxTab[cx] = (i << 1) + mps; +} + +//------------------------------------------------------------------------ +// JArithmeticDecoder +//------------------------------------------------------------------------ + +Guint JArithmeticDecoder::qeTab[47] = { + 0x56010000, 0x34010000, 0x18010000, 0x0AC10000, + 0x05210000, 0x02210000, 0x56010000, 0x54010000, + 0x48010000, 0x38010000, 0x30010000, 0x24010000, + 0x1C010000, 0x16010000, 0x56010000, 0x54010000, + 0x51010000, 0x48010000, 0x38010000, 0x34010000, + 0x30010000, 0x28010000, 0x24010000, 0x22010000, + 0x1C010000, 0x18010000, 0x16010000, 0x14010000, + 0x12010000, 0x11010000, 0x0AC10000, 0x09C10000, + 0x08A10000, 0x05210000, 0x04410000, 0x02A10000, + 0x02210000, 0x01410000, 0x01110000, 0x00850000, + 0x00490000, 0x00250000, 0x00150000, 0x00090000, + 0x00050000, 0x00010000, 0x56010000 +}; + +int JArithmeticDecoder::nmpsTab[47] = { + 1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46 +}; + +int JArithmeticDecoder::nlpsTab[47] = { + 1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14, + 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46 +}; + +int JArithmeticDecoder::switchTab[47] = { + 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +JArithmeticDecoder::JArithmeticDecoder() { + str = NULL; +} + +JArithmeticDecoder::~JArithmeticDecoder() { + while (dataLen > 0) { + readByte(); + } +} + +inline Guint JArithmeticDecoder::readByte() { + if (dataLen == 0) { + return 0xff; + } + if (dataLen > 0) { + --dataLen; + } + return (Guint)str->getChar() & 0xff; +} + +void JArithmeticDecoder::start() { + buf0 = readByte(); + buf1 = readByte(); + + // INITDEC + c = (buf0 ^ 0xff) << 16; + byteIn(); + c <<= 7; + ct -= 7; + a = 0x80000000; +} + +int JArithmeticDecoder::decodeBit(Guint context, + JArithmeticDecoderStats *stats) { + int bit; + Guint qe; + int iCX, mpsCX; + + iCX = stats->cxTab[context] >> 1; + mpsCX = stats->cxTab[context] & 1; + qe = qeTab[iCX]; + a -= qe; + if (c < a) { + if (a & 0x80000000) { + bit = mpsCX; + } else { + // MPS_EXCHANGE + if (a < qe) { + bit = 1 - mpsCX; + if (switchTab[iCX]) { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); + } else { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; + } + } else { + bit = mpsCX; + stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; + } + // RENORMD + do { + if (ct == 0) { + byteIn(); + } + a <<= 1; + c <<= 1; + --ct; + } while (!(a & 0x80000000)); + } + } else { + c -= a; + // LPS_EXCHANGE + if (a < qe) { + bit = mpsCX; + stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; + } else { + bit = 1 - mpsCX; + if (switchTab[iCX]) { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); + } else { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; + } + } + a = qe; + // RENORMD + do { + if (ct == 0) { + byteIn(); + } + a <<= 1; + c <<= 1; + --ct; + } while (!(a & 0x80000000)); + } + return bit; +} + +int JArithmeticDecoder::decodeByte(Guint context, + JArithmeticDecoderStats *stats) { + int byte; + int i; + + byte = 0; + for (i = 0; i < 8; ++i) { + byte = (byte << 1) | decodeBit(context, stats); + } + return byte; +} + +GBool JArithmeticDecoder::decodeInt(int *x, JArithmeticDecoderStats *stats) { + int s; + Guint v; + int i; + + prev = 1; + s = decodeIntBit(stats); + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + v = 0; + for (i = 0; i < 32; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 4436; + } else { + v = 0; + for (i = 0; i < 12; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 340; + } + } else { + v = 0; + for (i = 0; i < 8; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 84; + } + } else { + v = 0; + for (i = 0; i < 6; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 20; + } + } else { + v = decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v += 4; + } + } else { + v = decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + } + + if (s) { + if (v == 0) { + return gFalse; + } + *x = -(int)v; + } else { + *x = (int)v; + } + return gTrue; +} + +int JArithmeticDecoder::decodeIntBit(JArithmeticDecoderStats *stats) { + int bit; + + bit = decodeBit(prev, stats); + if (prev < 0x100) { + prev = (prev << 1) | bit; + } else { + prev = (((prev << 1) | bit) & 0x1ff) | 0x100; + } + return bit; +} + +Guint JArithmeticDecoder::decodeIAID(Guint codeLen, + JArithmeticDecoderStats *stats) { + Guint i; + int bit; + + prev = 1; + for (i = 0; i < codeLen; ++i) { + bit = decodeBit(prev, stats); + prev = (prev << 1) | bit; + } + return prev - (1 << codeLen); +} + +void JArithmeticDecoder::byteIn() { + if (buf0 == 0xff) { + if (buf1 > 0x8f) { + ct = 8; + } else { + buf0 = buf1; + buf1 = readByte(); + c = c + 0xfe00 - (buf0 << 9); + ct = 7; + } + } else { + buf0 = buf1; + buf1 = readByte(); + c = c + 0xff00 - (buf0 << 8); + ct = 8; + } +} diff --git a/pdf2swf/xpdf/JArithmeticDecoder.h b/pdf2swf/xpdf/JArithmeticDecoder.h new file mode 100644 index 0000000..a348017 --- /dev/null +++ b/pdf2swf/xpdf/JArithmeticDecoder.h @@ -0,0 +1,91 @@ +//======================================================================== +// +// JArithmeticDecoder.h +// +// Arithmetic decoder used by the JBIG2 and JPEG2000 decoders. +// +// Copyright 2002-2004 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JARITHMETICDECODER_H +#define JARITHMETICDECODER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class Stream; + +//------------------------------------------------------------------------ +// JArithmeticDecoderStats +//------------------------------------------------------------------------ + +class JArithmeticDecoderStats { +public: + + JArithmeticDecoderStats(int contextSizeA); + ~JArithmeticDecoderStats(); + JArithmeticDecoderStats *copy(); + void reset(); + int getContextSize() { return contextSize; } + void copyFrom(JArithmeticDecoderStats *stats); + void setEntry(Guint cx, int i, int mps); + +private: + + Guchar *cxTab; // cxTab[cx] = (i[cx] << 1) + mps[cx] + int contextSize; + + friend class JArithmeticDecoder; +}; + +//------------------------------------------------------------------------ +// JArithmeticDecoder +//------------------------------------------------------------------------ + +class JArithmeticDecoder { +public: + + JArithmeticDecoder(); + ~JArithmeticDecoder(); + void setStream(Stream *strA) + { str = strA; dataLen = -1; } + void setStream(Stream *strA, int dataLenA) + { str = strA; dataLen = dataLenA; } + void start(); + int decodeBit(Guint context, JArithmeticDecoderStats *stats); + int decodeByte(Guint context, JArithmeticDecoderStats *stats); + + // Returns false for OOB, otherwise sets * and returns true. + GBool decodeInt(int *x, JArithmeticDecoderStats *stats); + + Guint decodeIAID(Guint codeLen, + JArithmeticDecoderStats *stats); + +private: + + Guint readByte(); + int decodeIntBit(JArithmeticDecoderStats *stats); + void byteIn(); + + static Guint qeTab[47]; + static int nmpsTab[47]; + static int nlpsTab[47]; + static int switchTab[47]; + + Guint buf0, buf1; + Guint c, a; + int ct; + + Guint prev; // for the integer decoder + + Stream *str; + int dataLen; +}; + +#endif diff --git a/pdf2swf/xpdf/JBIG2Stream.cc b/pdf2swf/xpdf/JBIG2Stream.cc new file mode 100644 index 0000000..c1bf4f7 --- /dev/null +++ b/pdf2swf/xpdf/JBIG2Stream.cc @@ -0,0 +1,3337 @@ +//======================================================================== +// +// JBIG2Stream.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "GList.h" +#include "Error.h" +#include "JArithmeticDecoder.h" +#include "JBIG2Stream.h" + +//~ share these tables +#include "Stream-CCITT.h" + +//------------------------------------------------------------------------ + +static int contextSize[4] = { 16, 13, 10, 10 }; +static int refContextSize[2] = { 13, 10 }; + +//------------------------------------------------------------------------ +// JBIG2HuffmanTable +//------------------------------------------------------------------------ + +#define jbig2HuffmanLOW 0xfffffffd +#define jbig2HuffmanOOB 0xfffffffe +#define jbig2HuffmanEOT 0xffffffff + +struct JBIG2HuffmanTable { + int val; + Guint prefixLen; + Guint rangeLen; // can also be LOW, OOB, or EOT + Guint prefix; +}; + +JBIG2HuffmanTable huffTableA[] = { + { 0, 1, 4, 0x000 }, + { 16, 2, 8, 0x002 }, + { 272, 3, 16, 0x006 }, + { 65808, 3, 32, 0x007 }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableB[] = { + { 0, 1, 0, 0x000 }, + { 1, 2, 0, 0x002 }, + { 2, 3, 0, 0x006 }, + { 3, 4, 3, 0x00e }, + { 11, 5, 6, 0x01e }, + { 75, 6, 32, 0x03e }, + { 0, 6, jbig2HuffmanOOB, 0x03f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableC[] = { + { 0, 1, 0, 0x000 }, + { 1, 2, 0, 0x002 }, + { 2, 3, 0, 0x006 }, + { 3, 4, 3, 0x00e }, + { 11, 5, 6, 0x01e }, + { 0, 6, jbig2HuffmanOOB, 0x03e }, + { 75, 7, 32, 0x0fe }, + { -256, 8, 8, 0x0fe }, + { -257, 8, jbig2HuffmanLOW, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableD[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 0, 0x006 }, + { 4, 4, 3, 0x00e }, + { 12, 5, 6, 0x01e }, + { 76, 5, 32, 0x01f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableE[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 0, 0x006 }, + { 4, 4, 3, 0x00e }, + { 12, 5, 6, 0x01e }, + { 76, 6, 32, 0x03e }, + { -255, 7, 8, 0x07e }, + { -256, 7, jbig2HuffmanLOW, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableF[] = { + { 0, 2, 7, 0x000 }, + { 128, 3, 7, 0x002 }, + { 256, 3, 8, 0x003 }, + { -1024, 4, 9, 0x008 }, + { -512, 4, 8, 0x009 }, + { -256, 4, 7, 0x00a }, + { -32, 4, 5, 0x00b }, + { 512, 4, 9, 0x00c }, + { 1024, 4, 10, 0x00d }, + { -2048, 5, 10, 0x01c }, + { -128, 5, 6, 0x01d }, + { -64, 5, 5, 0x01e }, + { -2049, 6, jbig2HuffmanLOW, 0x03e }, + { 2048, 6, 32, 0x03f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableG[] = { + { -512, 3, 8, 0x000 }, + { 256, 3, 8, 0x001 }, + { 512, 3, 9, 0x002 }, + { 1024, 3, 10, 0x003 }, + { -1024, 4, 9, 0x008 }, + { -256, 4, 7, 0x009 }, + { -32, 4, 5, 0x00a }, + { 0, 4, 5, 0x00b }, + { 128, 4, 7, 0x00c }, + { -128, 5, 6, 0x01a }, + { -64, 5, 5, 0x01b }, + { 32, 5, 5, 0x01c }, + { 64, 5, 6, 0x01d }, + { -1025, 5, jbig2HuffmanLOW, 0x01e }, + { 2048, 5, 32, 0x01f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableH[] = { + { 0, 2, 1, 0x000 }, + { 0, 2, jbig2HuffmanOOB, 0x001 }, + { 4, 3, 4, 0x004 }, + { -1, 4, 0, 0x00a }, + { 22, 4, 4, 0x00b }, + { 38, 4, 5, 0x00c }, + { 2, 5, 0, 0x01a }, + { 70, 5, 6, 0x01b }, + { 134, 5, 7, 0x01c }, + { 3, 6, 0, 0x03a }, + { 20, 6, 1, 0x03b }, + { 262, 6, 7, 0x03c }, + { 646, 6, 10, 0x03d }, + { -2, 7, 0, 0x07c }, + { 390, 7, 8, 0x07d }, + { -15, 8, 3, 0x0fc }, + { -5, 8, 1, 0x0fd }, + { -7, 9, 1, 0x1fc }, + { -3, 9, 0, 0x1fd }, + { -16, 9, jbig2HuffmanLOW, 0x1fe }, + { 1670, 9, 32, 0x1ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableI[] = { + { 0, 2, jbig2HuffmanOOB, 0x000 }, + { -1, 3, 1, 0x002 }, + { 1, 3, 1, 0x003 }, + { 7, 3, 5, 0x004 }, + { -3, 4, 1, 0x00a }, + { 43, 4, 5, 0x00b }, + { 75, 4, 6, 0x00c }, + { 3, 5, 1, 0x01a }, + { 139, 5, 7, 0x01b }, + { 267, 5, 8, 0x01c }, + { 5, 6, 1, 0x03a }, + { 39, 6, 2, 0x03b }, + { 523, 6, 8, 0x03c }, + { 1291, 6, 11, 0x03d }, + { -5, 7, 1, 0x07c }, + { 779, 7, 9, 0x07d }, + { -31, 8, 4, 0x0fc }, + { -11, 8, 2, 0x0fd }, + { -15, 9, 2, 0x1fc }, + { -7, 9, 1, 0x1fd }, + { -32, 9, jbig2HuffmanLOW, 0x1fe }, + { 3339, 9, 32, 0x1ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableJ[] = { + { -2, 2, 2, 0x000 }, + { 6, 2, 6, 0x001 }, + { 0, 2, jbig2HuffmanOOB, 0x002 }, + { -3, 5, 0, 0x018 }, + { 2, 5, 0, 0x019 }, + { 70, 5, 5, 0x01a }, + { 3, 6, 0, 0x036 }, + { 102, 6, 5, 0x037 }, + { 134, 6, 6, 0x038 }, + { 198, 6, 7, 0x039 }, + { 326, 6, 8, 0x03a }, + { 582, 6, 9, 0x03b }, + { 1094, 6, 10, 0x03c }, + { -21, 7, 4, 0x07a }, + { -4, 7, 0, 0x07b }, + { 4, 7, 0, 0x07c }, + { 2118, 7, 11, 0x07d }, + { -5, 8, 0, 0x0fc }, + { 5, 8, 0, 0x0fd }, + { -22, 8, jbig2HuffmanLOW, 0x0fe }, + { 4166, 8, 32, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableK[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 1, 0x002 }, + { 4, 4, 0, 0x00c }, + { 5, 4, 1, 0x00d }, + { 7, 5, 1, 0x01c }, + { 9, 5, 2, 0x01d }, + { 13, 6, 2, 0x03c }, + { 17, 7, 2, 0x07a }, + { 21, 7, 3, 0x07b }, + { 29, 7, 4, 0x07c }, + { 45, 7, 5, 0x07d }, + { 77, 7, 6, 0x07e }, + { 141, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableL[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 1, 0x006 }, + { 5, 5, 0, 0x01c }, + { 6, 5, 1, 0x01d }, + { 8, 6, 1, 0x03c }, + { 10, 7, 0, 0x07a }, + { 11, 7, 1, 0x07b }, + { 13, 7, 2, 0x07c }, + { 17, 7, 3, 0x07d }, + { 25, 7, 4, 0x07e }, + { 41, 8, 5, 0x0fe }, + { 73, 8, 32, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableM[] = { + { 1, 1, 0, 0x000 }, + { 2, 3, 0, 0x004 }, + { 7, 3, 3, 0x005 }, + { 3, 4, 0, 0x00c }, + { 5, 4, 1, 0x00d }, + { 4, 5, 0, 0x01c }, + { 15, 6, 1, 0x03a }, + { 17, 6, 2, 0x03b }, + { 21, 6, 3, 0x03c }, + { 29, 6, 4, 0x03d }, + { 45, 6, 5, 0x03e }, + { 77, 7, 6, 0x07e }, + { 141, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableN[] = { + { 0, 1, 0, 0x000 }, + { -2, 3, 0, 0x004 }, + { -1, 3, 0, 0x005 }, + { 1, 3, 0, 0x006 }, + { 2, 3, 0, 0x007 }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableO[] = { + { 0, 1, 0, 0x000 }, + { -1, 3, 0, 0x004 }, + { 1, 3, 0, 0x005 }, + { -2, 4, 0, 0x00c }, + { 2, 4, 0, 0x00d }, + { -4, 5, 1, 0x01c }, + { 3, 5, 1, 0x01d }, + { -8, 6, 2, 0x03c }, + { 5, 6, 2, 0x03d }, + { -24, 7, 4, 0x07c }, + { 9, 7, 4, 0x07d }, + { -25, 7, jbig2HuffmanLOW, 0x07e }, + { 25, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +//------------------------------------------------------------------------ +// JBIG2HuffmanDecoder +//------------------------------------------------------------------------ + +class JBIG2HuffmanDecoder { +public: + + JBIG2HuffmanDecoder(); + ~JBIG2HuffmanDecoder(); + void setStream(Stream *strA) { str = strA; } + + void reset(); + + // Returns false for OOB, otherwise sets * and returns true. + GBool decodeInt(int *x, JBIG2HuffmanTable *table); + + Guint readBits(Guint n); + Guint readBit(); + + // Sort the table by prefix length and assign prefix values. + void buildTable(JBIG2HuffmanTable *table, Guint len); + +private: + + Stream *str; + Guint buf; + Guint bufLen; +}; + +JBIG2HuffmanDecoder::JBIG2HuffmanDecoder() { + str = NULL; + reset(); +} + +JBIG2HuffmanDecoder::~JBIG2HuffmanDecoder() { +} + +void JBIG2HuffmanDecoder::reset() { + buf = 0; + bufLen = 0; +} + +//~ optimize this +GBool JBIG2HuffmanDecoder::decodeInt(int *x, JBIG2HuffmanTable *table) { + Guint i, len, prefix; + + i = 0; + len = 0; + prefix = 0; + while (table[i].rangeLen != jbig2HuffmanEOT) { + while (len < table[i].prefixLen) { + prefix = (prefix << 1) | readBit(); + ++len; + } + if (prefix == table[i].prefix) { + if (table[i].rangeLen == jbig2HuffmanOOB) { + return gFalse; + } + if (table[i].rangeLen == jbig2HuffmanLOW) { + *x = table[i].val - readBits(32); + } else if (table[i].rangeLen > 0) { + *x = table[i].val + readBits(table[i].rangeLen); + } else { + *x = table[i].val; + } + return gTrue; + } + ++i; + } + return gFalse; +} + +Guint JBIG2HuffmanDecoder::readBits(Guint n) { + Guint x, mask, nLeft; + + mask = (n == 32) ? 0xffffffff : ((1 << n) - 1); + if (bufLen >= n) { + x = (buf >> (bufLen - n)) & mask; + bufLen -= n; + } else { + x = buf & ((1 << bufLen) - 1); + nLeft = n - bufLen; + bufLen = 0; + while (nLeft >= 8) { + x = (x << 8) | (str->getChar() & 0xff); + nLeft -= 8; + } + if (nLeft > 0) { + buf = str->getChar(); + bufLen = 8 - nLeft; + x = (x << nLeft) | ((buf >> bufLen) & ((1 << nLeft) - 1)); + } + } + return x; +} + +Guint JBIG2HuffmanDecoder::readBit() { + if (bufLen == 0) { + buf = str->getChar(); + bufLen = 8; + } + --bufLen; + return (buf >> bufLen) & 1; +} + +void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) { + Guint i, j, k, prefix; + JBIG2HuffmanTable tab; + + // stable selection sort: + // - entries with prefixLen > 0, in ascending prefixLen order + // - entry with prefixLen = 0, rangeLen = EOT + // - all other entries with prefixLen = 0 + // (on entry, table[len] has prefixLen = 0, rangeLen = EOT) + for (i = 0; i < len; ++i) { + for (j = i; j < len && table[j].prefixLen == 0; ++j) ; + if (j == len) { + break; + } + for (k = j + 1; k < len; ++k) { + if (table[k].prefixLen > 0 && + table[k].prefixLen < table[j].prefixLen) { + j = k; + } + } + if (j != i) { + tab = table[j]; + for (k = j; k > i; --k) { + table[k] = table[k - 1]; + } + table[i] = tab; + } + } + table[i] = table[len]; + + // assign prefixes + i = 0; + prefix = 0; + table[i++].prefix = prefix++; + for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) { + prefix <<= table[i].prefixLen - table[i-1].prefixLen; + table[i].prefix = prefix++; + } +} + +//------------------------------------------------------------------------ +// JBIG2MMRDecoder +//------------------------------------------------------------------------ + +class JBIG2MMRDecoder { +public: + + JBIG2MMRDecoder(); + ~JBIG2MMRDecoder(); + void setStream(Stream *strA) { str = strA; } + void reset(); + int get2DCode(); + int getBlackCode(); + int getWhiteCode(); + Guint get24Bits(); + void skipTo(Guint length); + +private: + + Stream *str; + Guint buf; + Guint bufLen; + Guint nBytesRead; +}; + +JBIG2MMRDecoder::JBIG2MMRDecoder() { + str = NULL; + reset(); +} + +JBIG2MMRDecoder::~JBIG2MMRDecoder() { +} + +void JBIG2MMRDecoder::reset() { + buf = 0; + bufLen = 0; + nBytesRead = 0; +} + +int JBIG2MMRDecoder::get2DCode() { + CCITTCode *p; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + p = &twoDimTab1[(buf >> 1) & 0x7f]; + } else if (bufLen == 8) { + p = &twoDimTab1[(buf >> 1) & 0x7f]; + } else { + p = &twoDimTab1[(buf << (7 - bufLen)) & 0x7f]; + if (p->bits < 0 || p->bits > (int)bufLen) { + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + p = &twoDimTab1[(buf >> (bufLen - 7)) & 0x7f]; + } + } + if (p->bits < 0) { + error(str->getPos(), "Bad two dim code in JBIG2 MMR stream"); + return 0; + } + bufLen -= p->bits; + return p->n; +} + +int JBIG2MMRDecoder::getWhiteCode() { + CCITTCode *p; + Guint code; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + } + while (1) { + if (bufLen >= 7 && ((buf >> (bufLen - 7)) & 0x7f) == 0) { + if (bufLen <= 12) { + code = buf << (12 - bufLen); + } else { + code = buf >> (bufLen - 12); + } + p = &whiteTab1[code & 0x1f]; + } else { + if (bufLen <= 9) { + code = buf << (9 - bufLen); + } else { + code = buf >> (bufLen - 9); + } + p = &whiteTab2[code & 0x1ff]; + } + if (p->bits > 0 && p->bits <= (int)bufLen) { + bufLen -= p->bits; + return p->n; + } + if (bufLen >= 12) { + break; + } + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + error(str->getPos(), "Bad white code in JBIG2 MMR stream"); + // eat a bit and return a positive number so that the caller doesn't + // go into an infinite loop + --bufLen; + return 1; +} + +int JBIG2MMRDecoder::getBlackCode() { + CCITTCode *p; + Guint code; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + } + while (1) { + if (bufLen >= 6 && ((buf >> (bufLen - 6)) & 0x3f) == 0) { + if (bufLen <= 13) { + code = buf << (13 - bufLen); + } else { + code = buf >> (bufLen - 13); + } + p = &blackTab1[code & 0x7f]; + } else if (bufLen >= 4 && ((buf >> (bufLen - 4)) & 0x0f) == 0) { + if (bufLen <= 12) { + code = buf << (12 - bufLen); + } else { + code = buf >> (bufLen - 12); + } + p = &blackTab2[(code & 0xff) - 64]; + } else { + if (bufLen <= 6) { + code = buf << (6 - bufLen); + } else { + code = buf >> (bufLen - 6); + } + p = &blackTab3[code & 0x3f]; + } + if (p->bits > 0 && p->bits <= (int)bufLen) { + bufLen -= p->bits; + return p->n; + } + if (bufLen >= 13) { + break; + } + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + error(str->getPos(), "Bad black code in JBIG2 MMR stream"); + // eat a bit and return a positive number so that the caller doesn't + // go into an infinite loop + --bufLen; + return 1; +} + +Guint JBIG2MMRDecoder::get24Bits() { + while (bufLen < 24) { + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + return (buf >> (bufLen - 24)) & 0xffffff; +} + +void JBIG2MMRDecoder::skipTo(Guint length) { + while (nBytesRead < length) { + str->getChar(); + ++nBytesRead; + } +} + +//------------------------------------------------------------------------ +// JBIG2Segment +//------------------------------------------------------------------------ + +enum JBIG2SegmentType { + jbig2SegBitmap, + jbig2SegSymbolDict, + jbig2SegPatternDict, + jbig2SegCodeTable +}; + +class JBIG2Segment { +public: + + JBIG2Segment(Guint segNumA) { segNum = segNumA; } + virtual ~JBIG2Segment() {} + void setSegNum(Guint segNumA) { segNum = segNumA; } + Guint getSegNum() { return segNum; } + virtual JBIG2SegmentType getType() = 0; + +private: + + Guint segNum; +}; + +//------------------------------------------------------------------------ +// JBIG2Bitmap +//------------------------------------------------------------------------ + +struct JBIG2BitmapPtr { + Guchar *p; + int shift; + int x; +}; + +class JBIG2Bitmap: public JBIG2Segment { +public: + + JBIG2Bitmap(Guint segNumA, int wA, int hA); + virtual ~JBIG2Bitmap(); + virtual JBIG2SegmentType getType() { return jbig2SegBitmap; } + JBIG2Bitmap *copy() { return new JBIG2Bitmap(0, this); } + JBIG2Bitmap *getSlice(Guint x, Guint y, Guint wA, Guint hA); + void expand(int newH, Guint pixel); + void clearToZero(); + void clearToOne(); + int getWidth() { return w; } + int getHeight() { return h; } + int getPixel(int x, int y) + { return (x < 0 || x >= w || y < 0 || y >= h) ? 0 : + (data[y * line + (x >> 3)] >> (7 - (x & 7))) & 1; } + void setPixel(int x, int y) + { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); } + void clearPixel(int x, int y) + { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); } + void getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr); + int nextPixel(JBIG2BitmapPtr *ptr); + void duplicateRow(int yDest, int ySrc); + void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp); + Guchar *getDataPtr() { return data; } + int getDataSize() { return h * line; } + +private: + + JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap); + + int w, h, line; + Guchar *data; +}; + +JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): + JBIG2Segment(segNumA) +{ + w = wA; + h = hA; + line = (wA + 7) >> 3; + data = (Guchar *)gmalloc(h * line); +} + +JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): + JBIG2Segment(segNumA) +{ + w = bitmap->w; + h = bitmap->h; + line = bitmap->line; + data = (Guchar *)gmalloc(h * line); + memcpy(data, bitmap->data, h * line); +} + +JBIG2Bitmap::~JBIG2Bitmap() { + gfree(data); +} + +//~ optimize this +JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) { + JBIG2Bitmap *slice; + Guint xx, yy; + + slice = new JBIG2Bitmap(0, wA, hA); + slice->clearToZero(); + for (yy = 0; yy < hA; ++yy) { + for (xx = 0; xx < wA; ++xx) { + if (getPixel(x + xx, y + yy)) { + slice->setPixel(xx, yy); + } + } + } + return slice; +} + +void JBIG2Bitmap::expand(int newH, Guint pixel) { + if (newH <= h) { + return; + } + data = (Guchar *)grealloc(data, newH * line); + if (pixel) { + memset(data + h * line, 0xff, (newH - h) * line); + } else { + memset(data + h * line, 0x00, (newH - h) * line); + } + h = newH; +} + +void JBIG2Bitmap::clearToZero() { + memset(data, 0, h * line); +} + +void JBIG2Bitmap::clearToOne() { + memset(data, 0xff, h * line); +} + +inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) { + if (y < 0 || y >= h || x >= w) { + ptr->p = NULL; + } else if (x < 0) { + ptr->p = &data[y * line]; + ptr->shift = 7; + ptr->x = x; + } else { + ptr->p = &data[y * line + (x >> 3)]; + ptr->shift = 7 - (x & 7); + ptr->x = x; + } +} + +inline int JBIG2Bitmap::nextPixel(JBIG2BitmapPtr *ptr) { + int pix; + + if (!ptr->p) { + pix = 0; + } else if (ptr->x < 0) { + ++ptr->x; + pix = 0; + } else { + pix = (*ptr->p >> ptr->shift) & 1; + if (++ptr->x == w) { + ptr->p = NULL; + } else if (ptr->shift == 0) { + ++ptr->p; + ptr->shift = 7; + } else { + --ptr->shift; + } + } + return pix; +} + +void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) { + memcpy(data + yDest * line, data + ySrc * line, line); +} + +void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y, + Guint combOp) { + int x0, x1, y0, y1, xx, yy; + Guchar *srcPtr, *destPtr; + Guint src0, src1, src, dest, s1, s2, m1, m2, m3; + GBool oneByte; + + if (y < 0) { + y0 = -y; + } else { + y0 = 0; + } + if (y + bitmap->h > h) { + y1 = h - y; + } else { + y1 = bitmap->h; + } + if (y0 >= y1) { + return; + } + + if (x >= 0) { + x0 = x & ~7; + } else { + x0 = 0; + } + x1 = x + bitmap->w; + if (x1 > w) { + x1 = w; + } + if (x0 >= x1) { + return; + } + + s1 = x & 7; + s2 = 8 - s1; + m1 = 0xff >> (x1 & 7); + m2 = 0xff << (((x1 & 7) == 0) ? 0 : 8 - (x1 & 7)); + m3 = (0xff >> s1) & m2; + + oneByte = x0 == ((x1 - 1) & ~7); + + for (yy = y0; yy < y1; ++yy) { + + // one byte per line -- need to mask both left and right side + if (oneByte) { + if (x >= 0) { + destPtr = data + (y + yy) * line + (x >> 3); + srcPtr = bitmap->data + yy * bitmap->line; + dest = *destPtr; + src1 = *srcPtr; + switch (combOp) { + case 0: // or + dest |= (src1 >> s1) & m2; + break; + case 1: // and + dest &= ((0xff00 | src1) >> s1) | m1; + break; + case 2: // xor + dest ^= (src1 >> s1) & m2; + break; + case 3: // xnor + dest ^= ((src1 ^ 0xff) >> s1) & m2; + break; + case 4: // replace + dest = (dest & ~m3) | ((src1 >> s1) & m3); + break; + } + *destPtr = dest; + } else { + destPtr = data + (y + yy) * line; + srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); + dest = *destPtr; + src1 = *srcPtr; + switch (combOp) { + case 0: // or + dest |= src1 & m2; + break; + case 1: // and + dest &= src1 | m1; + break; + case 2: // xor + dest ^= src1 & m2; + break; + case 3: // xnor + dest ^= (src1 ^ 0xff) & m2; + break; + case 4: // replace + dest = (src1 & m2) | (dest & m1); + break; + } + *destPtr = dest; + } + + // multiple bytes per line -- need to mask left side of left-most + // byte and right side of right-most byte + } else { + + // left-most byte + if (x >= 0) { + destPtr = data + (y + yy) * line + (x >> 3); + srcPtr = bitmap->data + yy * bitmap->line; + src1 = *srcPtr++; + dest = *destPtr; + switch (combOp) { + case 0: // or + dest |= src1 >> s1; + break; + case 1: // and + dest &= (0xff00 | src1) >> s1; + break; + case 2: // xor + dest ^= src1 >> s1; + break; + case 3: // xnor + dest ^= (src1 ^ 0xff) >> s1; + break; + case 4: // replace + dest = (dest & (0xff << s2)) | (src1 >> s1); + break; + } + *destPtr++ = dest; + xx = x0 + 8; + } else { + destPtr = data + (y + yy) * line; + srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); + src1 = *srcPtr++; + xx = x0; + } + + // middle bytes + for (; xx < x1 - 8; xx += 8) { + dest = *destPtr; + src0 = src1; + src1 = *srcPtr++; + src = (((src0 << 8) | src1) >> s1) & 0xff; + switch (combOp) { + case 0: // or + dest |= src; + break; + case 1: // and + dest &= src; + break; + case 2: // xor + dest ^= src; + break; + case 3: // xnor + dest ^= src ^ 0xff; + break; + case 4: // replace + dest = src; + break; + } + *destPtr++ = dest; + } + + // right-most byte + dest = *destPtr; + src0 = src1; + src1 = *srcPtr++; + src = (((src0 << 8) | src1) >> s1) & 0xff; + switch (combOp) { + case 0: // or + dest |= src & m2; + break; + case 1: // and + dest &= src | m1; + break; + case 2: // xor + dest ^= src & m2; + break; + case 3: // xnor + dest ^= (src ^ 0xff) & m2; + break; + case 4: // replace + dest = (src & m2) | (dest & m1); + break; + } + *destPtr = dest; + } + } +} + +//------------------------------------------------------------------------ +// JBIG2SymbolDict +//------------------------------------------------------------------------ + +class JBIG2SymbolDict: public JBIG2Segment { +public: + + JBIG2SymbolDict(Guint segNumA, Guint sizeA); + virtual ~JBIG2SymbolDict(); + virtual JBIG2SegmentType getType() { return jbig2SegSymbolDict; } + Guint getSize() { return size; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } + JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } + void setGenericRegionStats(JArithmeticDecoderStats *stats) + { genericRegionStats = stats; } + void setRefinementRegionStats(JArithmeticDecoderStats *stats) + { refinementRegionStats = stats; } + JArithmeticDecoderStats *getGenericRegionStats() + { return genericRegionStats; } + JArithmeticDecoderStats *getRefinementRegionStats() + { return refinementRegionStats; } + +private: + + Guint size; + JBIG2Bitmap **bitmaps; + JArithmeticDecoderStats *genericRegionStats; + JArithmeticDecoderStats *refinementRegionStats; +}; + +JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA): + JBIG2Segment(segNumA) +{ + size = sizeA; + bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *)); + genericRegionStats = NULL; + refinementRegionStats = NULL; +} + +JBIG2SymbolDict::~JBIG2SymbolDict() { + Guint i; + + for (i = 0; i < size; ++i) { + delete bitmaps[i]; + } + gfree(bitmaps); + if (genericRegionStats) { + delete genericRegionStats; + } + if (refinementRegionStats) { + delete refinementRegionStats; + } +} + +//------------------------------------------------------------------------ +// JBIG2PatternDict +//------------------------------------------------------------------------ + +class JBIG2PatternDict: public JBIG2Segment { +public: + + JBIG2PatternDict(Guint segNumA, Guint sizeA); + virtual ~JBIG2PatternDict(); + virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; } + Guint getSize() { return size; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } + JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } + +private: + + Guint size; + JBIG2Bitmap **bitmaps; +}; + +JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): + JBIG2Segment(segNumA) +{ + size = sizeA; + bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *)); +} + +JBIG2PatternDict::~JBIG2PatternDict() { + Guint i; + + for (i = 0; i < size; ++i) { + delete bitmaps[i]; + } + gfree(bitmaps); +} + +//------------------------------------------------------------------------ +// JBIG2CodeTable +//------------------------------------------------------------------------ + +class JBIG2CodeTable: public JBIG2Segment { +public: + + JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA); + virtual ~JBIG2CodeTable(); + virtual JBIG2SegmentType getType() { return jbig2SegCodeTable; } + JBIG2HuffmanTable *getHuffTable() { return table; } + +private: + + JBIG2HuffmanTable *table; +}; + +JBIG2CodeTable::JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA): + JBIG2Segment(segNumA) +{ + table = tableA; +} + +JBIG2CodeTable::~JBIG2CodeTable() { + gfree(table); +} + +//------------------------------------------------------------------------ +// JBIG2Stream +//------------------------------------------------------------------------ + +JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStream): + FilterStream(strA) +{ + pageBitmap = NULL; + + arithDecoder = new JArithmeticDecoder(); + genericRegionStats = new JArithmeticDecoderStats(1 << 1); + refinementRegionStats = new JArithmeticDecoderStats(1 << 1); + iadhStats = new JArithmeticDecoderStats(1 << 9); + iadwStats = new JArithmeticDecoderStats(1 << 9); + iaexStats = new JArithmeticDecoderStats(1 << 9); + iaaiStats = new JArithmeticDecoderStats(1 << 9); + iadtStats = new JArithmeticDecoderStats(1 << 9); + iaitStats = new JArithmeticDecoderStats(1 << 9); + iafsStats = new JArithmeticDecoderStats(1 << 9); + iadsStats = new JArithmeticDecoderStats(1 << 9); + iardxStats = new JArithmeticDecoderStats(1 << 9); + iardyStats = new JArithmeticDecoderStats(1 << 9); + iardwStats = new JArithmeticDecoderStats(1 << 9); + iardhStats = new JArithmeticDecoderStats(1 << 9); + iariStats = new JArithmeticDecoderStats(1 << 9); + iaidStats = new JArithmeticDecoderStats(1 << 1); + huffDecoder = new JBIG2HuffmanDecoder(); + mmrDecoder = new JBIG2MMRDecoder(); + + segments = globalSegments = new GList(); + if (globalsStream->isStream()) { + curStr = globalsStream->getStream(); + curStr->reset(); + arithDecoder->setStream(curStr); + huffDecoder->setStream(curStr); + mmrDecoder->setStream(curStr); + readSegments(); + } + + segments = NULL; + curStr = NULL; + dataPtr = dataEnd = NULL; +} + +JBIG2Stream::~JBIG2Stream() { + delete arithDecoder; + delete genericRegionStats; + delete refinementRegionStats; + delete iadhStats; + delete iadwStats; + delete iaexStats; + delete iaaiStats; + delete iadtStats; + delete iaitStats; + delete iafsStats; + delete iadsStats; + delete iardxStats; + delete iardyStats; + delete iardwStats; + delete iardhStats; + delete iariStats; + delete iaidStats; + delete huffDecoder; + delete mmrDecoder; + if (pageBitmap) { + delete pageBitmap; + } + if (segments) { + deleteGList(segments, JBIG2Segment); + } + if (globalSegments) { + deleteGList(globalSegments, JBIG2Segment); + } + delete str; +} + +void JBIG2Stream::reset() { + if (pageBitmap) { + delete pageBitmap; + pageBitmap = NULL; + } + if (segments) { + deleteGList(segments, JBIG2Segment); + } + segments = new GList(); + + curStr = str; + curStr->reset(); + arithDecoder->setStream(curStr); + huffDecoder->setStream(curStr); + mmrDecoder->setStream(curStr); + readSegments(); + + if (pageBitmap) { + dataPtr = pageBitmap->getDataPtr(); + dataEnd = dataPtr + pageBitmap->getDataSize(); + } else { + dataPtr = NULL; + } +} + +int JBIG2Stream::getChar() { + if (dataPtr && dataPtr < dataEnd) { + return (*dataPtr++ ^ 0xff) & 0xff; + } + return EOF; +} + +int JBIG2Stream::lookChar() { + if (dataPtr && dataPtr < dataEnd) { + return (*dataPtr ^ 0xff) & 0xff; + } + return EOF; +} + +GString *JBIG2Stream::getPSFilter(int psLevel, char *indent) { + return NULL; +} + +GBool JBIG2Stream::isBinary(GBool last) { + return str->isBinary(gTrue); +} + +void JBIG2Stream::readSegments() { + Guint segNum, segFlags, segType, page, segLength; + Guint refFlags, nRefSegs; + Guint *refSegs; + int c1, c2, c3; + Guint i; + + while (readULong(&segNum)) { + + // segment header flags + if (!readUByte(&segFlags)) { + goto eofError1; + } + segType = segFlags & 0x3f; + + // referred-to segment count and retention flags + if (!readUByte(&refFlags)) { + goto eofError1; + } + nRefSegs = refFlags >> 5; + if (nRefSegs == 7) { + if ((c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + goto eofError1; + } + refFlags = (refFlags << 24) | (c1 << 16) | (c2 << 8) | c3; + nRefSegs = refFlags & 0x1fffffff; + for (i = 0; i < (nRefSegs + 9) >> 3; ++i) { + c1 = curStr->getChar(); + } + } + + // referred-to segment numbers + refSegs = (Guint *)gmalloc(nRefSegs * sizeof(Guint)); + if (segNum <= 256) { + for (i = 0; i < nRefSegs; ++i) { + if (!readUByte(&refSegs[i])) { + goto eofError2; + } + } + } else if (segNum <= 65536) { + for (i = 0; i < nRefSegs; ++i) { + if (!readUWord(&refSegs[i])) { + goto eofError2; + } + } + } else { + for (i = 0; i < nRefSegs; ++i) { + if (!readULong(&refSegs[i])) { + goto eofError2; + } + } + } + + // segment page association + if (segFlags & 0x40) { + if (!readULong(&page)) { + goto eofError2; + } + } else { + if (!readUByte(&page)) { + goto eofError2; + } + } + + // segment data length + if (!readULong(&segLength)) { + goto eofError2; + } + + // read the segment data + switch (segType) { + case 0: + readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs); + break; + case 4: + readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); + break; + case 6: + readTextRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs); + break; + case 7: + readTextRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs); + break; + case 16: + readPatternDictSeg(segNum, segLength); + break; + case 20: + readHalftoneRegionSeg(segNum, gFalse, gFalse, segLength, + refSegs, nRefSegs); + break; + case 22: + readHalftoneRegionSeg(segNum, gTrue, gFalse, segLength, + refSegs, nRefSegs); + break; + case 23: + readHalftoneRegionSeg(segNum, gTrue, gTrue, segLength, + refSegs, nRefSegs); + break; + case 36: + readGenericRegionSeg(segNum, gFalse, gFalse, segLength); + break; + case 38: + readGenericRegionSeg(segNum, gTrue, gFalse, segLength); + break; + case 39: + readGenericRegionSeg(segNum, gTrue, gTrue, segLength); + break; + case 40: + readGenericRefinementRegionSeg(segNum, gFalse, gFalse, segLength, + refSegs, nRefSegs); + break; + case 42: + readGenericRefinementRegionSeg(segNum, gTrue, gFalse, segLength, + refSegs, nRefSegs); + break; + case 43: + readGenericRefinementRegionSeg(segNum, gTrue, gTrue, segLength, + refSegs, nRefSegs); + break; + case 48: + readPageInfoSeg(segLength); + break; + case 50: + readEndOfStripeSeg(segLength); + break; + case 52: + readProfilesSeg(segLength); + break; + case 53: + readCodeTableSeg(segNum, segLength); + break; + case 62: + readExtensionSeg(segLength); + break; + default: + error(getPos(), "Unknown segment type in JBIG2 stream"); + for (i = 0; i < segLength; ++i) { + if ((c1 = curStr->getChar()) == EOF) { + goto eofError2; + } + } + break; + } + + gfree(refSegs); + } + + return; + + eofError2: + gfree(refSegs); + eofError1: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, + Guint *refSegs, Guint nRefSegs) { + JBIG2SymbolDict *symbolDict; + JBIG2HuffmanTable *huffDHTable, *huffDWTable; + JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable; + JBIG2Segment *seg; + GList *codeTables; + JBIG2SymbolDict *inputSymbolDict; + Guint flags, sdTemplate, sdrTemplate, huff, refAgg; + Guint huffDH, huffDW, huffBMSize, huffAggInst; + Guint contextUsed, contextRetained; + int sdATX[4], sdATY[4], sdrATX[2], sdrATY[2]; + Guint numExSyms, numNewSyms, numInputSyms, symCodeLen; + JBIG2Bitmap **bitmaps; + JBIG2Bitmap *collBitmap, *refBitmap; + Guint *symWidths; + Guint symHeight, symWidth, totalWidth, x, symID; + int dh, dw, refAggNum, refDX, refDY, bmSize; + GBool ex; + int run, cnt; + Guint i, j, k; + Guchar *p; + + // symbol dictionary flags + if (!readUWord(&flags)) { + goto eofError; + } + sdTemplate = (flags >> 10) & 3; + sdrTemplate = (flags >> 12) & 1; + huff = flags & 1; + refAgg = (flags >> 1) & 1; + huffDH = (flags >> 2) & 3; + huffDW = (flags >> 4) & 3; + huffBMSize = (flags >> 6) & 1; + huffAggInst = (flags >> 7) & 1; + contextUsed = (flags >> 8) & 1; + contextRetained = (flags >> 9) & 1; + + // symbol dictionary AT flags + if (!huff) { + if (sdTemplate == 0) { + if (!readByte(&sdATX[0]) || + !readByte(&sdATY[0]) || + !readByte(&sdATX[1]) || + !readByte(&sdATY[1]) || + !readByte(&sdATX[2]) || + !readByte(&sdATY[2]) || + !readByte(&sdATX[3]) || + !readByte(&sdATY[3])) { + goto eofError; + } + } else { + if (!readByte(&sdATX[0]) || + !readByte(&sdATY[0])) { + goto eofError; + } + } + } + + // symbol dictionary refinement AT flags + if (refAgg && !sdrTemplate) { + if (!readByte(&sdrATX[0]) || + !readByte(&sdrATY[0]) || + !readByte(&sdrATX[1]) || + !readByte(&sdrATY[1])) { + goto eofError; + } + } + + // SDNUMEXSYMS and SDNUMNEWSYMS + if (!readULong(&numExSyms) || !readULong(&numNewSyms)) { + goto eofError; + } + + // get referenced segments: input symbol dictionaries and code tables + codeTables = new GList(); + numInputSyms = 0; + for (i = 0; i < nRefSegs; ++i) { + seg = findSegment(refSegs[i]); + if (seg->getType() == jbig2SegSymbolDict) { + numInputSyms += ((JBIG2SymbolDict *)seg)->getSize(); + } else if (seg->getType() == jbig2SegCodeTable) { + codeTables->append(seg); + } + } + + // compute symbol code length + symCodeLen = 0; + i = 1; + while (i < numInputSyms + numNewSyms) { + ++symCodeLen; + i <<= 1; + } + + // get the input symbol bitmaps + bitmaps = (JBIG2Bitmap **)gmalloc((numInputSyms + numNewSyms) * + sizeof(JBIG2Bitmap *)); + k = 0; + inputSymbolDict = NULL; + for (i = 0; i < nRefSegs; ++i) { + seg = findSegment(refSegs[i]); + if (seg->getType() == jbig2SegSymbolDict) { + inputSymbolDict = (JBIG2SymbolDict *)seg; + for (j = 0; j < inputSymbolDict->getSize(); ++j) { + bitmaps[k++] = inputSymbolDict->getBitmap(j); + } + } + } + + // get the Huffman tables + huffDHTable = huffDWTable = NULL; // make gcc happy + huffBMSizeTable = huffAggInstTable = NULL; // make gcc happy + i = 0; + if (huff) { + if (huffDH == 0) { + huffDHTable = huffTableD; + } else if (huffDH == 1) { + huffDHTable = huffTableE; + } else { + huffDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDW == 0) { + huffDWTable = huffTableB; + } else if (huffDW == 1) { + huffDWTable = huffTableC; + } else { + huffDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffBMSize == 0) { + huffBMSizeTable = huffTableA; + } else { + huffBMSizeTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffAggInst == 0) { + huffAggInstTable = huffTableA; + } else { + huffAggInstTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + } + delete codeTables; + + // set up the Huffman decoder + if (huff) { + huffDecoder->reset(); + + // set up the arithmetic decoder + } else { + if (contextUsed && inputSymbolDict) { + resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats()); + } else { + resetGenericStats(sdTemplate, NULL); + } + resetIntStats(symCodeLen); + arithDecoder->start(); + } + + // set up the arithmetic decoder for refinement/aggregation + if (refAgg) { + if (contextUsed && inputSymbolDict) { + resetRefinementStats(sdrTemplate, + inputSymbolDict->getRefinementRegionStats()); + } else { + resetRefinementStats(sdrTemplate, NULL); + } + } + + // allocate symbol widths storage + symWidths = NULL; + if (huff && !refAgg) { + symWidths = (Guint *)gmalloc(numNewSyms * sizeof(Guint)); + } + + symHeight = 0; + i = 0; + while (i < numNewSyms) { + + // read the height class delta height + if (huff) { + huffDecoder->decodeInt(&dh, huffDHTable); + } else { + arithDecoder->decodeInt(&dh, iadhStats); + } + symHeight += dh; + symWidth = 0; + totalWidth = 0; + j = i; + + // read the symbols in this height class + while (1) { + + // read the delta width + if (huff) { + if (!huffDecoder->decodeInt(&dw, huffDWTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&dw, iadwStats)) { + break; + } + } + symWidth += dw; + + // using a collective bitmap, so don't read a bitmap here + if (huff && !refAgg) { + symWidths[i] = symWidth; + totalWidth += symWidth; + + // refinement/aggregate coding + } else if (refAgg) { + if (huff) { + if (!huffDecoder->decodeInt(&refAggNum, huffAggInstTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&refAggNum, iaaiStats)) { + break; + } + } +#if 0 //~ This special case was added about a year before the final draft + //~ of the JBIG2 spec was released. I have encountered some old + //~ JBIG2 images that predate it. + if (0) { +#else + if (refAggNum == 1) { +#endif + if (huff) { + symID = huffDecoder->readBits(symCodeLen); + huffDecoder->decodeInt(&refDX, huffTableO); + huffDecoder->decodeInt(&refDY, huffTableO); + huffDecoder->decodeInt(&bmSize, huffTableA); + huffDecoder->reset(); + arithDecoder->start(); + } else { + symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); + arithDecoder->decodeInt(&refDX, iardxStats); + arithDecoder->decodeInt(&refDY, iardyStats); + } + refBitmap = bitmaps[symID]; + bitmaps[numInputSyms + i] = + readGenericRefinementRegion(symWidth, symHeight, + sdrTemplate, gFalse, + refBitmap, refDX, refDY, + sdrATX, sdrATY); + //~ do we need to use the bmSize value here (in Huffman mode)? + } else { + bitmaps[numInputSyms + i] = + readTextRegion(huff, gTrue, symWidth, symHeight, + refAggNum, 0, numInputSyms + i, NULL, + symCodeLen, bitmaps, 0, 0, 0, 1, 0, + huffTableF, huffTableH, huffTableK, huffTableO, + huffTableO, huffTableO, huffTableO, huffTableA, + sdrTemplate, sdrATX, sdrATY); + } + + // non-ref/agg coding + } else { + bitmaps[numInputSyms + i] = + readGenericBitmap(gFalse, symWidth, symHeight, + sdTemplate, gFalse, gFalse, NULL, + sdATX, sdATY, 0); + } + + ++i; + } + + // read the collective bitmap + if (huff && !refAgg) { + huffDecoder->decodeInt(&bmSize, huffBMSizeTable); + huffDecoder->reset(); + if (bmSize == 0) { + collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight); + bmSize = symHeight * ((totalWidth + 7) >> 3); + p = collBitmap->getDataPtr(); + for (k = 0; k < (Guint)bmSize; ++k) { + *p++ = curStr->getChar(); + } + } else { + collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight, + 0, gFalse, gFalse, NULL, NULL, NULL, + bmSize); + } + x = 0; + for (; j < i; ++j) { + bitmaps[numInputSyms + j] = + collBitmap->getSlice(x, 0, symWidths[j], symHeight); + x += symWidths[j]; + } + delete collBitmap; + } + } + + // create the symbol dict object + symbolDict = new JBIG2SymbolDict(segNum, numExSyms); + + // exported symbol list + i = j = 0; + ex = gFalse; + while (i < numInputSyms + numNewSyms) { + if (huff) { + huffDecoder->decodeInt(&run, huffTableA); + } else { + arithDecoder->decodeInt(&run, iaexStats); + } + if (ex) { + for (cnt = 0; cnt < run; ++cnt) { + symbolDict->setBitmap(j++, bitmaps[i++]->copy()); + } + } else { + i += run; + } + ex = !ex; + } + + for (i = 0; i < numNewSyms; ++i) { + delete bitmaps[numInputSyms + i]; + } + gfree(bitmaps); + if (symWidths) { + gfree(symWidths); + } + + // save the arithmetic decoder stats + if (!huff && contextRetained) { + symbolDict->setGenericRegionStats(genericRegionStats->copy()); + if (refAgg) { + symbolDict->setRefinementRegionStats(refinementRegionStats->copy()); + } + } + + // store the new symbol dict + segments->append(symbolDict); + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs) { + JBIG2Bitmap *bitmap; + JBIG2HuffmanTable runLengthTab[36]; + JBIG2HuffmanTable *symCodeTab; + JBIG2HuffmanTable *huffFSTable, *huffDSTable, *huffDTTable; + JBIG2HuffmanTable *huffRDWTable, *huffRDHTable; + JBIG2HuffmanTable *huffRDXTable, *huffRDYTable, *huffRSizeTable; + JBIG2Segment *seg; + GList *codeTables; + JBIG2SymbolDict *symbolDict; + JBIG2Bitmap **syms; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, huff, refine, logStrips, refCorner, transposed; + Guint combOp, defPixel, templ; + int sOffset; + Guint huffFlags, huffFS, huffDS, huffDT; + Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize; + Guint numInstances, numSyms, symCodeLen; + int atx[2], aty[2]; + Guint i, k, kk; + int j; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the text region header + if (!readUWord(&flags)) { + goto eofError; + } + huff = flags & 1; + refine = (flags >> 1) & 1; + logStrips = (flags >> 2) & 3; + refCorner = (flags >> 4) & 3; + transposed = (flags >> 6) & 1; + combOp = (flags >> 7) & 3; + defPixel = (flags >> 9) & 1; + sOffset = (flags >> 10) & 0x1f; + if (sOffset & 0x10) { + sOffset |= -1 - 0x0f; + } + templ = (flags >> 15) & 1; + huffFS = huffDS = huffDT = 0; // make gcc happy + huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy + if (huff) { + if (!readUWord(&huffFlags)) { + goto eofError; + } + huffFS = huffFlags & 3; + huffDS = (huffFlags >> 2) & 3; + huffDT = (huffFlags >> 4) & 3; + huffRDW = (huffFlags >> 6) & 3; + huffRDH = (huffFlags >> 8) & 3; + huffRDX = (huffFlags >> 10) & 3; + huffRDY = (huffFlags >> 12) & 3; + huffRSize = (huffFlags >> 14) & 1; + } + if (refine && templ == 0) { + if (!readByte(&atx[0]) || !readByte(&aty[0]) || + !readByte(&atx[1]) || !readByte(&aty[1])) { + goto eofError; + } + } + if (!readULong(&numInstances)) { + goto eofError; + } + + // get symbol dictionaries and tables + codeTables = new GList(); + numSyms = 0; + for (i = 0; i < nRefSegs; ++i) { + seg = findSegment(refSegs[i]); + if (seg->getType() == jbig2SegSymbolDict) { + numSyms += ((JBIG2SymbolDict *)seg)->getSize(); + } else if (seg->getType() == jbig2SegCodeTable) { + codeTables->append(seg); + } + } + symCodeLen = 0; + i = 1; + while (i < numSyms) { + ++symCodeLen; + i <<= 1; + } + + // get the symbol bitmaps + syms = (JBIG2Bitmap **)gmalloc(numSyms * sizeof(JBIG2Bitmap *)); + kk = 0; + for (i = 0; i < nRefSegs; ++i) { + seg = findSegment(refSegs[i]); + if (seg->getType() == jbig2SegSymbolDict) { + symbolDict = (JBIG2SymbolDict *)seg; + for (k = 0; k < symbolDict->getSize(); ++k) { + syms[kk++] = symbolDict->getBitmap(k); + } + } + } + + // get the Huffman tables + huffFSTable = huffDSTable = huffDTTable = NULL; // make gcc happy + huffRDWTable = huffRDHTable = NULL; // make gcc happy + huffRDXTable = huffRDYTable = huffRSizeTable = NULL; // make gcc happy + i = 0; + if (huff) { + if (huffFS == 0) { + huffFSTable = huffTableF; + } else if (huffFS == 1) { + huffFSTable = huffTableG; + } else { + huffFSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDS == 0) { + huffDSTable = huffTableH; + } else if (huffDS == 1) { + huffDSTable = huffTableI; + } else if (huffDS == 2) { + huffDSTable = huffTableJ; + } else { + huffDSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDT == 0) { + huffDTTable = huffTableK; + } else if (huffDT == 1) { + huffDTTable = huffTableL; + } else if (huffDT == 2) { + huffDTTable = huffTableM; + } else { + huffDTTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDW == 0) { + huffRDWTable = huffTableN; + } else if (huffRDW == 1) { + huffRDWTable = huffTableO; + } else { + huffRDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDH == 0) { + huffRDHTable = huffTableN; + } else if (huffRDH == 1) { + huffRDHTable = huffTableO; + } else { + huffRDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDX == 0) { + huffRDXTable = huffTableN; + } else if (huffRDX == 1) { + huffRDXTable = huffTableO; + } else { + huffRDXTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDY == 0) { + huffRDYTable = huffTableN; + } else if (huffRDY == 1) { + huffRDYTable = huffTableO; + } else { + huffRDYTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRSize == 0) { + huffRSizeTable = huffTableA; + } else { + huffRSizeTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + } + delete codeTables; + + // symbol ID Huffman decoding table + if (huff) { + huffDecoder->reset(); + for (i = 0; i < 32; ++i) { + runLengthTab[i].val = i; + runLengthTab[i].prefixLen = huffDecoder->readBits(4); + runLengthTab[i].rangeLen = 0; + } + runLengthTab[32].val = 0x103; + runLengthTab[32].prefixLen = huffDecoder->readBits(4); + runLengthTab[32].rangeLen = 2; + runLengthTab[33].val = 0x203; + runLengthTab[33].prefixLen = huffDecoder->readBits(4); + runLengthTab[33].rangeLen = 3; + runLengthTab[34].val = 0x20b; + runLengthTab[34].prefixLen = huffDecoder->readBits(4); + runLengthTab[34].rangeLen = 7; + runLengthTab[35].prefixLen = 0; + runLengthTab[35].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(runLengthTab, 35); + symCodeTab = (JBIG2HuffmanTable *)gmalloc((numSyms + 1) * + sizeof(JBIG2HuffmanTable)); + for (i = 0; i < numSyms; ++i) { + symCodeTab[i].val = i; + symCodeTab[i].rangeLen = 0; + } + i = 0; + while (i < numSyms) { + huffDecoder->decodeInt(&j, runLengthTab); + if (j > 0x200) { + for (j -= 0x200; j && i < numSyms; --j) { + symCodeTab[i++].prefixLen = 0; + } + } else if (j > 0x100) { + for (j -= 0x100; j && i < numSyms; --j) { + symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; + ++i; + } + } else { + symCodeTab[i++].prefixLen = j; + } + } + symCodeTab[numSyms].prefixLen = 0; + symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(symCodeTab, numSyms); + huffDecoder->reset(); + + // set up the arithmetic decoder + } else { + symCodeTab = NULL; + resetIntStats(symCodeLen); + arithDecoder->start(); + } + if (refine) { + resetRefinementStats(templ, NULL); + } + + bitmap = readTextRegion(huff, refine, w, h, numInstances, + logStrips, numSyms, symCodeTab, symCodeLen, syms, + defPixel, combOp, transposed, refCorner, sOffset, + huffFSTable, huffDSTable, huffDTTable, + huffRDWTable, huffRDHTable, + huffRDXTable, huffRDYTable, huffRSizeTable, + templ, atx, aty); + + gfree(syms); + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + // clean up the Huffman decoder + if (huff) { + gfree(symCodeTab); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, + int w, int h, + Guint numInstances, + Guint logStrips, + int numSyms, + JBIG2HuffmanTable *symCodeTab, + Guint symCodeLen, + JBIG2Bitmap **syms, + Guint defPixel, Guint combOp, + Guint transposed, Guint refCorner, + int sOffset, + JBIG2HuffmanTable *huffFSTable, + JBIG2HuffmanTable *huffDSTable, + JBIG2HuffmanTable *huffDTTable, + JBIG2HuffmanTable *huffRDWTable, + JBIG2HuffmanTable *huffRDHTable, + JBIG2HuffmanTable *huffRDXTable, + JBIG2HuffmanTable *huffRDYTable, + JBIG2HuffmanTable *huffRSizeTable, + Guint templ, + int *atx, int *aty) { + JBIG2Bitmap *bitmap; + JBIG2Bitmap *symbolBitmap; + Guint strips; + int t, dt, tt, s, ds, sFirst, j; + int rdw, rdh, rdx, rdy, ri, refDX, refDY, bmSize; + Guint symID, inst, bw, bh; + + strips = 1 << logStrips; + + // allocate the bitmap + bitmap = new JBIG2Bitmap(0, w, h); + if (defPixel) { + bitmap->clearToOne(); + } else { + bitmap->clearToZero(); + } + + // decode initial T value + if (huff) { + huffDecoder->decodeInt(&t, huffDTTable); + } else { + arithDecoder->decodeInt(&t, iadtStats); + } + t *= -(int)strips; + + inst = 0; + sFirst = 0; + while (inst < numInstances) { + + // decode delta-T + if (huff) { + huffDecoder->decodeInt(&dt, huffDTTable); + } else { + arithDecoder->decodeInt(&dt, iadtStats); + } + t += dt * strips; + + // first S value + if (huff) { + huffDecoder->decodeInt(&ds, huffFSTable); + } else { + arithDecoder->decodeInt(&ds, iafsStats); + } + sFirst += ds; + s = sFirst; + + // read the instances + while (1) { + + // T value + if (strips == 1) { + dt = 0; + } else if (huff) { + dt = huffDecoder->readBits(logStrips); + } else { + arithDecoder->decodeInt(&dt, iaitStats); + } + tt = t + dt; + + // symbol ID + if (huff) { + if (symCodeTab) { + huffDecoder->decodeInt(&j, symCodeTab); + symID = (Guint)j; + } else { + symID = huffDecoder->readBits(symCodeLen); + } + } else { + symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); + } + + // get the symbol bitmap + symbolBitmap = NULL; + if (refine) { + if (huff) { + ri = (int)huffDecoder->readBit(); + } else { + arithDecoder->decodeInt(&ri, iariStats); + } + } else { + ri = 0; + } + if (ri) { + if (huff) { + huffDecoder->decodeInt(&rdw, huffRDWTable); + huffDecoder->decodeInt(&rdh, huffRDHTable); + huffDecoder->decodeInt(&rdx, huffRDXTable); + huffDecoder->decodeInt(&rdy, huffRDYTable); + huffDecoder->decodeInt(&bmSize, huffRSizeTable); + huffDecoder->reset(); + arithDecoder->start(); + } else { + arithDecoder->decodeInt(&rdw, iardwStats); + arithDecoder->decodeInt(&rdh, iardhStats); + arithDecoder->decodeInt(&rdx, iardxStats); + arithDecoder->decodeInt(&rdy, iardyStats); + } + refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx; + refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy; + + symbolBitmap = + readGenericRefinementRegion(rdw + syms[symID]->getWidth(), + rdh + syms[symID]->getHeight(), + templ, gFalse, syms[symID], + refDX, refDY, atx, aty); + //~ do we need to use the bmSize value here (in Huffman mode)? + } else { + symbolBitmap = syms[symID]; + } + + // combine the symbol bitmap into the region bitmap + //~ something is wrong here - refCorner shouldn't degenerate into + //~ two cases + bw = symbolBitmap->getWidth() - 1; + bh = symbolBitmap->getHeight() - 1; + if (transposed) { + switch (refCorner) { + case 0: // bottom left + bitmap->combine(symbolBitmap, tt, s, combOp); + break; + case 1: // top left + bitmap->combine(symbolBitmap, tt, s, combOp); + break; + case 2: // bottom right + bitmap->combine(symbolBitmap, tt - bw, s, combOp); + break; + case 3: // top right + bitmap->combine(symbolBitmap, tt - bw, s, combOp); + break; + } + s += bh; + } else { + switch (refCorner) { + case 0: // bottom left + bitmap->combine(symbolBitmap, s, tt - bh, combOp); + break; + case 1: // top left + bitmap->combine(symbolBitmap, s, tt, combOp); + break; + case 2: // bottom right + bitmap->combine(symbolBitmap, s, tt - bh, combOp); + break; + case 3: // top right + bitmap->combine(symbolBitmap, s, tt, combOp); + break; + } + s += bw; + } + if (ri) { + delete symbolBitmap; + } + + // next instance + ++inst; + + // next S value + if (huff) { + if (!huffDecoder->decodeInt(&ds, huffDSTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&ds, iadsStats)) { + break; + } + } + s += sOffset + ds; + } + } + + return bitmap; +} + +void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) { + JBIG2PatternDict *patternDict; + JBIG2Bitmap *bitmap; + Guint flags, patternW, patternH, grayMax, templ, mmr; + int atx[4], aty[4]; + Guint i, x; + + // halftone dictionary flags, pattern width and height, max gray value + if (!readUByte(&flags) || + !readUByte(&patternW) || + !readUByte(&patternH) || + !readULong(&grayMax)) { + goto eofError; + } + templ = (flags >> 1) & 3; + mmr = flags & 1; + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // read the bitmap + atx[0] = -(int)patternW; aty[0] = 0; + atx[1] = -3; aty[1] = -1; + atx[2] = 2; aty[2] = -2; + atx[3] = -2; aty[3] = -2; + bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH, + templ, gFalse, gFalse, NULL, + atx, aty, length - 7); + + // create the pattern dict object + patternDict = new JBIG2PatternDict(segNum, grayMax + 1); + + // split up the bitmap + x = 0; + for (i = 0; i <= grayMax; ++i) { + patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH)); + x += patternW; + } + + // free memory + delete bitmap; + + // store the new pattern dict + segments->append(patternDict); + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs) { + JBIG2Bitmap *bitmap; + JBIG2Segment *seg; + JBIG2PatternDict *patternDict; + JBIG2Bitmap *skipBitmap; + Guint *grayImg; + JBIG2Bitmap *grayBitmap; + JBIG2Bitmap *patternBitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, mmr, templ, enableSkip, combOp; + Guint gridW, gridH, stepX, stepY, patW, patH; + int atx[4], aty[4]; + int gridX, gridY, xx, yy, bit, j; + Guint bpp, m, n, i; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the halftone region header + if (!readUByte(&flags)) { + goto eofError; + } + mmr = flags & 1; + templ = (flags >> 1) & 3; + enableSkip = (flags >> 3) & 1; + combOp = (flags >> 4) & 7; + if (!readULong(&gridW) || !readULong(&gridH) || + !readLong(&gridX) || !readLong(&gridY) || + !readUWord(&stepX) || !readUWord(&stepY)) { + goto eofError; + } + + // get pattern dictionary + if (nRefSegs != 1) { + error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); + return; + } + seg = findSegment(refSegs[0]); + if (seg->getType() != jbig2SegPatternDict) { + error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); + return; + } + patternDict = (JBIG2PatternDict *)seg; + bpp = 0; + i = 1; + while (i < patternDict->getSize()) { + ++bpp; + i <<= 1; + } + patW = patternDict->getBitmap(0)->getWidth(); + patH = patternDict->getBitmap(0)->getHeight(); + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // allocate the bitmap + bitmap = new JBIG2Bitmap(segNum, w, h); + if (flags & 0x80) { // HDEFPIXEL + bitmap->clearToOne(); + } else { + bitmap->clearToZero(); + } + + // compute the skip bitmap + skipBitmap = NULL; + if (enableSkip) { + skipBitmap = new JBIG2Bitmap(0, gridW, gridH); + skipBitmap->clearToZero(); + for (m = 0; m < gridH; ++m) { + xx = gridX + m * stepY; + yy = gridY + m * stepX; + for (n = 0; n < gridW; ++n) { + if (((xx + (int)patW) >> 8) <= 0 || (xx >> 8) >= (int)w || + ((yy + (int)patH) >> 8) <= 0 || (yy >> 8) >= (int)h) { + skipBitmap->setPixel(n, m); + } + } + } + } + + // read the gray-scale image + grayImg = (Guint *)gmalloc(gridW * gridH * sizeof(Guint)); + memset(grayImg, 0, gridW * gridH * sizeof(Guint)); + atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1; + atx[1] = -3; aty[1] = -1; + atx[2] = 2; aty[2] = -2; + atx[3] = -2; aty[3] = -2; + for (j = bpp - 1; j >= 0; --j) { + grayBitmap = readGenericBitmap(mmr, gridW, gridH, templ, gFalse, + enableSkip, skipBitmap, atx, aty, -1); + i = 0; + for (m = 0; m < gridH; ++m) { + for (n = 0; n < gridW; ++n) { + bit = grayBitmap->getPixel(n, m) ^ (grayImg[i] & 1); + grayImg[i] = (grayImg[i] << 1) | bit; + ++i; + } + } + delete grayBitmap; + } + + // decode the image + i = 0; + for (m = 0; m < gridH; ++m) { + xx = gridX + m * stepY; + yy = gridY + m * stepX; + for (n = 0; n < gridW; ++n) { + if (!(enableSkip && skipBitmap->getPixel(n, m))) { + patternBitmap = patternDict->getBitmap(grayImg[i]); + bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp); + } + xx += stepX; + yy -= stepY; + ++i; + } + } + + gfree(grayImg); + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + segments->append(bitmap); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length) { + JBIG2Bitmap *bitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, mmr, templ, tpgdOn; + int atx[4], aty[4]; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the generic region segment header + if (!readUByte(&flags)) { + goto eofError; + } + mmr = flags & 1; + templ = (flags >> 1) & 3; + tpgdOn = (flags >> 3) & 1; + + // AT flags + if (!mmr) { + if (templ == 0) { + if (!readByte(&atx[0]) || + !readByte(&aty[0]) || + !readByte(&atx[1]) || + !readByte(&aty[1]) || + !readByte(&atx[2]) || + !readByte(&aty[2]) || + !readByte(&atx[3]) || + !readByte(&aty[3])) { + goto eofError; + } + } else { + if (!readByte(&atx[0]) || + !readByte(&aty[0])) { + goto eofError; + } + } + } + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // read the bitmap + bitmap = readGenericBitmap(mmr, w, h, templ, tpgdOn, gFalse, + NULL, atx, aty, mmr ? 0 : length - 18); + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, + int templ, GBool tpgdOn, + GBool useSkip, JBIG2Bitmap *skip, + int *atx, int *aty, + int mmrDataLength) { + JBIG2Bitmap *bitmap; + GBool ltp; + Guint ltpCX, cx, cx0, cx1, cx2; + JBIG2BitmapPtr cxPtr0, cxPtr1; + JBIG2BitmapPtr atPtr0, atPtr1, atPtr2, atPtr3; + int *refLine, *codingLine; + int code1, code2, code3; + int x, y, a0, pix, i, refI, codingI; + + bitmap = new JBIG2Bitmap(0, w, h); + bitmap->clearToZero(); + + //----- MMR decode + + if (mmr) { + + mmrDecoder->reset(); + refLine = (int *)gmalloc((w + 2) * sizeof(int)); + codingLine = (int *)gmalloc((w + 2) * sizeof(int)); + codingLine[0] = codingLine[1] = w; + + for (y = 0; y < h; ++y) { + + // copy coding line to ref line + for (i = 0; codingLine[i] < w; ++i) { + refLine[i] = codingLine[i]; + } + refLine[i] = refLine[i + 1] = w; + + // decode a line + refI = 0; // b1 = refLine[refI] + codingI = 0; // a1 = codingLine[codingI] + a0 = 0; + do { + code1 = mmrDecoder->get2DCode(); + switch (code1) { + case twoDimPass: + if (refLine[refI] < w) { + a0 = refLine[refI + 1]; + refI += 2; + } + break; + case twoDimHoriz: + if (codingI & 1) { + code1 = 0; + do { + code1 += code3 = mmrDecoder->getBlackCode(); + } while (code3 >= 64); + code2 = 0; + do { + code2 += code3 = mmrDecoder->getWhiteCode(); + } while (code3 >= 64); + } else { + code1 = 0; + do { + code1 += code3 = mmrDecoder->getWhiteCode(); + } while (code3 >= 64); + code2 = 0; + do { + code2 += code3 = mmrDecoder->getBlackCode(); + } while (code3 >= 64); + } + if (code1 > 0 || code2 > 0) { + a0 = codingLine[codingI++] = a0 + code1; + a0 = codingLine[codingI++] = a0 + code2; + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + } + break; + case twoDimVert0: + a0 = codingLine[codingI++] = refLine[refI]; + if (refLine[refI] < w) { + ++refI; + } + break; + case twoDimVertR1: + a0 = codingLine[codingI++] = refLine[refI] + 1; + if (refLine[refI] < w) { + ++refI; + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + } + break; + case twoDimVertR2: + a0 = codingLine[codingI++] = refLine[refI] + 2; + if (refLine[refI] < w) { + ++refI; + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + } + break; + case twoDimVertR3: + a0 = codingLine[codingI++] = refLine[refI] + 3; + if (refLine[refI] < w) { + ++refI; + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + } + break; + case twoDimVertL1: + a0 = codingLine[codingI++] = refLine[refI] - 1; + if (refI > 0) { + --refI; + } else { + ++refI; + } + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + break; + case twoDimVertL2: + a0 = codingLine[codingI++] = refLine[refI] - 2; + if (refI > 0) { + --refI; + } else { + ++refI; + } + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + break; + case twoDimVertL3: + a0 = codingLine[codingI++] = refLine[refI] - 3; + if (refI > 0) { + --refI; + } else { + ++refI; + } + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + break; + default: + error(getPos(), "Illegal code in JBIG2 MMR bitmap data"); + break; + } + } while (a0 < w); + codingLine[codingI++] = w; + + // convert the run lengths to a bitmap line + i = 0; + while (codingLine[i] < w) { + for (x = codingLine[i]; x < codingLine[i+1]; ++x) { + bitmap->setPixel(x, y); + } + i += 2; + } + } + + if (mmrDataLength >= 0) { + mmrDecoder->skipTo(mmrDataLength); + } else { + if (mmrDecoder->get24Bits() != 0x001001) { + error(getPos(), "Missing EOFB in JBIG2 MMR bitmap data"); + } + } + + gfree(refLine); + gfree(codingLine); + + //----- arithmetic decode + + } else { + // set up the typical row context + ltpCX = 0; // make gcc happy + if (tpgdOn) { + switch (templ) { + case 0: + ltpCX = 0x3953; // 001 11001 0101 0011 + break; + case 1: + ltpCX = 0x079a; // 0011 11001 101 0 + break; + case 2: + ltpCX = 0x0e3; // 001 1100 01 1 + break; + case 3: + ltpCX = 0x18a; // 01100 0101 1 + break; + } + } + + ltp = 0; + cx = cx0 = cx1 = cx2 = 0; // make gcc happy + for (y = 0; y < h; ++y) { + + // check for a "typical" (duplicate) row + if (tpgdOn) { + if (arithDecoder->decodeBit(ltpCX, genericRegionStats)) { + ltp = !ltp; + } + if (ltp) { + bitmap->duplicateRow(y, y-1); + continue; + } + } + + switch (templ) { + case 0: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + bitmap->getPixelPtr(atx[1], y + aty[1], &atPtr1); + bitmap->getPixelPtr(atx[2], y + aty[2], &atPtr2); + bitmap->getPixelPtr(atx[3], y + aty[3], &atPtr3); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) | + (bitmap->nextPixel(&atPtr0) << 3) | + (bitmap->nextPixel(&atPtr1) << 2) | + (bitmap->nextPixel(&atPtr2) << 1) | + bitmap->nextPixel(&atPtr3); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x0f; + } + break; + + case 1: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x0f; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x07; + } + break; + + case 2: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x0f; + cx2 = ((cx2 << 1) | pix) & 0x03; + } + break; + + case 3: + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx1 << 5) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x0f; + } + break; + } + } + } + + return bitmap; +} + +void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, + Guint nRefSegs) { + JBIG2Bitmap *bitmap, *refBitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, templ, tpgrOn; + int atx[2], aty[2]; + JBIG2Segment *seg; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the generic refinement region segment header + if (!readUByte(&flags)) { + goto eofError; + } + templ = flags & 1; + tpgrOn = (flags >> 1) & 1; + + // AT flags + if (!templ) { + if (!readByte(&atx[0]) || !readByte(&aty[0]) || + !readByte(&atx[1]) || !readByte(&aty[1])) { + goto eofError; + } + } + + // resize the page bitmap if needed + if (nRefSegs == 0 || imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + } + + // get referenced bitmap + if (nRefSegs > 1) { + error(getPos(), "Bad reference in JBIG2 generic refinement segment"); + return; + } + if (nRefSegs == 1) { + seg = findSegment(refSegs[0]); + if (seg->getType() != jbig2SegBitmap) { + error(getPos(), "Bad bitmap reference in JBIG2 generic refinement segment"); + return; + } + refBitmap = (JBIG2Bitmap *)seg; + } else { + refBitmap = pageBitmap->getSlice(x, y, w, h); + } + + // set up the arithmetic decoder + resetRefinementStats(templ, NULL); + arithDecoder->start(); + + // read + bitmap = readGenericRefinementRegion(w, h, templ, tpgrOn, + refBitmap, 0, 0, atx, aty); + + // combine the region bitmap into the page bitmap + if (imm) { + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + // delete the referenced bitmap + if (nRefSegs == 1) { + discardSegment(refSegs[0]); + } else { + delete refBitmap; + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h, + int templ, GBool tpgrOn, + JBIG2Bitmap *refBitmap, + int refDX, int refDY, + int *atx, int *aty) { + JBIG2Bitmap *bitmap; + GBool ltp; + Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2; + JBIG2BitmapPtr cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6; + JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2; + int x, y, pix; + + bitmap = new JBIG2Bitmap(0, w, h); + bitmap->clearToZero(); + + // set up the typical row context + if (templ) { + ltpCX = 0x008; + } else { + ltpCX = 0x0010; + } + + ltp = 0; + for (y = 0; y < h; ++y) { + + if (templ) { + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(-1, y, &cxPtr1); + refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); + cx3 = refBitmap->nextPixel(&cxPtr3); + cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); + refBitmap->getPixelPtr(-refDX, y+1-refDY, &cxPtr4); + cx4 = refBitmap->nextPixel(&cxPtr4); + + // set up the typical prediction context + tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy + if (tpgrOn) { + refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); + tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); + tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); + tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + } + + for (x = 0; x < w; ++x) { + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 7; + cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; + cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 3; + + if (tpgrOn) { + // update the typical predictor context + tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; + tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; + tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; + + // check for a "typical" pixel + if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { + ltp = !ltp; + } + if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { + bitmap->clearPixel(x, y); + continue; + } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { + bitmap->setPixel(x, y); + continue; + } + } + + // build the context + cx = (cx0 << 7) | (bitmap->nextPixel(&cxPtr1) << 6) | + (refBitmap->nextPixel(&cxPtr2) << 5) | + (cx3 << 2) | cx4; + + // decode the pixel + if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { + bitmap->setPixel(x, y); + } + } + + } else { + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(-1, y, &cxPtr1); + refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); + cx2 = refBitmap->nextPixel(&cxPtr2); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); + cx3 = refBitmap->nextPixel(&cxPtr3); + cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &cxPtr4); + cx4 = refBitmap->nextPixel(&cxPtr4); + cx4 = (cx4 << 1) | refBitmap->nextPixel(&cxPtr4); + bitmap->getPixelPtr(atx[0], y+aty[0], &cxPtr5); + refBitmap->getPixelPtr(atx[1]-refDX, y+aty[1]-refDY, &cxPtr6); + + // set up the typical prediction context + tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy + if (tpgrOn) { + refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); + tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); + tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); + tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + } + + for (x = 0; x < w; ++x) { + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 3; + cx2 = ((cx2 << 1) | refBitmap->nextPixel(&cxPtr2)) & 3; + cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; + cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 7; + + if (tpgrOn) { + // update the typical predictor context + tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; + tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; + tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; + + // check for a "typical" pixel + if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { + ltp = !ltp; + } + if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { + bitmap->clearPixel(x, y); + continue; + } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { + bitmap->setPixel(x, y); + continue; + } + } + + // build the context + cx = (cx0 << 11) | (bitmap->nextPixel(&cxPtr1) << 10) | + (cx2 << 8) | (cx3 << 5) | (cx4 << 2) | + (bitmap->nextPixel(&cxPtr5) << 1) | + refBitmap->nextPixel(&cxPtr6); + + // decode the pixel + if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { + bitmap->setPixel(x, y); + } + } + } + } + + return bitmap; +} + +void JBIG2Stream::readPageInfoSeg(Guint length) { + Guint xRes, yRes, flags, striping; + + if (!readULong(&pageW) || !readULong(&pageH) || + !readULong(&xRes) || !readULong(&yRes) || + !readUByte(&flags) || !readUWord(&striping)) { + goto eofError; + } + pageDefPixel = (flags >> 2) & 1; + defCombOp = (flags >> 3) & 3; + + // allocate the page bitmap + if (pageH == 0xffffffff) { + curPageH = striping & 0x7fff; + } else { + curPageH = pageH; + } + pageBitmap = new JBIG2Bitmap(0, pageW, curPageH); + + // default pixel value + if (pageDefPixel) { + pageBitmap->clearToOne(); + } else { + pageBitmap->clearToZero(); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readEndOfStripeSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +void JBIG2Stream::readProfilesSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) { + JBIG2HuffmanTable *huffTab; + Guint flags, oob, prefixBits, rangeBits; + int lowVal, highVal, val; + Guint huffTabSize, i; + + if (!readUByte(&flags) || !readLong(&lowVal) || !readLong(&highVal)) { + goto eofError; + } + oob = flags & 1; + prefixBits = ((flags >> 1) & 7) + 1; + rangeBits = ((flags >> 4) & 7) + 1; + + huffDecoder->reset(); + huffTabSize = 8; + huffTab = (JBIG2HuffmanTable *) + gmalloc(huffTabSize * sizeof(JBIG2HuffmanTable)); + i = 0; + val = lowVal; + while (val < highVal) { + if (i == huffTabSize) { + huffTabSize *= 2; + huffTab = (JBIG2HuffmanTable *) + grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable)); + } + huffTab[i].val = val; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = huffDecoder->readBits(rangeBits); + val += 1 << huffTab[i].rangeLen; + ++i; + } + if (i + oob + 3 > huffTabSize) { + huffTabSize = i + oob + 3; + huffTab = (JBIG2HuffmanTable *) + grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable)); + } + huffTab[i].val = lowVal - 1; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = jbig2HuffmanLOW; + ++i; + huffTab[i].val = highVal; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = 32; + ++i; + if (oob) { + huffTab[i].val = 0; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = jbig2HuffmanOOB; + ++i; + } + huffTab[i].val = 0; + huffTab[i].prefixLen = 0; + huffTab[i].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(huffTab, i); + + // create and store the new table segment + segments->append(new JBIG2CodeTable(segNum, huffTab)); + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readExtensionSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +JBIG2Segment *JBIG2Stream::findSegment(Guint segNum) { + JBIG2Segment *seg; + int i; + + for (i = 0; i < globalSegments->getLength(); ++i) { + seg = (JBIG2Segment *)globalSegments->get(i); + if (seg->getSegNum() == segNum) { + return seg; + } + } + for (i = 0; i < segments->getLength(); ++i) { + seg = (JBIG2Segment *)segments->get(i); + if (seg->getSegNum() == segNum) { + return seg; + } + } + return NULL; +} + +void JBIG2Stream::discardSegment(Guint segNum) { + JBIG2Segment *seg; + int i; + + for (i = 0; i < globalSegments->getLength(); ++i) { + seg = (JBIG2Segment *)globalSegments->get(i); + if (seg->getSegNum() == segNum) { + globalSegments->del(i); + return; + } + } + for (i = 0; i < segments->getLength(); ++i) { + seg = (JBIG2Segment *)segments->get(i); + if (seg->getSegNum() == segNum) { + segments->del(i); + return; + } + } +} + +void JBIG2Stream::resetGenericStats(Guint templ, + JArithmeticDecoderStats *prevStats) { + int size; + + size = contextSize[templ]; + if (prevStats && prevStats->getContextSize() == size) { + if (genericRegionStats->getContextSize() == size) { + genericRegionStats->copyFrom(prevStats); + } else { + delete genericRegionStats; + genericRegionStats = prevStats->copy(); + } + } else { + if (genericRegionStats->getContextSize() == size) { + genericRegionStats->reset(); + } else { + delete genericRegionStats; + genericRegionStats = new JArithmeticDecoderStats(1 << size); + } + } +} + +void JBIG2Stream::resetRefinementStats(Guint templ, + JArithmeticDecoderStats *prevStats) { + int size; + + size = refContextSize[templ]; + if (prevStats && prevStats->getContextSize() == size) { + if (refinementRegionStats->getContextSize() == size) { + refinementRegionStats->copyFrom(prevStats); + } else { + delete refinementRegionStats; + refinementRegionStats = prevStats->copy(); + } + } else { + if (refinementRegionStats->getContextSize() == size) { + refinementRegionStats->reset(); + } else { + delete refinementRegionStats; + refinementRegionStats = new JArithmeticDecoderStats(1 << size); + } + } +} + +void JBIG2Stream::resetIntStats(int symCodeLen) { + iadhStats->reset(); + iadwStats->reset(); + iaexStats->reset(); + iaaiStats->reset(); + iadtStats->reset(); + iaitStats->reset(); + iafsStats->reset(); + iadsStats->reset(); + iardxStats->reset(); + iardyStats->reset(); + iardwStats->reset(); + iardhStats->reset(); + iariStats->reset(); + if (iaidStats->getContextSize() == symCodeLen + 1) { + iaidStats->reset(); + } else { + delete iaidStats; + iaidStats = new JArithmeticDecoderStats(1 << (symCodeLen + 1)); + } +} + +GBool JBIG2Stream::readUByte(Guint *x) { + int c0; + + if ((c0 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)c0; + return gTrue; +} + +GBool JBIG2Stream::readByte(int *x) { + int c0; + + if ((c0 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = c0; + if (c0 & 0x80) { + *x |= -1 - 0xff; + } + return gTrue; +} + +GBool JBIG2Stream::readUWord(Guint *x) { + int c0, c1; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 8) | c1); + return gTrue; +} + +GBool JBIG2Stream::readULong(Guint *x) { + int c0, c1, c2, c3; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + return gTrue; +} + +GBool JBIG2Stream::readLong(int *x) { + int c0, c1, c2, c3; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + if (c0 & 0x80) { + *x |= -1 - (int)0xffffffff; + } + return gTrue; +} diff --git a/pdf2swf/xpdf/JBIG2Stream.h b/pdf2swf/xpdf/JBIG2Stream.h new file mode 100644 index 0000000..ed26d4e --- /dev/null +++ b/pdf2swf/xpdf/JBIG2Stream.h @@ -0,0 +1,143 @@ +//======================================================================== +// +// JBIG2Stream.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JBIG2STREAM_H +#define JBIG2STREAM_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" +#include "Stream.h" + +class GList; +class JBIG2Segment; +class JBIG2Bitmap; +class JArithmeticDecoder; +class JArithmeticDecoderStats; +class JBIG2HuffmanDecoder; +struct JBIG2HuffmanTable; +class JBIG2MMRDecoder; + +//------------------------------------------------------------------------ + +class JBIG2Stream: public FilterStream { +public: + + JBIG2Stream(Stream *strA, Object *globalsStream); + virtual ~JBIG2Stream(); + virtual StreamKind getKind() { return strJBIG2; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + void readSegments(); + void readSymbolDictSeg(Guint segNum, Guint length, + Guint *refSegs, Guint nRefSegs); + void readTextRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs); + JBIG2Bitmap *readTextRegion(GBool huff, GBool refine, + int w, int h, + Guint numInstances, + Guint logStrips, + int numSyms, + JBIG2HuffmanTable *symCodeTab, + Guint symCodeLen, + JBIG2Bitmap **syms, + Guint defPixel, Guint combOp, + Guint transposed, Guint refCorner, + int sOffset, + JBIG2HuffmanTable *huffFSTable, + JBIG2HuffmanTable *huffDSTable, + JBIG2HuffmanTable *huffDTTable, + JBIG2HuffmanTable *huffRDWTable, + JBIG2HuffmanTable *huffRDHTable, + JBIG2HuffmanTable *huffRDXTable, + JBIG2HuffmanTable *huffRDYTable, + JBIG2HuffmanTable *huffRSizeTable, + Guint templ, + int *atx, int *aty); + void readPatternDictSeg(Guint segNum, Guint length); + void readHalftoneRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs); + void readGenericRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length); + JBIG2Bitmap *readGenericBitmap(GBool mmr, int w, int h, + int templ, GBool tpgdOn, + GBool useSkip, JBIG2Bitmap *skip, + int *atx, int *aty, + int mmrDataLength); + void readGenericRefinementRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, + Guint nRefSegs); + JBIG2Bitmap *readGenericRefinementRegion(int w, int h, + int templ, GBool tpgrOn, + JBIG2Bitmap *refBitmap, + int refDX, int refDY, + int *atx, int *aty); + void readPageInfoSeg(Guint length); + void readEndOfStripeSeg(Guint length); + void readProfilesSeg(Guint length); + void readCodeTableSeg(Guint segNum, Guint length); + void readExtensionSeg(Guint length); + JBIG2Segment *findSegment(Guint segNum); + void discardSegment(Guint segNum); + void resetGenericStats(Guint templ, + JArithmeticDecoderStats *prevStats); + void resetRefinementStats(Guint templ, + JArithmeticDecoderStats *prevStats); + void resetIntStats(int symCodeLen); + GBool readUByte(Guint *x); + GBool readByte(int *x); + GBool readUWord(Guint *x); + GBool readULong(Guint *x); + GBool readLong(int *x); + + Guint pageW, pageH, curPageH; + Guint pageDefPixel; + JBIG2Bitmap *pageBitmap; + Guint defCombOp; + GList *segments; // [JBIG2Segment] + GList *globalSegments; // [JBIG2Segment] + Stream *curStr; + Guchar *dataPtr; + Guchar *dataEnd; + + JArithmeticDecoder *arithDecoder; + JArithmeticDecoderStats *genericRegionStats; + JArithmeticDecoderStats *refinementRegionStats; + JArithmeticDecoderStats *iadhStats; + JArithmeticDecoderStats *iadwStats; + JArithmeticDecoderStats *iaexStats; + JArithmeticDecoderStats *iaaiStats; + JArithmeticDecoderStats *iadtStats; + JArithmeticDecoderStats *iaitStats; + JArithmeticDecoderStats *iafsStats; + JArithmeticDecoderStats *iadsStats; + JArithmeticDecoderStats *iardxStats; + JArithmeticDecoderStats *iardyStats; + JArithmeticDecoderStats *iardwStats; + JArithmeticDecoderStats *iardhStats; + JArithmeticDecoderStats *iariStats; + JArithmeticDecoderStats *iaidStats; + JBIG2HuffmanDecoder *huffDecoder; + JBIG2MMRDecoder *mmrDecoder; +}; + +#endif diff --git a/pdf2swf/xpdf/JPXStream.cc b/pdf2swf/xpdf/JPXStream.cc new file mode 100644 index 0000000..defa7d2 --- /dev/null +++ b/pdf2swf/xpdf/JPXStream.cc @@ -0,0 +1,2822 @@ +//======================================================================== +// +// JPXStream.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "Error.h" +#include "JArithmeticDecoder.h" +#include "JPXStream.h" + +//~ to do: +// - precincts +// - ROI +// - progression order changes +// - packed packet headers +// - support for palettes, channel maps, etc. +// - make sure all needed JP2/JPX subboxes are parsed (readBoxes) +// - can we assume that QCC segments must come after the QCD segment? +// - skip EPH markers (readTilePartData) +// - handle tilePartToEOC in readTilePartData +// - deal with multiple codeword segments (readTilePartData, +// readCodeBlockData) +// - progression orders 2, 3, and 4 +// - in coefficient decoding (readCodeBlockData): +// - termination pattern: terminate after every coding pass +// - error resilience segmentation symbol +// - selective arithmetic coding bypass +// - vertically causal context formation +// - coeffs longer than 31 bits (should just ignore the extra bits?) +// - handle boxes larger than 2^32 bytes +// - the fixed-point arithmetic won't handle 16-bit pixels + +//------------------------------------------------------------------------ + +// number of contexts for the arithmetic decoder +#define jpxNContexts 19 + +#define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup +#define jpxContextSign 9 // 9 - 13: sign +#define jpxContextMagRef 14 // 14 -16: magnitude refinement +#define jpxContextRunLength 17 // cleanup: run length +#define jpxContextUniform 18 // cleanup: first signif coeff + +//------------------------------------------------------------------------ + +#define jpxPassSigProp 0 +#define jpxPassMagRef 1 +#define jpxPassCleanup 2 + +//------------------------------------------------------------------------ + +// arithmetic decoder context for the significance propagation and +// cleanup passes: +// [horiz][vert][diag][subband] +// where subband = 0 for HL +// = 1 for LH and LL +// = 2 for HH +static Guint sigPropContext[3][3][5][3] = { + {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0 + { 1, 1, 3 }, // horiz=0, vert=0, diag=1 + { 2, 2, 6 }, // horiz=0, vert=0, diag=2 + { 2, 2, 8 }, // horiz=0, vert=0, diag=3 + { 2, 2, 8 }}, // horiz=0, vert=0, diag=4 + {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0 + { 6, 3, 4 }, // horiz=0, vert=1, diag=1 + { 6, 3, 7 }, // horiz=0, vert=1, diag=2 + { 6, 3, 8 }, // horiz=0, vert=1, diag=3 + { 6, 3, 8 }}, // horiz=0, vert=1, diag=4 + {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0 + { 8, 4, 5 }, // horiz=0, vert=2, diag=1 + { 8, 4, 7 }, // horiz=0, vert=2, diag=2 + { 8, 4, 8 }, // horiz=0, vert=2, diag=3 + { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4 + {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0 + { 3, 6, 4 }, // horiz=1, vert=0, diag=1 + { 3, 6, 7 }, // horiz=1, vert=0, diag=2 + { 3, 6, 8 }, // horiz=1, vert=0, diag=3 + { 3, 6, 8 }}, // horiz=1, vert=0, diag=4 + {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0 + { 7, 7, 5 }, // horiz=1, vert=1, diag=1 + { 7, 7, 7 }, // horiz=1, vert=1, diag=2 + { 7, 7, 8 }, // horiz=1, vert=1, diag=3 + { 7, 7, 8 }}, // horiz=1, vert=1, diag=4 + {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0 + { 8, 7, 5 }, // horiz=1, vert=2, diag=1 + { 8, 7, 7 }, // horiz=1, vert=2, diag=2 + { 8, 7, 8 }, // horiz=1, vert=2, diag=3 + { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4 + {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0 + { 4, 8, 5 }, // horiz=2, vert=0, diag=1 + { 4, 8, 7 }, // horiz=2, vert=0, diag=2 + { 4, 8, 8 }, // horiz=2, vert=0, diag=3 + { 4, 8, 8 }}, // horiz=2, vert=0, diag=4 + {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0 + { 7, 8, 5 }, // horiz=2, vert=1, diag=1 + { 7, 8, 7 }, // horiz=2, vert=1, diag=2 + { 7, 8, 8 }, // horiz=2, vert=1, diag=3 + { 7, 8, 8 }}, // horiz=2, vert=1, diag=4 + {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0 + { 8, 8, 5 }, // horiz=2, vert=2, diag=1 + { 8, 8, 7 }, // horiz=2, vert=2, diag=2 + { 8, 8, 8 }, // horiz=2, vert=2, diag=3 + { 8, 8, 8 }}} // horiz=2, vert=2, diag=4 +}; + +// arithmetic decoder context and xor bit for the sign bit in the +// significance propagation pass: +// [horiz][vert][k] +// where horiz/vert are offset by 2 (i.e., range is -2 .. 2) +// and k = 0 for the context +// = 1 for the xor bit +static Guint signContext[5][5][2] = { + {{ 13, 1 }, // horiz=-2, vert=-2 + { 13, 1 }, // horiz=-2, vert=-1 + { 12, 1 }, // horiz=-2, vert= 0 + { 11, 1 }, // horiz=-2, vert=+1 + { 11, 1 }}, // horiz=-2, vert=+2 + {{ 13, 1 }, // horiz=-1, vert=-2 + { 13, 1 }, // horiz=-1, vert=-1 + { 12, 1 }, // horiz=-1, vert= 0 + { 11, 1 }, // horiz=-1, vert=+1 + { 11, 1 }}, // horiz=-1, vert=+2 + {{ 10, 1 }, // horiz= 0, vert=-2 + { 10, 1 }, // horiz= 0, vert=-1 + { 9, 0 }, // horiz= 0, vert= 0 + { 10, 0 }, // horiz= 0, vert=+1 + { 10, 0 }}, // horiz= 0, vert=+2 + {{ 11, 0 }, // horiz=+1, vert=-2 + { 11, 0 }, // horiz=+1, vert=-1 + { 12, 0 }, // horiz=+1, vert= 0 + { 13, 0 }, // horiz=+1, vert=+1 + { 13, 0 }}, // horiz=+1, vert=+2 + {{ 11, 0 }, // horiz=+2, vert=-2 + { 11, 0 }, // horiz=+2, vert=-1 + { 12, 0 }, // horiz=+2, vert= 0 + { 13, 0 }, // horiz=+2, vert=+1 + { 13, 0 }}, // horiz=+2, vert=+2 +}; + +//------------------------------------------------------------------------ + +// constants used in the IDWT +#define idwtAlpha -1.586134342059924 +#define idwtBeta -0.052980118572961 +#define idwtGamma 0.882911075530934 +#define idwtDelta 0.443506852043971 +#define idwtKappa 1.230174104914001 +#define idwtIKappa (1.0 / idwtKappa) + +// number of bits to the right of the decimal point for the fixed +// point arithmetic used in the IDWT +#define fracBits 16 + +//------------------------------------------------------------------------ + +// floor(x / y) +#define jpxFloorDiv(x, y) ((x) / (y)) + +// floor(x / 2^y) +#define jpxFloorDivPow2(x, y) ((x) >> (y)) + +// ceil(x / y) +#define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y)) + +// ceil(x / 2^y) +#define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y)) + +//------------------------------------------------------------------------ + +JPXStream::JPXStream(Stream *strA): + FilterStream(strA) +{ + nComps = 0; + bpc = NULL; + width = height = 0; + haveCS = gFalse; + havePalette = gFalse; + haveCompMap = gFalse; + haveChannelDefn = gFalse; + + img.tiles = NULL; + bitBuf = 0; + bitBufLen = 0; + bitBufSkip = gFalse; + byteCount = 0; +} + +JPXStream::~JPXStream() { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + Guint comp, i, k, r, pre, sb; + + gfree(bpc); + if (havePalette) { + gfree(palette.bpc); + gfree(palette.c); + } + if (haveCompMap) { + gfree(compMap.comp); + gfree(compMap.type); + gfree(compMap.pComp); + } + if (haveChannelDefn) { + gfree(channelDefn.idx); + gfree(channelDefn.type); + gfree(channelDefn.assoc); + } + + if (img.tiles) { + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + tile = &img.tiles[i]; + if (tile->tileComps) { + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + gfree(tileComp->quantSteps); + gfree(tileComp->data); + gfree(tileComp->buf); + if (tileComp->resLevels) { + for (r = 0; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + if (resLevel->precincts) { + for (pre = 0; pre < 1; ++pre) { + precinct = &resLevel->precincts[pre]; + if (precinct->subbands) { + for (sb = 0; sb < (r == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + gfree(subband->inclusion); + gfree(subband->zeroBitPlane); + if (subband->cbs) { + for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) { + cb = &subband->cbs[k]; + gfree(cb->coeffs); + if (cb->stats) { + delete cb->stats; + } + } + gfree(subband->cbs); + } + } + gfree(precinct->subbands); + } + } + gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts); + } + } + gfree(img.tiles[i].tileComps[comp].resLevels); + } + } + gfree(img.tiles[i].tileComps); + } + } + gfree(img.tiles); + } + delete str; +} + +void JPXStream::reset() { + str->reset(); + if (readBoxes()) { + curY = img.yOffset; + } else { + // readBoxes reported an error, so we go immediately to EOF + curY = img.ySize; + } + curX = img.xOffset; + curComp = 0; + readBufLen = 0; +} + +int JPXStream::getChar() { + int c; + + if (readBufLen < 8) { + fillReadBuf(); + } + if (readBufLen == 8) { + c = readBuf & 0xff; + readBufLen = 0; + } else if (readBufLen > 8) { + c = (readBuf >> (readBufLen - 8)) & 0xff; + readBufLen -= 8; + } else if (readBufLen == 0) { + c = EOF; + } else { + c = (readBuf << (8 - readBufLen)) & 0xff; + readBufLen = 0; + } + return c; +} + +int JPXStream::lookChar() { + int c; + + if (readBufLen < 8) { + fillReadBuf(); + } + if (readBufLen == 8) { + c = readBuf & 0xff; + } else if (readBufLen > 8) { + c = (readBuf >> (readBufLen - 8)) & 0xff; + } else if (readBufLen == 0) { + c = EOF; + } else { + c = (readBuf << (8 - readBufLen)) & 0xff; + } + return c; +} + +void JPXStream::fillReadBuf() { + JPXTileComp *tileComp; + Guint tileIdx, tx, ty; + int pix, pixBits; + + do { + if (curY >= img.ySize) { + return; + } + tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles + + (curX - img.xTileOffset) / img.xTileSize; +#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid + tileComp = &img.tiles[tileIdx].tileComps[curComp]; +#else + tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp]; +#endif + tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep); + ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep); + pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx]; + pixBits = tileComp->prec; +#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid + if (++curComp == img.nComps) { +#else + if (havePalette) { + if (pix >= 0 && pix < palette.nEntries) { + pix = palette.c[pix * palette.nComps + curComp]; + } else { + pix = + pixBits = palette.bpc[curComp]; + } + if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) { +#endif + curComp = 0; + if (++curX == img.xSize) { + curX = img.xOffset; + ++curY; + } + } + if (pixBits == 8) { + readBuf = (readBuf << 8) | (pix & 0xff); + } else { + readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1)); + } + readBufLen += pixBits; + } while (readBufLen < 8); +} + +GString *JPXStream::getPSFilter(int psLevel, char *indent) { + return NULL; +} + +GBool JPXStream::isBinary(GBool last) { + return str->isBinary(gTrue); +} + +GBool JPXStream::readBoxes() { + Guint boxType, boxLen, dataLen; + Guint bpc1, compression, unknownColorspace, ipr; + Guint i, j; + + haveImgHdr = gFalse; + + // check for a naked JPEG 2000 codestream (without the JP2/JPX + // wrapper) -- this appears to be a violation of the PDF spec, but + // Acrobat allows it + if (str->lookChar() == 0xff) { + error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper"); + readCodestream(0); + nComps = img.nComps; + bpc = (Guint *)gmalloc(nComps * sizeof(Guint)); + for (i = 0; i < nComps; ++i) { + bpc[i] = img.tiles[0].tileComps[i].prec; + } + width = img.xSize - img.xOffset; + height = img.ySize - img.yOffset; + return gTrue; + } + + while (readBoxHdr(&boxType, &boxLen, &dataLen)) { + switch (boxType) { + case 0x6a703268: // JP2 header + // this is a grouping box ('superbox') which has no real + // contents and doesn't appear to be used consistently, i.e., + // some things which should be subboxes of the JP2 header box + // show up outside of it - so we simply ignore the JP2 header + // box + break; + case 0x69686472: // image header + if (!readULong(&height) || + !readULong(&width) || + !readUWord(&nComps) || + !readUByte(&bpc1) || + !readUByte(&compression) || + !readUByte(&unknownColorspace) || + !readUByte(&ipr)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + if (compression != 7) { + error(getPos(), "Unknown compression type in JPX stream"); + return gFalse; + } + bpc = (Guint *)gmalloc(nComps * sizeof(Guint)); + for (i = 0; i < nComps; ++i) { + bpc[i] = bpc1; + } + haveImgHdr = gTrue; + break; + case 0x62706363: // bits per component + if (!haveImgHdr) { + error(getPos(), "Found bits per component box before image header box in JPX stream"); + return gFalse; + } + if (dataLen != nComps) { + error(getPos(), "Invalid bits per component box in JPX stream"); + return gFalse; + } + for (i = 0; i < nComps; ++i) { + if (!readUByte(&bpc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + break; + case 0x636F6C72: // color specification + if (!readColorSpecBox(dataLen)) { + return gFalse; + } + break; + case 0x70636c72: // palette + if (!readUWord(&palette.nEntries) || + !readUByte(&palette.nComps)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + palette.bpc = (Guint *)gmalloc(palette.nComps * sizeof(Guint)); + palette.c = + (int *)gmalloc(palette.nEntries * palette.nComps * sizeof(int)); + for (i = 0; i < palette.nComps; ++i) { + if (!readUByte(&palette.bpc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + ++palette.bpc[i]; + } + for (i = 0; i < palette.nEntries; ++i) { + for (j = 0; j < palette.nComps; ++j) { + if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3, + (palette.bpc[j] & 0x80) ? gTrue : gFalse, + &palette.c[i * palette.nComps + j])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + } + havePalette = gTrue; + break; + case 0x636d6170: // component mapping + compMap.nChannels = dataLen / 4; + compMap.comp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint)); + compMap.type = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint)); + compMap.pComp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint)); + for (i = 0; i < compMap.nChannels; ++i) { + if (!readUWord(&compMap.comp[i]) || + !readUByte(&compMap.type[i]) || + !readUByte(&compMap.pComp[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + haveCompMap = gTrue; + break; + case 0x63646566: // channel definition + if (!readUWord(&channelDefn.nChannels)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + channelDefn.idx = + (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + channelDefn.type = + (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + channelDefn.assoc = + (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + for (i = 0; i < channelDefn.nChannels; ++i) { + if (!readUWord(&channelDefn.idx[i]) || + !readUWord(&channelDefn.type[i]) || + !readUWord(&channelDefn.assoc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + haveChannelDefn = gTrue; + break; + case 0x6A703263: // contiguous codestream + if (!bpc) { + error(getPos(), "JPX stream is missing the image header box"); + return gFalse; + } + if (!haveCS) { + error(getPos(), "JPX stream has no supported color spec"); + return gFalse; + } + if (!readCodestream(dataLen)) { + return gFalse; + } + break; + default: + for (i = 0; i < dataLen; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + break; + } + } + return gTrue; +} + +GBool JPXStream::readColorSpecBox(Guint dataLen) { + JPXColorSpec newCS; + Guint csApprox, csEnum; + Guint i; + GBool ok; + + ok = gFalse; + if (!readUByte(&newCS.meth) || + !readByte(&newCS.prec) || + !readUByte(&csApprox)) { + goto err; + } + switch (newCS.meth) { + case 1: // enumerated colorspace + if (!readULong(&csEnum)) { + goto err; + } + newCS.enumerated.type = (JPXColorSpaceType)csEnum; + switch (newCS.enumerated.type) { + case jpxCSBiLevel: + ok = gTrue; + break; + case jpxCSYCbCr1: + ok = gTrue; + break; + case jpxCSYCbCr2: + ok = gTrue; + break; + case jpxCSYCBCr3: + ok = gTrue; + break; + case jpxCSPhotoYCC: + ok = gTrue; + break; + case jpxCSCMY: + ok = gTrue; + break; + case jpxCSCMYK: + ok = gTrue; + break; + case jpxCSYCCK: + ok = gTrue; + break; + case jpxCSCIELab: + if (dataLen == 3 + 7*4) { + if (!readULong(&newCS.enumerated.cieLab.rl) || + !readULong(&newCS.enumerated.cieLab.ol) || + !readULong(&newCS.enumerated.cieLab.ra) || + !readULong(&newCS.enumerated.cieLab.oa) || + !readULong(&newCS.enumerated.cieLab.rb) || + !readULong(&newCS.enumerated.cieLab.ob) || + !readULong(&newCS.enumerated.cieLab.il)) { + goto err; + } + } else if (dataLen == 3) { + //~ this assumes the 8-bit case + newCS.enumerated.cieLab.rl = 100; + newCS.enumerated.cieLab.ol = 0; + newCS.enumerated.cieLab.ra = 255; + newCS.enumerated.cieLab.oa = 128; + newCS.enumerated.cieLab.rb = 255; + newCS.enumerated.cieLab.ob = 96; + newCS.enumerated.cieLab.il = 0x00443530; + } else { + goto err; + } + ok = gTrue; + break; + case jpxCSsRGB: + ok = gTrue; + break; + case jpxCSGrayscale: + ok = gTrue; + break; + case jpxCSBiLevel2: + ok = gTrue; + break; + case jpxCSCIEJab: + // not allowed in PDF + goto err; + case jpxCSCISesRGB: + ok = gTrue; + break; + case jpxCSROMMRGB: + ok = gTrue; + break; + case jpxCSsRGBYCbCr: + ok = gTrue; + break; + case jpxCSYPbPr1125: + ok = gTrue; + break; + case jpxCSYPbPr1250: + ok = gTrue; + break; + default: + goto err; + } + break; + case 2: // restricted ICC profile + case 3: // any ICC profile (JPX) + case 4: // vendor color (JPX) + for (i = 0; i < dataLen - 3; ++i) { + if (str->getChar() == EOF) { + goto err; + } + } + break; + } + + if (ok && (!haveCS || newCS.prec > cs.prec)) { + cs = newCS; + haveCS = gTrue; + } + + return gTrue; + + err: + error(getPos(), "Error in JPX color spec"); + return gFalse; +} + +GBool JPXStream::readCodestream(Guint len) { + JPXTile *tile; + JPXTileComp *tileComp; + int segType; + GBool haveSIZ, haveCOD, haveQCD, haveSOT; + Guint precinctSize, style; + Guint segLen, capabilities, comp, i, j, r; + + //----- main header + haveSIZ = haveCOD = haveQCD = haveSOT = gFalse; + do { + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX codestream"); + return gFalse; + } + switch (segType) { + case 0x4f: // SOC - start of codestream + // marker only + break; + case 0x51: // SIZ - image and tile size + if (!readUWord(&capabilities) || + !readULong(&img.xSize) || + !readULong(&img.ySize) || + !readULong(&img.xOffset) || + !readULong(&img.yOffset) || + !readULong(&img.xTileSize) || + !readULong(&img.yTileSize) || + !readULong(&img.xTileOffset) || + !readULong(&img.yTileOffset) || + !readUWord(&img.nComps)) { + error(getPos(), "Error in JPX SIZ marker segment"); + return gFalse; + } + if (haveImgHdr && img.nComps != nComps) { + error(getPos(), "Different number of components in JPX SIZ marker segment"); + return gFalse; + } + img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1) + / img.xTileSize; + img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) + / img.yTileSize; + img.tiles = (JPXTile *)gmalloc(img.nXTiles * img.nYTiles * + sizeof(JPXTile)); + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps = (JPXTileComp *)gmalloc(img.nComps * + sizeof(JPXTileComp)); + for (comp = 0; comp < img.nComps; ++comp) { + img.tiles[i].tileComps[comp].quantSteps = NULL; + img.tiles[i].tileComps[comp].data = NULL; + img.tiles[i].tileComps[comp].buf = NULL; + img.tiles[i].tileComps[comp].resLevels = NULL; + } + } + for (comp = 0; comp < img.nComps; ++comp) { + if (!readUByte(&img.tiles[0].tileComps[comp].prec) || + !readUByte(&img.tiles[0].tileComps[comp].hSep) || + !readUByte(&img.tiles[0].tileComps[comp].vSep)) { + error(getPos(), "Error in JPX SIZ marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].sgned = + (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse; + img.tiles[0].tileComps[comp].prec = + (img.tiles[0].tileComps[comp].prec & 0x7f) + 1; + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp]; + } + } + haveSIZ = gTrue; + break; + case 0x52: // COD - coding style default + if (!readUByte(&img.tiles[0].tileComps[0].style) || + !readUByte(&img.tiles[0].progOrder) || + !readUWord(&img.tiles[0].nLayers) || + !readUByte(&img.tiles[0].multiComp) || + !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockW) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockH) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) || + !readUByte(&img.tiles[0].tileComps[0].transform)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[0].codeBlockW += 2; + img.tiles[0].tileComps[0].codeBlockH += 2; + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + if (i != 0) { + img.tiles[i].progOrder = img.tiles[0].progOrder; + img.tiles[i].nLayers = img.tiles[0].nLayers; + img.tiles[i].multiComp = img.tiles[0].multiComp; + } + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + img.tiles[i].tileComps[comp].style = + img.tiles[0].tileComps[0].style; + img.tiles[i].tileComps[comp].nDecompLevels = + img.tiles[0].tileComps[0].nDecompLevels; + img.tiles[i].tileComps[comp].codeBlockW = + img.tiles[0].tileComps[0].codeBlockW; + img.tiles[i].tileComps[comp].codeBlockH = + img.tiles[0].tileComps[0].codeBlockH; + img.tiles[i].tileComps[comp].codeBlockStyle = + img.tiles[0].tileComps[0].codeBlockStyle; + img.tiles[i].tileComps[comp].transform = + img.tiles[0].tileComps[0].transform; + } + img.tiles[i].tileComps[comp].resLevels = + (JPXResLevel *)gmalloc( + (img.tiles[i].tileComps[comp].nDecompLevels + 1) * + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; + } + } + } + for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) { + if (img.tiles[0].tileComps[0].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[0].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[0].tileComps[0].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15; + img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15; + } + } + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[0].tileComps[0].resLevels[r].precinctWidth; + img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[0].tileComps[0].resLevels[r].precinctHeight; + } + } + } + } + haveCOD = gTrue; + break; + case 0x53: // COC - coding style component + if (!haveCOD) { + error(getPos(), "JPX COC marker segment before COD segment"); + return gFalse; + } + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&style) || + !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) || + !readUByte(&img.tiles[0].tileComps[comp].transform)) { + error(getPos(), "Error in JPX COC marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].style = + (img.tiles[0].tileComps[comp].style & ~1) | (style & 1); + img.tiles[0].tileComps[comp].codeBlockW += 2; + img.tiles[0].tileComps[comp].codeBlockH += 2; + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + if (i != 0) { + img.tiles[i].tileComps[comp].style = + img.tiles[0].tileComps[comp].style; + img.tiles[i].tileComps[comp].nDecompLevels = + img.tiles[0].tileComps[comp].nDecompLevels; + img.tiles[i].tileComps[comp].codeBlockW = + img.tiles[0].tileComps[comp].codeBlockW; + img.tiles[i].tileComps[comp].codeBlockH = + img.tiles[0].tileComps[comp].codeBlockH; + img.tiles[i].tileComps[comp].codeBlockStyle = + img.tiles[0].tileComps[comp].codeBlockStyle; + img.tiles[i].tileComps[comp].transform = + img.tiles[0].tileComps[comp].transform; + } + img.tiles[i].tileComps[comp].resLevels = + (JPXResLevel *)grealloc( + img.tiles[i].tileComps[comp].resLevels, + (img.tiles[i].tileComps[comp].nDecompLevels + 1) * + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; + } + } + for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) { + if (img.tiles[0].tileComps[comp].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15; + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15; + } + } + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth; + img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight; + } + } + break; + case 0x5c: // QCD - quantization default + if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) { + img.tiles[0].tileComps[0].nQuantSteps = segLen - 3; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps * + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) { + img.tiles[0].tileComps[0].nQuantSteps = 1; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps * + sizeof(Guint)); + if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) { + img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps * + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + img.tiles[i].tileComps[comp].quantStyle = + img.tiles[0].tileComps[0].quantStyle; + img.tiles[i].tileComps[comp].nQuantSteps = + img.tiles[0].tileComps[0].nQuantSteps; + img.tiles[i].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps * + sizeof(Guint)); + for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) { + img.tiles[i].tileComps[comp].quantSteps[j] = + img.tiles[0].tileComps[0].quantSteps[j]; + } + } + } + } + haveQCD = gTrue; + break; + case 0x5d: // QCC - quantization component + if (!haveQCD) { + error(getPos(), "JPX QCC marker segment before QCD segment"); + return gFalse; + } + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) { + img.tiles[0].tileComps[comp].nQuantSteps = + segLen - (img.nComps > 256 ? 5 : 4); + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps * + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } + } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) { + img.tiles[0].tileComps[comp].nQuantSteps = 1; + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps * + sizeof(Guint)); + if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) { + img.tiles[0].tileComps[comp].nQuantSteps = + (segLen - (img.nComps > 256 ? 5 : 4)) / 2; + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps * + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps[comp].quantStyle = + img.tiles[0].tileComps[comp].quantStyle; + img.tiles[i].tileComps[comp].nQuantSteps = + img.tiles[0].tileComps[comp].nQuantSteps; + img.tiles[i].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps * + sizeof(Guint)); + for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) { + img.tiles[i].tileComps[comp].quantSteps[j] = + img.tiles[0].tileComps[comp].quantSteps[j]; + } + } + break; + case 0x5e: // RGN - region of interest +#if 1 //~ ROI is unimplemented + fprintf(stderr, "RGN\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&compInfo[comp].defROI.style) || + !readUByte(&compInfo[comp].defROI.shift)) { + error(getPos(), "Error in JPX RGN marker segment"); + return gFalse; + } +#endif + break; + case 0x5f: // POC - progression order change +#if 1 //~ progression order changes are unimplemented + fprintf(stderr, "POC\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); + progs = (JPXProgOrder *)gmalloc(nProgs * sizeof(JPXProgOrder)); + for (i = 0; i < nProgs; ++i) { + if (!readUByte(&progs[i].startRes) || + !(img.nComps > 256 && readUWord(&progs[i].startComp)) || + !(img.nComps <= 256 && readUByte(&progs[i].startComp)) || + !readUWord(&progs[i].endLayer) || + !readUByte(&progs[i].endRes) || + !(img.nComps > 256 && readUWord(&progs[i].endComp)) || + !(img.nComps <= 256 && readUByte(&progs[i].endComp)) || + !readUByte(&progs[i].progOrder)) { + error(getPos(), "Error in JPX POC marker segment"); + return gFalse; + } + } +#endif + break; + case 0x60: // PPM - packed packet headers, main header +#if 1 //~ packed packet headers are unimplemented + fprintf(stderr, "PPM\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#endif + break; + case 0x55: // TLM - tile-part lengths + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX TLM marker segment"); + return gFalse; + } + } + break; + case 0x57: // PLM - packet length, main header + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PLM marker segment"); + return gFalse; + } + } + break; + case 0x63: // CRG - component registration + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX CRG marker segment"); + return gFalse; + } + } + break; + case 0x64: // COM - comment + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX COM marker segment"); + return gFalse; + } + } + break; + case 0x90: // SOT - start of tile + haveSOT = gTrue; + break; + default: + error(getPos(), "Unknown marker segment %02x in JPX stream", segType); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + break; + } + } + break; + } + } while (!haveSOT); + + if (!haveSIZ) { + error(getPos(), "Missing SIZ marker segment in JPX stream"); + return gFalse; + } + if (!haveCOD) { + error(getPos(), "Missing COD marker segment in JPX stream"); + return gFalse; + } + if (!haveQCD) { + error(getPos(), "Missing QCD marker segment in JPX stream"); + return gFalse; + } + + //----- read the tile-parts + while (1) { + if (!readTilePart()) { + return gFalse; + } + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX codestream"); + return gFalse; + } + if (segType != 0x90) { // SOT - start of tile + break; + } + } + + if (segType != 0xd9) { // EOC - end of codestream + error(getPos(), "Missing EOC marker in JPX codestream"); + return gFalse; + } + + //----- finish decoding the image + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + tile = &img.tiles[i]; + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + inverseTransform(tileComp); + } + if (!inverseMultiCompAndDC(tile)) { + return gFalse; + } + } + + //~ can free memory below tileComps here, and also tileComp.buf + + return gTrue; +} + +GBool JPXStream::readTilePart() { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + GBool haveSOD; + Guint tileIdx, tilePartLen, tilePartIdx, nTileParts; + GBool tilePartToEOC; + Guint precinctSize, style; + Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen; + Guint i, j, k, cbX, cbY, r, pre, sb, cbi; + int segType, level; + + // process the SOT marker segment + if (!readUWord(&tileIdx) || + !readULong(&tilePartLen) || + !readUByte(&tilePartIdx) || + !readUByte(&nTileParts)) { + error(getPos(), "Error in JPX SOT marker segment"); + return gFalse; + } + + if (tileIdx >= img.nXTiles * img.nYTiles) { + error(getPos(), "Weird tile index in JPX stream"); + return gFalse; + } + + tilePartToEOC = tilePartLen == 0; + tilePartLen -= 12; // subtract size of SOT segment + + haveSOD = gFalse; + do { + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX tile-part codestream"); + return gFalse; + } + tilePartLen -= 2 + segLen; + switch (segType) { + case 0x52: // COD - coding style default + if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) || + !readUByte(&img.tiles[tileIdx].progOrder) || + !readUWord(&img.tiles[tileIdx].nLayers) || + !readUByte(&img.tiles[tileIdx].multiComp) || + !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) || + !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[0].codeBlockW += 2; + img.tiles[tileIdx].tileComps[0].codeBlockH += 2; + for (comp = 0; comp < img.nComps; ++comp) { + if (comp != 0) { + img.tiles[tileIdx].tileComps[comp].style = + img.tiles[tileIdx].tileComps[0].style; + img.tiles[tileIdx].tileComps[comp].nDecompLevels = + img.tiles[tileIdx].tileComps[0].nDecompLevels; + img.tiles[tileIdx].tileComps[comp].codeBlockW = + img.tiles[tileIdx].tileComps[0].codeBlockW; + img.tiles[tileIdx].tileComps[comp].codeBlockH = + img.tiles[tileIdx].tileComps[0].codeBlockH; + img.tiles[tileIdx].tileComps[comp].codeBlockStyle = + img.tiles[tileIdx].tileComps[0].codeBlockStyle; + img.tiles[tileIdx].tileComps[comp].transform = + img.tiles[tileIdx].tileComps[0].transform; + } + img.tiles[tileIdx].tileComps[comp].resLevels = + (JPXResLevel *)grealloc( + img.tiles[tileIdx].tileComps[comp].resLevels, + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) * + sizeof(JPXResLevel)); + for (r = 0; + r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; + ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; + } + } + for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) { + if (img.tiles[tileIdx].tileComps[0].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15; + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15; + } + } + for (comp = 1; comp < img.nComps; ++comp) { + for (r = 0; + r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; + ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight; + } + } + break; + case 0x53: // COC - coding style component + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&style) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) { + error(getPos(), "Error in JPX COC marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[comp].style = + (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1); + img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; + img.tiles[tileIdx].tileComps[comp].codeBlockH += 2; + img.tiles[tileIdx].tileComps[comp].resLevels = + (JPXResLevel *)grealloc( + img.tiles[tileIdx].tileComps[comp].resLevels, + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) * + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; + } + for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { + if (img.tiles[tileIdx].tileComps[comp].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15; + } + } + break; + case 0x5c: // QCD - quantization default + if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = + segLen - 3; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps * + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = 1; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps * + sizeof(Guint)); + if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps * + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + for (comp = 1; comp < img.nComps; ++comp) { + img.tiles[tileIdx].tileComps[comp].quantStyle = + img.tiles[tileIdx].tileComps[0].quantStyle; + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + img.tiles[tileIdx].tileComps[0].nQuantSteps; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps * + sizeof(Guint)); + for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) { + img.tiles[tileIdx].tileComps[comp].quantSteps[j] = + img.tiles[tileIdx].tileComps[0].quantSteps[j]; + } + } + break; + case 0x5d: // QCC - quantization component + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + segLen - (img.nComps > 256 ? 5 : 4); + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps * + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } + } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) + == 0x01) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps * + sizeof(Guint)); + if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) + == 0x02) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + (segLen - (img.nComps > 256 ? 5 : 4)) / 2; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps * + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + break; + case 0x5e: // RGN - region of interest +#if 1 //~ ROI is unimplemented + fprintf(stderr, "RGN\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&compInfo[comp].roi.style) || + !readUByte(&compInfo[comp].roi.shift)) { + error(getPos(), "Error in JPX RGN marker segment"); + return gFalse; + } +#endif + break; + case 0x5f: // POC - progression order change +#if 1 //~ progression order changes are unimplemented + fprintf(stderr, "POC\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); + tileProgs = (JPXProgOrder *)gmalloc(nTileProgs * sizeof(JPXProgOrder)); + for (i = 0; i < nTileProgs; ++i) { + if (!readUByte(&tileProgs[i].startRes) || + !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) || + !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) || + !readUWord(&tileProgs[i].endLayer) || + !readUByte(&tileProgs[i].endRes) || + !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) || + !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) || + !readUByte(&tileProgs[i].progOrder)) { + error(getPos(), "Error in JPX POC marker segment"); + return gFalse; + } + } +#endif + break; + case 0x61: // PPT - packed packet headers, tile-part hdr +#if 1 //~ packed packet headers are unimplemented + fprintf(stderr, "PPT\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPT marker segment"); + return gFalse; + } + } +#endif + case 0x58: // PLT - packet length, tile-part header + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PLT marker segment"); + return gFalse; + } + } + break; + case 0x64: // COM - comment + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX COM marker segment"); + return gFalse; + } + } + break; + case 0x93: // SOD - start of data + haveSOD = gTrue; + break; + default: + error(getPos(), "Unknown marker segment %02x in JPX tile-part stream", + segType); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + break; + } + } + break; + } + } while (!haveSOD); + + //----- initialize the tile, precincts, and code-blocks + if (tilePartIdx == 0) { + tile = &img.tiles[tileIdx]; + i = tileIdx / img.nXTiles; + j = tileIdx % img.nXTiles; + if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) { + tile->x0 = img.xOffset; + } + if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) { + tile->y0 = img.yOffset; + } + if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) { + tile->x1 = img.xSize; + } + if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) { + tile->y1 = img.ySize; + } + tile->comp = 0; + tile->res = 0; + tile->precinct = 0; + tile->layer = 0; + tile->maxNDecompLevels = 0; + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + if (tileComp->nDecompLevels > tile->maxNDecompLevels) { + tile->maxNDecompLevels = tileComp->nDecompLevels; + } + tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep); + tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->hSep); + tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep); + tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep); + tileComp->cbW = 1 << tileComp->codeBlockW; + tileComp->cbH = 1 << tileComp->codeBlockH; + tileComp->data = (int *)gmalloc((tileComp->x1 - tileComp->x0) * + (tileComp->y1 - tileComp->y0) * + sizeof(int)); + if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { + n = tileComp->x1 - tileComp->x0; + } else { + n = tileComp->y1 - tileComp->y0; + } + tileComp->buf = (int *)gmalloc((n + 8) * sizeof(int)); + for (r = 0; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + k = r == 0 ? tileComp->nDecompLevels + : tileComp->nDecompLevels - r + 1; + resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k); + resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k); + resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k); + resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k); + if (r == 0) { + resLevel->bx0[0] = resLevel->x0; + resLevel->by0[0] = resLevel->y0; + resLevel->bx1[0] = resLevel->x1; + resLevel->by1[0] = resLevel->y1; + } else { + resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); + resLevel->by0[0] = resLevel->y0; + resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); + resLevel->by1[0] = resLevel->y1; + resLevel->bx0[1] = resLevel->x0; + resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); + resLevel->bx1[1] = resLevel->x1; + resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); + resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); + resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); + resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); + resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); + } + resLevel->precincts = (JPXPrecinct *)gmalloc(1 * sizeof(JPXPrecinct)); + for (pre = 0; pre < 1; ++pre) { + precinct = &resLevel->precincts[pre]; + precinct->x0 = resLevel->x0; + precinct->y0 = resLevel->y0; + precinct->x1 = resLevel->x1; + precinct->y1 = resLevel->y1; + nSBs = r == 0 ? 1 : 3; + precinct->subbands = + (JPXSubband *)gmalloc(nSBs * sizeof(JPXSubband)); + for (sb = 0; sb < nSBs; ++sb) { + subband = &precinct->subbands[sb]; + subband->x0 = resLevel->bx0[sb]; + subband->y0 = resLevel->by0[sb]; + subband->x1 = resLevel->bx1[sb]; + subband->y1 = resLevel->by1[sb]; + subband->nXCBs = jpxCeilDivPow2(subband->x1, + tileComp->codeBlockW) + - jpxFloorDivPow2(subband->x0, + tileComp->codeBlockW); + subband->nYCBs = jpxCeilDivPow2(subband->y1, + tileComp->codeBlockH) + - jpxFloorDivPow2(subband->y0, + tileComp->codeBlockH); + n = subband->nXCBs > subband->nYCBs ? subband->nXCBs + : subband->nYCBs; + for (subband->maxTTLevel = 0, --n; + n; + ++subband->maxTTLevel, n >>= 1) ; + n = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + n += nx * ny; + } + subband->inclusion = + (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode)); + subband->zeroBitPlane = + (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode)); + for (k = 0; k < n; ++k) { + subband->inclusion[k].finished = gFalse; + subband->inclusion[k].val = 0; + subband->zeroBitPlane[k].finished = gFalse; + subband->zeroBitPlane[k].val = 0; + } + subband->cbs = (JPXCodeBlock *)gmalloc(subband->nXCBs * + subband->nYCBs * + sizeof(JPXCodeBlock)); + sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW); + sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH); + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW; + cb->x1 = cb->x0 + tileComp->cbW; + if (subband->x0 > cb->x0) { + cb->x0 = subband->x0; + } + if (subband->x1 < cb->x1) { + cb->x1 = subband->x1; + } + cb->y0 = (sby0 + cbY) << tileComp->codeBlockH; + cb->y1 = cb->y0 + tileComp->cbH; + if (subband->y0 > cb->y0) { + cb->y0 = subband->y0; + } + if (subband->y1 < cb->y1) { + cb->y1 = subband->y1; + } + cb->seen = gFalse; + cb->lBlock = 3; + cb->nextPass = jpxPassCleanup; + cb->nZeroBitPlanes = 0; + cb->coeffs = + (JPXCoeff *)gmalloc((1 << (tileComp->codeBlockW + + tileComp->codeBlockH)) + * sizeof(JPXCoeff)); + for (cbi = 0; + cbi < (Guint)(1 << (tileComp->codeBlockW + + tileComp->codeBlockH)); + ++cbi) { + cb->coeffs[cbi].flags = 0; + cb->coeffs[cbi].len = 0; + cb->coeffs[cbi].mag = 0; + } + cb->stats = new JArithmeticDecoderStats(jpxNContexts); + cb->stats->setEntry(jpxContextSigProp, 4, 0); + cb->stats->setEntry(jpxContextRunLength, 3, 0); + cb->stats->setEntry(jpxContextUniform, 46, 0); + ++cb; + } + } + } + } + } + } + } + + return readTilePartData(tileIdx, tilePartLen, tilePartToEOC); +} + +GBool JPXStream::readTilePartData(Guint tileIdx, + Guint tilePartLen, GBool tilePartToEOC) { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + Guint ttVal; + Guint bits, cbX, cbY, nx, ny, i, j, n, sb; + int level; + + tile = &img.tiles[tileIdx]; + + // read all packets from this tile-part + while (1) { + if (tilePartToEOC) { + //~ peek for an EOC marker + } else if (tilePartLen == 0) { + break; + } + + tileComp = &tile->tileComps[tile->comp]; + resLevel = &tileComp->resLevels[tile->res]; + precinct = &resLevel->precincts[tile->precinct]; + + //----- packet header + + // zero-length flag + if (!readBits(1, &bits)) { + goto err; + } + if (!bits) { + // packet is empty -- clear all code-block inclusion flags + for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + cb->included = gFalse; + } + } + } + } else { + + for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + + // skip code-blocks with no coefficients + if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) { + cb->included = gFalse; + continue; + } + + // code-block inclusion + if (cb->seen) { + if (!readBits(1, &cb->included)) { + goto err; + } + } else { + ttVal = 0; + i = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + j = i + (cbY >> level) * nx + (cbX >> level); + if (!subband->inclusion[j].finished && + !subband->inclusion[j].val) { + subband->inclusion[j].val = ttVal; + } else { + ttVal = subband->inclusion[j].val; + } + while (!subband->inclusion[j].finished && + ttVal <= tile->layer) { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 1) { + subband->inclusion[j].finished = gTrue; + } else { + ++ttVal; + } + } + subband->inclusion[j].val = ttVal; + if (ttVal > tile->layer) { + break; + } + i += nx * ny; + } + cb->included = level < 0; + } + + if (cb->included) { + + // zero bit-plane count + if (!cb->seen) { + ttVal = 0; + i = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + j = i + (cbY >> level) * nx + (cbX >> level); + if (!subband->zeroBitPlane[j].finished && + !subband->zeroBitPlane[j].val) { + subband->zeroBitPlane[j].val = ttVal; + } else { + ttVal = subband->zeroBitPlane[j].val; + } + while (!subband->zeroBitPlane[j].finished) { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 1) { + subband->zeroBitPlane[j].finished = gTrue; + } else { + ++ttVal; + } + } + subband->zeroBitPlane[j].val = ttVal; + i += nx * ny; + } + cb->nZeroBitPlanes = ttVal; + } + + // number of coding passes + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 0) { + cb->nCodingPasses = 1; + } else { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 0) { + cb->nCodingPasses = 2; + } else { + if (!readBits(2, &bits)) { + goto err; + } + if (bits < 3) { + cb->nCodingPasses = 3 + bits; + } else { + if (!readBits(5, &bits)) { + goto err; + } + if (bits < 31) { + cb->nCodingPasses = 6 + bits; + } else { + if (!readBits(7, &bits)) { + goto err; + } + cb->nCodingPasses = 37 + bits; + } + } + } + } + + // update Lblock + while (1) { + if (!readBits(1, &bits)) { + goto err; + } + if (!bits) { + break; + } + ++cb->lBlock; + } + + // length of compressed data + //~ deal with multiple codeword segments + for (n = cb->lBlock, i = cb->nCodingPasses >> 1; + i; + ++n, i >>= 1) ; + if (!readBits(n, &cb->dataLen)) { + goto err; + } + } + } + } + } + } + tilePartLen -= byteCount; + clearBitBuf(); + + //----- packet data + + for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + if (cb->included) { + if (!readCodeBlockData(tileComp, resLevel, precinct, subband, + tile->res, sb, cb)) { + return gFalse; + } + tilePartLen -= cb->dataLen; + cb->seen = gTrue; + } + } + } + } + + //----- next packet + + switch (tile->progOrder) { + case 0: // layer, resolution level, component, precinct + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + } + } + } + break; + case 1: // resolution level, layer, component, precinct + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + } + } + } + break; + case 2: // resolution level, precinct, component, layer + //~ this isn't correct -- see B.12.1.3 + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + } + } + } + break; + case 3: // precinct, component, resolution level, layer + //~ this isn't correct -- see B.12.1.4 + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + } + } + } + break; + case 4: // component, precinct, resolution level, layer + //~ this isn't correct -- see B.12.1.5 + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + } + } + } + break; + } + } + + return gTrue; + + err: + error(getPos(), "Error in JPX stream"); + return gFalse; +} + +GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, + JPXResLevel *resLevel, + JPXPrecinct *precinct, + JPXSubband *subband, + Guint res, Guint sb, + JPXCodeBlock *cb) { + JPXCoeff *coeff0, *coeff1, *coeff; + JArithmeticDecoder *arithDecoder; + Guint horiz, vert, diag, all, cx, xorBit; + int horizSign, vertSign; + Guint i, x, y0, y1, y2; + + arithDecoder = new JArithmeticDecoder(); + arithDecoder->setStream(str, cb->dataLen); + arithDecoder->start(); + + for (i = 0; i < cb->nCodingPasses; ++i) { + switch (cb->nextPass) { + + //----- significance propagation pass + case jpxPassSigProp: + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + for (y1 = 0, coeff = coeff1; + y1 < 4 && y0+y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if (!(coeff->flags & jpxCoeffSignificant)) { + horiz = vert = diag = 0; + horizSign = vertSign = 2; + if (x > cb->x0) { + if (coeff[-1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + if (coeff[1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + if (y0+y1 < cb->y1 - 1) { + if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; + if (cx != 0) { + if (arithDecoder->decodeBit(cx, cb->stats)) { + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + cx = signContext[horizSign][vertSign][0]; + xorBit = signContext[horizSign][vertSign][1]; + if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + } + ++coeff->len; + coeff->flags |= jpxCoeffTouched; + } + } + } + } + } + ++cb->nextPass; + break; + + //----- magnitude refinement pass + case jpxPassMagRef: + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + for (y1 = 0, coeff = coeff1; + y1 < 4 && y0+y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if ((coeff->flags & jpxCoeffSignificant) && + !(coeff->flags & jpxCoeffTouched)) { + if (coeff->flags & jpxCoeffFirstMagRef) { + all = 0; + if (x > cb->x0) { + all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1; + if (y0+y1 > cb->y0) { + all += (coeff[-tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + all += (coeff[1].flags >> jpxCoeffSignificantB) & 1; + if (y0+y1 > cb->y0) { + all += (coeff[-tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + all += (coeff[-tileComp->cbW].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW].flags + >> jpxCoeffSignificantB) & 1; + } + cx = all ? 15 : 14; + } else { + cx = 16; + } + coeff->mag = (coeff->mag << 1) | + arithDecoder->decodeBit(cx, cb->stats); + ++coeff->len; + coeff->flags |= jpxCoeffTouched; + coeff->flags &= ~jpxCoeffFirstMagRef; + } + } + } + } + ++cb->nextPass; + break; + + //----- cleanup pass + case jpxPassCleanup: + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + y1 = 0; + if (y0 + 3 < cb->y1 && + !(coeff1->flags & jpxCoeffTouched) && + !(coeff1[tileComp->cbW].flags & jpxCoeffTouched) && + !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) && + !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) && + (x == cb->x0 || y0 == cb->y0 || + !(coeff1[-tileComp->cbW - 1].flags + & jpxCoeffSignificant)) && + (y0 == cb->y0 || + !(coeff1[-tileComp->cbW].flags & jpxCoeffSignificant)) && + (x == cb->x1 - 1 || y0 == cb->y0 || + !(coeff1[-tileComp->cbW + 1].flags & jpxCoeffSignificant)) && + (x == cb->x0 || + (!(coeff1[-1].flags & jpxCoeffSignificant) && + !(coeff1[tileComp->cbW - 1].flags + & jpxCoeffSignificant) && + !(coeff1[2 * tileComp->cbW - 1].flags + & jpxCoeffSignificant) && + !(coeff1[3 * tileComp->cbW - 1].flags + & jpxCoeffSignificant))) && + (x == cb->x1 - 1 || + (!(coeff1[1].flags & jpxCoeffSignificant) && + !(coeff1[tileComp->cbW + 1].flags + & jpxCoeffSignificant) && + !(coeff1[2 * tileComp->cbW + 1].flags + & jpxCoeffSignificant) && + !(coeff1[3 * tileComp->cbW + 1].flags + & jpxCoeffSignificant))) && + (x == cb->x0 || y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW - 1].flags & jpxCoeffSignificant)) && + (y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW].flags & jpxCoeffSignificant)) && + (x == cb->x1 - 1 || y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW + 1].flags + & jpxCoeffSignificant))) { + if (arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) { + y1 = arithDecoder->decodeBit(jpxContextUniform, cb->stats); + y1 = (y1 << 1) | + arithDecoder->decodeBit(jpxContextUniform, cb->stats); + for (y2 = 0, coeff = coeff1; + y2 < y1; + ++y2, coeff += tileComp->cbW) { + ++coeff->len; + } + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + ++coeff->len; + cx = signContext[2][2][0]; + xorBit = signContext[2][2][1]; + if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + ++y1; + } else { + for (y1 = 0, coeff = coeff1; + y1 < 4; + ++y1, coeff += tileComp->cbW) { + ++coeff->len; + } + y1 = 4; + } + } + for (coeff = &coeff1[y1 << tileComp->codeBlockW]; + y1 < 4 && y0 + y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if (!(coeff->flags & jpxCoeffTouched)) { + horiz = vert = diag = 0; + horizSign = vertSign = 2; + if (x > cb->x0) { + if (coeff[-1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + if (coeff[1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + if (y0+y1 < cb->y1 - 1) { + if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; + if (arithDecoder->decodeBit(cx, cb->stats)) { + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + cx = signContext[horizSign][vertSign][0]; + xorBit = signContext[horizSign][vertSign][1]; + if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + } + ++coeff->len; + } else { + coeff->flags &= ~jpxCoeffTouched; + } + } + } + } + cb->nextPass = jpxPassSigProp; + break; + } + } + + delete arithDecoder; + return gTrue; +} + +// Inverse quantization, and wavelet transform (IDWT). This also does +// the initial shift to convert to fixed point format. +void JPXStream::inverseTransform(JPXTileComp *tileComp) { + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + JPXCoeff *coeff0, *coeff; + Guint qStyle, guard, eps, shift, shift2; + double mu; + int val; + int *dataPtr; + Guint nx0, ny0, nx1, ny1; + Guint r, cbX, cbY, x, y; + + //----- (NL)LL subband (resolution level 0) + + resLevel = &tileComp->resLevels[0]; + precinct = &resLevel->precincts[0]; + subband = &precinct->subbands[0]; + + // i-quant parameters + qStyle = tileComp->quantStyle & 0x1f; + guard = (tileComp->quantStyle >> 5) & 7; + if (qStyle == 0) { + eps = (tileComp->quantSteps[0] >> 3) & 0x1f; + shift = guard + eps - 1; + mu = 0; // make gcc happy + } else { + shift = guard - 1 + tileComp->prec; + mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0; + } + if (tileComp->transform == 0) { + shift += fracBits; + } + + // copy (NL)LL into the upper-left corner of the data array, doing + // the fixed point adjustment and dequantization along the way + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + for (y = cb->y0, coeff0 = cb->coeffs; + y < cb->y1; + ++y, coeff0 += tileComp->cbW) { + dataPtr = &tileComp->data[(y - subband->y0) + * (tileComp->x1 - tileComp->x0) + + (cb->x0 - subband->x0)]; + for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) { + val = (int)coeff->mag; + if (val != 0) { + shift2 = shift - (cb->nZeroBitPlanes + coeff->len); + if (shift2 > 0) { + val = (val << shift2) + (1 << (shift2 - 1)); + } else { + val >>= -shift2; + } + if (qStyle == 0) { + if (tileComp->transform == 0) { + val &= -1 << fracBits; + } + } else { + val = (int)((double)val * mu); + } + if (coeff->flags & jpxCoeffSign) { + val = -val; + } + } + *dataPtr++ = val; + } + } + ++cb; + } + } + + //----- IDWT for each level + + for (r = 1; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + + // (n)LL is already in the upper-left corner of the + // tile-component data array -- interleave with (n)HL/LH/HH + // and inverse transform to get (n-1)LL, which will be stored + // in the upper-left corner of the tile-component data array + if (r == tileComp->nDecompLevels) { + nx0 = tileComp->x0; + ny0 = tileComp->y0; + nx1 = tileComp->x1; + ny1 = tileComp->y1; + } else { + nx0 = tileComp->resLevels[r+1].x0; + ny0 = tileComp->resLevels[r+1].y0; + nx1 = tileComp->resLevels[r+1].x1; + ny1 = tileComp->resLevels[r+1].y1; + } + inverseTransformLevel(tileComp, r, resLevel, nx0, ny0, nx1, ny1); + } +} + +// Do one level of the inverse transform: +// - take (n)LL from the tile-component data array +// - take (n)HL/LH/HH from +// - leave the resulting (n-1)LL in the tile-component data array +void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, + Guint r, JPXResLevel *resLevel, + Guint nx0, Guint ny0, + Guint nx1, Guint ny1) { + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + JPXCoeff *coeff0, *coeff; + Guint qStyle, guard, eps, shift, shift2, t; + double mu; + int val; + int *dataPtr; + Guint xo, yo; + Guint x, y, sb, cbX, cbY; + int xx, yy; + + //----- interleave + + // spread out LL + for (yy = resLevel->y1 - 1; yy >= (int)resLevel->y0; --yy) { + for (xx = resLevel->x1 - 1; xx >= (int)resLevel->x0; --xx) { + tileComp->data[(2 * yy - ny0) * (tileComp->x1 - tileComp->x0) + + (2 * xx - nx0)] = + tileComp->data[(yy - resLevel->y0) * (tileComp->x1 - tileComp->x0) + + (xx - resLevel->x0)]; + } + } + + // i-quant parameters + qStyle = tileComp->quantStyle & 0x1f; + guard = (tileComp->quantStyle >> 5) & 7; + + // interleave HL/LH/HH + precinct = &resLevel->precincts[0]; + for (sb = 0; sb < 3; ++sb) { + + // i-quant parameters + if (qStyle == 0) { + eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f; + shift = guard + eps - 1; + mu = 0; // make gcc happy + } else { + shift = guard + tileComp->prec; + if (sb == 2) { + ++shift; + } + t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)]; + mu = (double)(0x800 + (t & 0x7ff)) / 2048.0; + } + if (tileComp->transform == 0) { + shift += fracBits; + } + + // copy the subband coefficients into the data array, doing the + // fixed point adjustment and dequantization along the way + xo = (sb & 1) ? 0 : 1; + yo = (sb > 0) ? 1 : 0; + subband = &precinct->subbands[sb]; + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + for (y = cb->y0, coeff0 = cb->coeffs; + y < cb->y1; + ++y, coeff0 += tileComp->cbW) { + dataPtr = &tileComp->data[(2 * y + yo - ny0) + * (tileComp->x1 - tileComp->x0) + + (2 * cb->x0 + xo - nx0)]; + for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) { + val = (int)coeff->mag; + if (val != 0) { + shift2 = shift - (cb->nZeroBitPlanes + coeff->len); + if (shift2 > 0) { + val = (val << shift2) + (1 << (shift2 - 1)); + } else { + val >>= -shift2; + } + if (qStyle == 0) { + if (tileComp->transform == 0) { + val &= -1 << fracBits; + } + } else { + val = (int)((double)val * mu); + } + if (coeff->flags & jpxCoeffSign) { + val = -val; + } + } + *dataPtr = val; + dataPtr += 2; + } + } + ++cb; + } + } + } + + //----- horizontal (row) transforms + dataPtr = tileComp->data; + for (y = 0; y < ny1 - ny0; ++y) { + inverseTransform1D(tileComp, dataPtr, 1, nx0, nx1); + dataPtr += tileComp->x1 - tileComp->x0; + } + + //----- vertical (column) transforms + dataPtr = tileComp->data; + for (x = 0; x < nx1 - nx0; ++x) { + inverseTransform1D(tileComp, dataPtr, + tileComp->x1 - tileComp->x0, ny0, ny1); + ++dataPtr; + } +} + +void JPXStream::inverseTransform1D(JPXTileComp *tileComp, + int *data, Guint stride, + Guint i0, Guint i1) { + int *buf; + Guint offset, end, i; + + //----- special case for length = 1 + if (i1 - i0 == 1) { + if (i0 & 1) { + *data >>= 1; + } + + } else { + + // choose an offset: this makes even buf[] indexes correspond to + // odd values of i, and vice versa + offset = 3 + (i0 & 1); + end = offset + i1 - i0; + + //----- gather + buf = tileComp->buf; + for (i = 0; i < i1 - i0; ++i) { + buf[offset + i] = data[i * stride]; + } + + //----- extend right + buf[end] = buf[end - 2]; + if (i1 - i0 == 2) { + buf[end+1] = buf[offset + 1]; + buf[end+2] = buf[offset]; + buf[end+3] = buf[offset + 1]; + } else { + buf[end+1] = buf[end - 3]; + if (i1 - i0 == 3) { + buf[end+2] = buf[offset + 1]; + buf[end+3] = buf[offset + 2]; + } else { + buf[end+2] = buf[end - 4]; + if (i1 - i0 == 4) { + buf[end+3] = buf[offset + 1]; + } else { + buf[end+3] = buf[end - 5]; + } + } + } + + //----- extend left + buf[offset - 1] = buf[offset + 1]; + buf[offset - 2] = buf[offset + 2]; + buf[offset - 3] = buf[offset + 3]; + if (offset == 4) { + buf[0] = buf[offset + 4]; + } + + //----- 9-7 irreversible filter + + if (tileComp->transform == 0) { + // step 1 (even) + for (i = 1; i <= end + 2; i += 2) { + buf[i] = (int)(idwtKappa * buf[i]); + } + // step 2 (odd) + for (i = 0; i <= end + 3; i += 2) { + buf[i] = (int)(idwtIKappa * buf[i]); + } + // step 3 (even) + for (i = 1; i <= end + 2; i += 2) { + buf[i] = (int)(buf[i] - idwtDelta * (buf[i-1] + buf[i+1])); + } + // step 4 (odd) + for (i = 2; i <= end + 1; i += 2) { + buf[i] = (int)(buf[i] - idwtGamma * (buf[i-1] + buf[i+1])); + } + // step 5 (even) + for (i = 3; i <= end; i += 2) { + buf[i] = (int)(buf[i] - idwtBeta * (buf[i-1] + buf[i+1])); + } + // step 6 (odd) + for (i = 4; i <= end - 1; i += 2) { + buf[i] = (int)(buf[i] - idwtAlpha * (buf[i-1] + buf[i+1])); + } + + //----- 5-3 reversible filter + + } else { + // step 1 (even) + for (i = 3; i <= end; i += 2) { + buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2; + } + // step 2 (odd) + for (i = 4; i < end; i += 2) { + buf[i] += (buf[i-1] + buf[i+1]) >> 1; + } + } + + //----- scatter + for (i = 0; i < i1 - i0; ++i) { + data[i * stride] = buf[offset + i]; + } + } +} + +// Inverse multi-component transform and DC level shift. This also +// converts fixed point samples back to integers. +GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { + JPXTileComp *tileComp; + int coeff, d0, d1, d2, minVal, maxVal, zeroVal; + int *dataPtr; + Guint j, comp, x, y; + + //----- inverse multi-component transform + + if (tile->multiComp == 1) { + if (img.nComps < 3 || + tile->tileComps[0].hSep != tile->tileComps[1].hSep || + tile->tileComps[0].vSep != tile->tileComps[1].vSep || + tile->tileComps[1].hSep != tile->tileComps[2].hSep || + tile->tileComps[1].vSep != tile->tileComps[2].vSep) { + return gFalse; + } + + // inverse irreversible multiple component transform + if (tile->tileComps[0].transform == 0) { + j = 0; + for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { + for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { + d0 = tile->tileComps[0].data[j]; + d1 = tile->tileComps[1].data[j]; + d2 = tile->tileComps[2].data[j]; + tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5); + tile->tileComps[1].data[j] = + (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5); + tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5); + ++j; + } + } + + // inverse reversible multiple component transform + } else { + j = 0; + for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { + for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { + d0 = tile->tileComps[0].data[j]; + d1 = tile->tileComps[1].data[j]; + d2 = tile->tileComps[2].data[j]; + tile->tileComps[0].data[j] = d0 - ((d2 + d1) >> 2); + tile->tileComps[1].data[j] = d2 - d1; + tile->tileComps[2].data[j] = d0 - d1; + ++j; + } + } + } + } + + //----- DC level shift + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + + // signed: clip + if (tileComp->sgned) { + minVal = -(1 << (tileComp->prec - 1)); + maxVal = (1 << (tileComp->prec - 1)) - 1; + dataPtr = tileComp->data; + for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { + for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { + coeff = *dataPtr; + if (tileComp->transform == 0) { + coeff >>= fracBits; + } + if (coeff < minVal) { + coeff = minVal; + } else if (coeff > maxVal) { + coeff = maxVal; + } + *dataPtr++ = coeff; + } + } + + // unsigned: inverse DC level shift and clip + } else { + maxVal = (1 << tileComp->prec) - 1; + zeroVal = 1 << (tileComp->prec - 1); + dataPtr = tileComp->data; + for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { + for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { + coeff = *dataPtr; + if (tileComp->transform == 0) { + coeff >>= fracBits; + } + coeff += zeroVal; + if (coeff < 0) { + coeff = 0; + } else if (coeff > maxVal) { + coeff = maxVal; + } + *dataPtr++ = coeff; + } + } + } + } + + return gTrue; +} + +GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) { + Guint len, lenH; + + if (!readULong(&len) || + !readULong(boxType)) { + return gFalse; + } + if (len == 1) { + if (!readULong(&lenH) || !readULong(&len)) { + return gFalse; + } + if (lenH) { + error(getPos(), "JPX stream contains a box larger than 2^32 bytes"); + return gFalse; + } + *boxLen = len; + *dataLen = len - 16; + } else if (len == 0) { + *boxLen = 0; + *dataLen = 0; + } else { + *boxLen = len; + *dataLen = len - 8; + } + return gTrue; +} + +int JPXStream::readMarkerHdr(int *segType, Guint *segLen) { + int c; + + do { + do { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + } while (c != 0xff); + do { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + } while (c == 0xff); + } while (c == 0x00); + *segType = c; + if ((c >= 0x30 && c <= 0x3f) || + c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) { + *segLen = 0; + return gTrue; + } + return readUWord(segLen); +} + +GBool JPXStream::readUByte(Guint *x) { + int c0; + + if ((c0 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)c0; + return gTrue; +} + +GBool JPXStream::readByte(int *x) { + int c0; + + if ((c0 = str->getChar()) == EOF) { + return gFalse; + } + *x = c0; + if (c0 & 0x80) { + *x |= -1 - 0xff; + } + return gTrue; +} + +GBool JPXStream::readUWord(Guint *x) { + int c0, c1; + + if ((c0 = str->getChar()) == EOF || + (c1 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 8) | c1); + return gTrue; +} + +GBool JPXStream::readULong(Guint *x) { + int c0, c1, c2, c3; + + if ((c0 = str->getChar()) == EOF || + (c1 = str->getChar()) == EOF || + (c2 = str->getChar()) == EOF || + (c3 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + return gTrue; +} + +GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) { + int y, c, i; + + y = 0; + for (i = 0; i < nBytes; ++i) { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + y = (y << 8) + c; + } + if (signd) { + if (y & (1 << (8 * nBytes - 1))) { + y |= -1 << (8 * nBytes); + } + } + *x = y; + return gTrue; +} + +GBool JPXStream::readBits(int nBits, Guint *x) { + int c; + + while (bitBufLen < nBits) { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + ++byteCount; + if (bitBufSkip) { + bitBuf = (bitBuf << 7) | (c & 0x7f); + bitBufLen += 7; + } else { + bitBuf = (bitBuf << 8) | (c & 0xff); + bitBufLen += 8; + } + bitBufSkip = c == 0xff; + } + *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1); + bitBufLen -= nBits; + return gTrue; +} + +void JPXStream::clearBitBuf() { + bitBufLen = 0; + bitBufSkip = gFalse; + byteCount = 0; +} diff --git a/pdf2swf/xpdf/JPXStream.h b/pdf2swf/xpdf/JPXStream.h new file mode 100644 index 0000000..eb84fe6 --- /dev/null +++ b/pdf2swf/xpdf/JPXStream.h @@ -0,0 +1,340 @@ +//======================================================================== +// +// JPXStream.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JPXSTREAM_H +#define JPXSTREAM_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" +#include "Stream.h" + +class JArithmeticDecoderStats; + +//------------------------------------------------------------------------ + +enum JPXColorSpaceType { + jpxCSBiLevel = 0, + jpxCSYCbCr1 = 1, + jpxCSYCbCr2 = 3, + jpxCSYCBCr3 = 4, + jpxCSPhotoYCC = 9, + jpxCSCMY = 11, + jpxCSCMYK = 12, + jpxCSYCCK = 13, + jpxCSCIELab = 14, + jpxCSsRGB = 16, + jpxCSGrayscale = 17, + jpxCSBiLevel2 = 18, + jpxCSCIEJab = 19, + jpxCSCISesRGB = 20, + jpxCSROMMRGB = 21, + jpxCSsRGBYCbCr = 22, + jpxCSYPbPr1125 = 23, + jpxCSYPbPr1250 = 24 +}; + +struct JPXColorSpec { + Guint meth; // method + int prec; // precedence + union { + struct { + JPXColorSpaceType type; // color space type + union { + struct { + Guint rl, ol, ra, oa, rb, ob, il; + } cieLab; + }; + } enumerated; + }; +}; + +//------------------------------------------------------------------------ + +struct JPXPalette { + Guint nEntries; // number of entries in the palette + Guint nComps; // number of components in each entry + Guint *bpc; // bits per component, for each component + int *c; // color data: + // c[i*nComps+j] = entry i, component j +}; + +//------------------------------------------------------------------------ + +struct JPXCompMap { + Guint nChannels; // number of channels + Guint *comp; // codestream components mapped to each channel + Guint *type; // 0 for direct use, 1 for palette mapping + Guint *pComp; // palette components to use +}; + +//------------------------------------------------------------------------ + +struct JPXChannelDefn { + Guint nChannels; // number of channels + Guint *idx; // channel indexes + Guint *type; // channel types + Guint *assoc; // channel associations +}; + +//------------------------------------------------------------------------ + +struct JPXTagTreeNode { + GBool finished; // true if this node is finished + Guint val; // current value +}; + +//------------------------------------------------------------------------ + +struct JPXCoeff { + Gushort flags; // flag bits + Gushort len; // number of significant bits in mag + Guint mag; // magnitude value +}; + +// coefficient flags +#define jpxCoeffSignificantB 0 +#define jpxCoeffTouchedB 1 +#define jpxCoeffFirstMagRefB 2 +#define jpxCoeffSignB 7 +#define jpxCoeffSignificant (1 << jpxCoeffSignificantB) +#define jpxCoeffTouched (1 << jpxCoeffTouchedB) +#define jpxCoeffFirstMagRef (1 << jpxCoeffFirstMagRefB) +#define jpxCoeffSign (1 << jpxCoeffSignB) + +//------------------------------------------------------------------------ + +struct JPXCodeBlock { + //----- size + Guint x0, y0, x1, y1; // bounds + + //----- persistent state + GBool seen; // true if this code-block has already + // been seen + Guint lBlock; // base number of bits used for pkt data length + Guint nextPass; // next coding pass + + //---- info from first packet + Guint nZeroBitPlanes; // number of zero bit planes + + //----- info for the current packet + Guint included; // code-block inclusion in this packet: + // 0=not included, 1=included + Guint nCodingPasses; // number of coding passes in this pkt + Guint dataLen; // pkt data length + + //----- coefficient data + JPXCoeff *coeffs; // the coefficients + JArithmeticDecoderStats // arithmetic decoder stats + *stats; +}; + +//------------------------------------------------------------------------ + +struct JPXSubband { + //----- computed + Guint x0, y0, x1, y1; // bounds + Guint nXCBs, nYCBs; // number of code-blocks in the x and y + // directions + + //----- tag trees + Guint maxTTLevel; // max tag tree level + JPXTagTreeNode *inclusion; // inclusion tag tree for each subband + JPXTagTreeNode *zeroBitPlane; // zero-bit plane tag tree for each + // subband + + //----- children + JPXCodeBlock *cbs; // the code-blocks (len = nXCBs * nYCBs) +}; + +//------------------------------------------------------------------------ + +struct JPXPrecinct { + //----- computed + Guint x0, y0, x1, y1; // bounds of the precinct + + //----- children + JPXSubband *subbands; // the subbands +}; + +//------------------------------------------------------------------------ + +struct JPXResLevel { + //----- from the COD and COC segments (main and tile) + Guint precinctWidth; // log2(precinct width) + Guint precinctHeight; // log2(precinct height) + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile-comp (for this res level) + Guint bx0[3], by0[3], // subband bounds + bx1[3], by1[3]; + + //---- children + JPXPrecinct *precincts; // the precincts +}; + +//------------------------------------------------------------------------ + +struct JPXTileComp { + //----- from the SIZ segment + GBool sgned; // 1 for signed, 0 for unsigned + Guint prec; // precision, in bits + Guint hSep; // horizontal separation of samples + Guint vSep; // vertical separation of samples + + //----- from the COD and COC segments (main and tile) + Guint style; // coding style parameter (Scod / Scoc) + Guint nDecompLevels; // number of decomposition levels + Guint codeBlockW; // log2(code-block width) + Guint codeBlockH; // log2(code-block height) + Guint codeBlockStyle; // code-block style + Guint transform; // wavelet transformation + + //----- from the QCD and QCC segments (main and tile) + Guint quantStyle; // quantization style + Guint *quantSteps; // quantization step size for each subband + Guint nQuantSteps; // number of entries in quantSteps + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile-comp, in ref coords + Guint cbW; // code-block width + Guint cbH; // code-block height + + //----- image data + int *data; // the decoded image data + int *buf; // intermediate buffer for the inverse + // transform + + //----- children + JPXResLevel *resLevels; // the resolution levels + // (len = nDecompLevels + 1) +}; + +//------------------------------------------------------------------------ + +struct JPXTile { + //----- from the COD segments (main and tile) + Guint progOrder; // progression order + Guint nLayers; // number of layers + Guint multiComp; // multiple component transformation + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile, in ref coords + Guint maxNDecompLevels; // max number of decomposition levels used + // in any component in this tile + + //----- progression order loop counters + Guint comp; // component + Guint res; // resolution level + Guint precinct; // precinct + Guint layer; // layer + + //----- children + JPXTileComp *tileComps; // the tile-components (len = JPXImage.nComps) +}; + +//------------------------------------------------------------------------ + +struct JPXImage { + //----- from the SIZ segment + Guint xSize, ySize; // size of reference grid + Guint xOffset, yOffset; // image offset + Guint xTileSize, yTileSize; // size of tiles + Guint xTileOffset, // offset of first tile + yTileOffset; + Guint nComps; // number of components + + //----- computed + Guint nXTiles; // number of tiles in x direction + Guint nYTiles; // number of tiles in y direction + + //----- children + JPXTile *tiles; // the tiles (len = nXTiles * nYTiles) +}; + +//------------------------------------------------------------------------ + +class JPXStream: public FilterStream { +public: + + JPXStream(Stream *strA); + virtual ~JPXStream(); + virtual StreamKind getKind() { return strJPX; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + void fillReadBuf(); + GBool readBoxes(); + GBool readColorSpecBox(Guint dataLen); + GBool readCodestream(Guint len); + GBool readTilePart(); + GBool readTilePartData(Guint tileIdx, + Guint tilePartLen, GBool tilePartToEOC); + GBool readCodeBlockData(JPXTileComp *tileComp, + JPXResLevel *resLevel, + JPXPrecinct *precinct, + JPXSubband *subband, + Guint res, Guint sb, + JPXCodeBlock *cb); + void inverseTransform(JPXTileComp *tileComp); + void inverseTransformLevel(JPXTileComp *tileComp, + Guint r, JPXResLevel *resLevel, + Guint nx0, Guint ny0, + Guint nx1, Guint ny1); + void inverseTransform1D(JPXTileComp *tileComp, + int *data, Guint stride, + Guint i0, Guint i1); + GBool inverseMultiCompAndDC(JPXTile *tile); + GBool readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen); + int readMarkerHdr(int *segType, Guint *segLen); + GBool readUByte(Guint *x); + GBool readByte(int *x); + GBool readUWord(Guint *x); + GBool readULong(Guint *x); + GBool readNBytes(int nBytes, GBool signd, int *x); + GBool readBits(int nBits, Guint *x); + void clearBitBuf(); + + Guint nComps; // number of components + Guint *bpc; // bits per component, for each component + Guint width, height; // image size + GBool haveImgHdr; // set if a JP2/JPX image header has been + // found + JPXColorSpec cs; // color specification + GBool haveCS; // set if a color spec has been found + JPXPalette palette; // the palette + GBool havePalette; // set if a palette has been found + JPXCompMap compMap; // the component mapping + GBool haveCompMap; // set if a component mapping has been found + JPXChannelDefn channelDefn; // channel definition + GBool haveChannelDefn; // set if a channel defn has been found + + JPXImage img; // JPEG2000 decoder data + Guint bitBuf; // buffer for bit reads + int bitBufLen; // number of bits in bitBuf + GBool bitBufSkip; // true if next bit should be skipped + // (for bit stuffing) + Guint byteCount; // number of bytes read since last call + // to clearBitBuf + + Guint curX, curY, curComp; // current position for lookChar/getChar + Guint readBuf; // read buffer + Guint readBufLen; // number of valid bits in readBuf +}; + +#endif diff --git a/pdf2swf/xpdf/Lexer.cc b/pdf2swf/xpdf/Lexer.cc index d037469..1fa166f 100644 --- a/pdf2swf/xpdf/Lexer.cc +++ b/pdf2swf/xpdf/Lexer.cc @@ -2,15 +2,16 @@ // // Lexer.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include diff --git a/pdf2swf/xpdf/Lexer.h b/pdf2swf/xpdf/Lexer.h index 8a01ab2..398d27c 100644 --- a/pdf2swf/xpdf/Lexer.h +++ b/pdf2swf/xpdf/Lexer.h @@ -2,14 +2,16 @@ // // Lexer.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef LEXER_H #define LEXER_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/Link.cc b/pdf2swf/xpdf/Link.cc index af64c8b..2d146b5 100644 --- a/pdf2swf/xpdf/Link.cc +++ b/pdf2swf/xpdf/Link.cc @@ -2,15 +2,16 @@ // // Link.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include "gmem.h" @@ -22,8 +23,117 @@ #include "Link.h" //------------------------------------------------------------------------ +// LinkAction +//------------------------------------------------------------------------ + +LinkAction *LinkAction::parseDest(Object *obj) { + LinkAction *action; + + action = new LinkGoTo(obj); + if (!action->isOk()) { + delete action; + return NULL; + } + return action; +} + +LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) { + LinkAction *action; + Object obj2, obj3, obj4; + + if (!obj->isDict()) { + error(-1, "Bad annotation action"); + return NULL; + } + + obj->dictLookup("S", &obj2); + + // GoTo action + if (obj2.isName("GoTo")) { + obj->dictLookup("D", &obj3); + action = new LinkGoTo(&obj3); + obj3.free(); + + // GoToR action + } else if (obj2.isName("GoToR")) { + obj->dictLookup("F", &obj3); + obj->dictLookup("D", &obj4); + action = new LinkGoToR(&obj3, &obj4); + obj3.free(); + obj4.free(); + + // Launch action + } else if (obj2.isName("Launch")) { + action = new LinkLaunch(obj); + + // URI action + } else if (obj2.isName("URI")) { + obj->dictLookup("URI", &obj3); + action = new LinkURI(&obj3, baseURI); + obj3.free(); + + // Named action + } else if (obj2.isName("Named")) { + obj->dictLookup("N", &obj3); + action = new LinkNamed(&obj3); + obj3.free(); + + // Movie action + } else if (obj2.isName("Movie")) { + obj->dictLookupNF("Annot", &obj3); + obj->dictLookup("T", &obj4); + action = new LinkMovie(&obj3, &obj4); + obj3.free(); + obj4.free(); + + // unknown action + } else if (obj2.isName()) { + action = new LinkUnknown(obj2.getName()); + + // action is missing or wrong type + } else { + error(-1, "Bad annotation action"); + action = NULL; + } + + obj2.free(); + + if (action && !action->isOk()) { + delete action; + return NULL; + } + return action; +} + +GString *LinkAction::getFileSpecName(Object *fileSpecObj) { + GString *name; + Object obj1; + + name = NULL; + + // string + if (fileSpecObj->isString()) { + name = fileSpecObj->getString()->copy(); + + // dictionary + } else if (fileSpecObj->isDict()) { + if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { + obj1.free(); + fileSpecObj->dictLookup("F", &obj1); + } + if (obj1.isString()) + name = obj1.getString()->copy(); + else + error(-1, "Illegal file spec in link"); + obj1.free(); + + // error + } else { + error(-1, "Illegal file spec in link"); + } -static GString *getFileSpecName(Object *fileSpecObj); + return name; +} //------------------------------------------------------------------------ // LinkDest @@ -37,6 +147,10 @@ LinkDest::LinkDest(Array *a) { ok = gFalse; // get page + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + return; + } a->getNF(0, &obj1); if (obj1.isInt()) { pageNum = obj1.getInt() + 1; @@ -57,46 +171,66 @@ LinkDest::LinkDest(Array *a) { // XYZ link if (obj1.isName("XYZ")) { kind = destXYZ; - a->get(2, &obj2); - if (obj2.isNull()) { + if (a->getLength() < 3) { changeLeft = gFalse; - } else if (obj2.isNum()) { - changeLeft = gTrue; - left = obj2.getNum(); } else { - error(-1, "Bad annotation destination position"); - goto err1; + a->get(2, &obj2); + if (obj2.isNull()) { + changeLeft = gFalse; + } else if (obj2.isNum()) { + changeLeft = gTrue; + left = obj2.getNum(); + } else { + error(-1, "Bad annotation destination position"); + goto err1; + } + obj2.free(); } - obj2.free(); - a->get(3, &obj2); - if (obj2.isNull()) { + if (a->getLength() < 4) { changeTop = gFalse; - } else if (obj2.isNum()) { - changeTop = gTrue; - top = obj2.getNum(); } else { - error(-1, "Bad annotation destination position"); - goto err1; + a->get(3, &obj2); + if (obj2.isNull()) { + changeTop = gFalse; + } else if (obj2.isNum()) { + changeTop = gTrue; + top = obj2.getNum(); + } else { + error(-1, "Bad annotation destination position"); + goto err1; + } + obj2.free(); } - obj2.free(); - a->get(4, &obj2); - if (obj2.isNull()) { + if (a->getLength() < 5) { changeZoom = gFalse; - } else if (obj2.isNum()) { - changeZoom = gTrue; - zoom = obj2.getNum(); } else { - error(-1, "Bad annotation destination position"); - goto err1; + a->get(4, &obj2); + if (obj2.isNull()) { + changeZoom = gFalse; + } else if (obj2.isNum()) { + changeZoom = gTrue; + zoom = obj2.getNum(); + } else { + error(-1, "Bad annotation destination position"); + goto err1; + } + obj2.free(); } - obj2.free(); // Fit link } else if (obj1.isName("Fit")) { + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + goto err2; + } kind = destFit; // FitH link } else if (obj1.isName("FitH")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } kind = destFitH; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -107,6 +241,10 @@ LinkDest::LinkDest(Array *a) { // FitV link } else if (obj1.isName("FitV")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } kind = destFitV; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -117,6 +255,10 @@ LinkDest::LinkDest(Array *a) { // FitR link } else if (obj1.isName("FitR")) { + if (a->getLength() < 6) { + error(-1, "Annotation destination array is too short"); + goto err2; + } kind = destFitR; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -145,10 +287,18 @@ LinkDest::LinkDest(Array *a) { // FitB link } else if (obj1.isName("FitB")) { + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + goto err2; + } kind = destFitB; // FitBH link } else if (obj1.isName("FitBH")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } kind = destFitBH; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -159,6 +309,10 @@ LinkDest::LinkDest(Array *a) { // FitBV link } else if (obj1.isName("FitBV")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } kind = destFitBV; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -292,18 +446,33 @@ LinkLaunch::LinkLaunch(Object *actionObj) { fileName = getFileSpecName(&obj1); } else { obj1.free(); +#ifdef WIN32 + if (actionObj->dictLookup("Win", &obj1)->isDict()) { + obj1.dictLookup("F", &obj2); + fileName = getFileSpecName(&obj2); + obj2.free(); + if (obj1.dictLookup("P", &obj2)->isString()) { + params = obj2.getString()->copy(); + } + obj2.free(); + } else { + error(-1, "Bad launch-type link action"); + } +#else //~ This hasn't been defined by Adobe yet, so assume it looks //~ just like the Win dictionary until they say otherwise. if (actionObj->dictLookup("Unix", &obj1)->isDict()) { obj1.dictLookup("F", &obj2); fileName = getFileSpecName(&obj2); obj2.free(); - if (obj1.dictLookup("P", &obj2)->isString()) + if (obj1.dictLookup("P", &obj2)->isString()) { params = obj2.getString()->copy(); + } obj2.free(); } else { error(-1, "Bad launch-type link action"); } +#endif } obj1.free(); } @@ -378,6 +547,28 @@ LinkNamed::~LinkNamed() { } //------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) { + annotRef.num = -1; + title = NULL; + if (annotObj->isRef()) { + annotRef = annotObj->getRef(); + } else if (titleObj->isString()) { + title = titleObj->getString()->copy(); + } else { + error(-1, "Movie action is missing both the Annot and T keys"); + } +} + +LinkMovie::~LinkMovie() { + if (title) { + delete title; + } +} + +//------------------------------------------------------------------------ // LinkUnknown //------------------------------------------------------------------------ @@ -390,13 +581,42 @@ LinkUnknown::~LinkUnknown() { } //------------------------------------------------------------------------ +// LinkBorderStyle +//------------------------------------------------------------------------ + +LinkBorderStyle::LinkBorderStyle(LinkBorderType typeA, double widthA, + double *dashA, int dashLengthA, + double rA, double gA, double bA) { + type = typeA; + width = widthA; + dash = dashA; + dashLength = dashLengthA; + r = rA; + g = gA; + b = bA; +} + +LinkBorderStyle::~LinkBorderStyle() { + if (dash) { + gfree(dash); + } +} + +//------------------------------------------------------------------------ // Link //------------------------------------------------------------------------ Link::Link(Dict *dict, GString *baseURI) { - Object obj1, obj2, obj3, obj4; + Object obj1, obj2, obj3; + LinkBorderType borderType; + double borderWidth; + double *borderDash; + int borderDashLength; + double borderR, borderG, borderB; double t; + int i; + borderStyle = NULL; action = NULL; ok = gFalse; @@ -441,82 +661,110 @@ Link::Link(Dict *dict, GString *baseURI) { y2 = t; } - // get border - borderW = 1; - if (!dict->lookup("Border", &obj1)->isNull()) { - if (obj1.isArray() && obj1.arrayGetLength() >= 3) { - if (obj1.arrayGet(2, &obj2)->isNum()) { - borderW = obj2.getNum(); - } else { - error(-1, "Bad annotation border"); + // get the border style info + borderType = linkBorderSolid; + borderWidth = 1; + borderDash = NULL; + borderDashLength = 0; + borderR = 0; + borderG = 0; + borderB = 1; + if (dict->lookup("BS", &obj1)->isDict()) { + if (obj1.dictLookup("S", &obj2)->isName()) { + if (obj2.isName("S")) { + borderType = linkBorderSolid; + } else if (obj2.isName("D")) { + borderType = linkBorderDashed; + } else if (obj2.isName("B")) { + borderType = linkBorderEmbossed; + } else if (obj2.isName("I")) { + borderType = linkBorderEngraved; + } else if (obj2.isName("U")) { + borderType = linkBorderUnderlined; + } + } + obj2.free(); + if (obj1.dictLookup("W", &obj2)->isNum()) { + borderWidth = obj2.getNum(); + } + obj2.free(); + if (obj1.dictLookup("D", &obj2)->isArray()) { + borderDashLength = obj2.arrayGetLength(); + borderDash = (double *)gmalloc(borderDashLength * sizeof(double)); + for (i = 0; i < borderDashLength; ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + borderDash[i] = obj3.getNum(); + } else { + borderDash[i] = 1; + } + obj3.free(); + } + } + obj2.free(); + } else { + obj1.free(); + if (dict->lookup("Border", &obj1)->isArray()) { + if (obj1.arrayGetLength() >= 3) { + if (obj1.arrayGet(2, &obj2)->isNum()) { + borderWidth = obj2.getNum(); + } + obj2.free(); + if (obj1.arrayGetLength() >= 4) { + if (obj1.arrayGet(3, &obj2)->isArray()) { + borderType = linkBorderDashed; + borderDashLength = obj2.arrayGetLength(); + borderDash = (double *)gmalloc(borderDashLength * sizeof(double)); + for (i = 0; i < borderDashLength; ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + borderDash[i] = obj3.getNum(); + } else { + borderDash[i] = 1; + } + obj3.free(); + } + } + obj2.free(); + } } - obj2.free(); } } obj1.free(); + if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) { + if (obj1.arrayGet(0, &obj2)->isNum()) { + borderR = obj2.getNum(); + } + obj1.free(); + if (obj1.arrayGet(1, &obj2)->isNum()) { + borderG = obj2.getNum(); + } + obj1.free(); + if (obj1.arrayGet(2, &obj2)->isNum()) { + borderB = obj2.getNum(); + } + obj1.free(); + } + obj1.free(); + borderStyle = new LinkBorderStyle(borderType, borderWidth, + borderDash, borderDashLength, + borderR, borderG, borderB); // look for destination if (!dict->lookup("Dest", &obj1)->isNull()) { - action = new LinkGoTo(&obj1); + action = LinkAction::parseDest(&obj1); // look for action } else { obj1.free(); if (dict->lookup("A", &obj1)->isDict()) { - obj1.dictLookup("S", &obj2); - - // GoTo action - if (obj2.isName("GoTo")) { - obj1.dictLookup("D", &obj3); - action = new LinkGoTo(&obj3); - obj3.free(); - - // GoToR action - } else if (obj2.isName("GoToR")) { - obj1.dictLookup("F", &obj3); - obj1.dictLookup("D", &obj4); - action = new LinkGoToR(&obj3, &obj4); - obj3.free(); - obj4.free(); - - // Launch action - } else if (obj2.isName("Launch")) { - action = new LinkLaunch(&obj1); - - // URI action - } else if (obj2.isName("URI")) { - obj1.dictLookup("URI", &obj3); - action = new LinkURI(&obj3, baseURI); - obj3.free(); - - // Named action - } else if (obj2.isName("Named")) { - obj1.dictLookup("N", &obj3); - action = new LinkNamed(&obj3); - obj3.free(); - - // unknown action - } else if (obj2.isName()) { - action = new LinkUnknown(obj2.getName()); - - // action is missing or wrong type - } else { - error(-1, "Bad annotation action"); - action = NULL; - } - - obj2.free(); - - } else { - error(-1, "Missing annotation destination/action"); - action = NULL; + action = LinkAction::parseAction(&obj1, baseURI); } } obj1.free(); // check for bad action - if (action && action->isOk()) + if (action) { ok = gTrue; + } return; @@ -527,8 +775,12 @@ Link::Link(Dict *dict, GString *baseURI) { } Link::~Link() { - if (action) + if (borderStyle) { + delete borderStyle; + } + if (action) { delete action; + } } //------------------------------------------------------------------------ @@ -595,36 +847,3 @@ GBool Links::onLink(double x, double y) { } return gFalse; } - -//------------------------------------------------------------------------ - -// Extract a file name from a file specification (string or dictionary). -static GString *getFileSpecName(Object *fileSpecObj) { - GString *name; - Object obj1; - - name = NULL; - - // string - if (fileSpecObj->isString()) { - name = fileSpecObj->getString()->copy(); - - // dictionary - } else if (fileSpecObj->isDict()) { - if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { - obj1.free(); - fileSpecObj->dictLookup("F", &obj1); - } - if (obj1.isString()) - name = obj1.getString()->copy(); - else - error(-1, "Illegal file spec in link"); - obj1.free(); - - // error - } else { - error(-1, "Illegal file spec in link"); - } - - return name; -} diff --git a/pdf2swf/xpdf/Link.h b/pdf2swf/xpdf/Link.h index 4c644b8..9f04420 100644 --- a/pdf2swf/xpdf/Link.h +++ b/pdf2swf/xpdf/Link.h @@ -2,14 +2,16 @@ // // Link.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef LINK_H #define LINK_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -29,6 +31,7 @@ enum LinkActionKind { actionLaunch, // launch app (or open document) actionURI, // URI actionNamed, // named action + actionMovie, // movie action actionUnknown // anything else }; @@ -43,6 +46,16 @@ public: // Check link action type. virtual LinkActionKind getKind() = 0; + + // Parse a destination (old-style action) name, string, or array. + static LinkAction *parseDest(Object *obj); + + // Parse an action dictionary. + static LinkAction *parseAction(Object *obj, GString *baseURI = NULL); + + // Extract a file name from a file specification (string or + // dictionary). + static GString *getFileSpecName(Object *fileSpecObj); }; //------------------------------------------------------------------------ @@ -240,6 +253,30 @@ private: }; //------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +class LinkMovie: public LinkAction { +public: + + LinkMovie(Object *annotObj, Object *titleObj); + + virtual ~LinkMovie(); + + virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; } + + virtual LinkActionKind getKind() { return actionMovie; } + GBool hasAnnotRef() { return annotRef.num >= 0; } + Ref *getAnnotRef() { return &annotRef; } + GString *getTitle() { return title; } + +private: + + Ref annotRef; + GString *title; +}; + +//------------------------------------------------------------------------ // LinkUnknown //------------------------------------------------------------------------ @@ -265,6 +302,42 @@ private: }; //------------------------------------------------------------------------ +// LinkBorderStyle +//------------------------------------------------------------------------ + +enum LinkBorderType { + linkBorderSolid, + linkBorderDashed, + linkBorderEmbossed, + linkBorderEngraved, + linkBorderUnderlined +}; + +class LinkBorderStyle { +public: + + LinkBorderStyle(LinkBorderType typeA, double widthA, + double *dashA, int dashLengthA, + double rA, double gA, double bA); + ~LinkBorderStyle(); + + LinkBorderType getType() { return type; } + double getWidth() { return width; } + void getDash(double **dashA, int *dashLengthA) + { *dashA = dash; *dashLengthA = dashLength; } + void getColor(double *rA, double *gA, double *bA) + { *rA = r; *gA = g; *bA = b; } + +private: + + LinkBorderType type; + double width; + double *dash; + int dashLength; + double r, g, b; +}; + +//------------------------------------------------------------------------ // Link //------------------------------------------------------------------------ @@ -287,16 +360,18 @@ public: // Get action. LinkAction *getAction() { return action; } - // Get border corners and width. - void getBorder(double *xa1, double *ya1, double *xa2, double *ya2, - double *wa) - { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; *wa = borderW; } + // Get the link rectangle. + void getRect(double *xa1, double *ya1, double *xa2, double *ya2) + { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } + + // Get the border style info. + LinkBorderStyle *getBorderStyle() { return borderStyle; } private: double x1, y1; // lower left corner double x2, y2; // upper right corner - double borderW; // border width + LinkBorderStyle *borderStyle; // border style LinkAction *action; // action GBool ok; // is link valid? }; diff --git a/pdf2swf/xpdf/NameToCharCode.cc b/pdf2swf/xpdf/NameToCharCode.cc index b9cde77..8f22a90 100644 --- a/pdf2swf/xpdf/NameToCharCode.cc +++ b/pdf2swf/xpdf/NameToCharCode.cc @@ -2,15 +2,16 @@ // // NameToCharCode.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "gmem.h" #include "NameToCharCode.h" diff --git a/pdf2swf/xpdf/NameToCharCode.h b/pdf2swf/xpdf/NameToCharCode.h index 22e41b6..65453c3 100644 --- a/pdf2swf/xpdf/NameToCharCode.h +++ b/pdf2swf/xpdf/NameToCharCode.h @@ -2,14 +2,16 @@ // // NameToCharCode.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef NAMETOCHARCODE_H #define NAMETOCHARCODE_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/NameToUnicodeTable.h b/pdf2swf/xpdf/NameToUnicodeTable.h index 432fafb..4f28fff 100644 --- a/pdf2swf/xpdf/NameToUnicodeTable.h +++ b/pdf2swf/xpdf/NameToUnicodeTable.h @@ -2,7 +2,7 @@ // // NameToUnicodeTable.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -10,6 +10,37 @@ static struct { Unicode u; char *name; } nameToUnicodeTab[] = { + {0x0021, "!"}, + {0x0023, "#"}, + {0x0024, "$"}, + {0x0025, "%"}, + {0x0026, "&"}, + {0x0027, "'"}, + {0x0028, "("}, + {0x0029, ")"}, + {0x002a, "*"}, + {0x002b, "+"}, + {0x002c, ","}, + {0x002d, "-"}, + {0x002e, "."}, + {0x002f, "/"}, + {0x0030, "0"}, + {0x0031, "1"}, + {0x0032, "2"}, + {0x0033, "3"}, + {0x0034, "4"}, + {0x0035, "5"}, + {0x0036, "6"}, + {0x0037, "7"}, + {0x0038, "8"}, + {0x0039, "9"}, + {0x003a, ":"}, + {0x003b, ";"}, + {0x003c, "<"}, + {0x003d, "="}, + {0x003e, ">"}, + {0x003f, "?"}, + {0x0040, "@"}, {0x0041, "A"}, {0x00c6, "AE"}, {0x01fc, "AEacute"}, @@ -304,6 +335,12 @@ static struct { {0x017b, "Zdotaccent"}, {0x0396, "Zeta"}, {0x005a, "Zsmall"}, + {0x0022, "\""}, + {0x005c, "\\"}, + {0x005d, "]"}, + {0x005e, "^"}, + {0x005f, "_"}, + {0x0060, "`"}, {0x0061, "a"}, {0x00e1, "aacute"}, {0x0103, "abreve"}, @@ -647,8 +684,8 @@ static struct { {0xf6e2, "commasuperior"}, {0x2245, "congruent"}, {0x00a9, "copyright"}, - {0xf8e9, "copyrightsans"}, - {0xf6d9, "copyrightserif"}, + {0x00a9, "copyrightsans"}, + {0x00a9, "copyrightserif"}, {0x00a4, "currency"}, {0xf6d1, "cyrBreve"}, {0xf6d2, "cyrFlex"}, @@ -715,6 +752,7 @@ static struct { {0x203c, "exclamdbl"}, {0x00a1, "exclamdown"}, {0x00a1, "exclamdownsmall"}, + {0x0021, "exclamleft"}, {0x0021, "exclamsmall"}, {0x2203, "existential"}, {0x0066, "f"}, @@ -934,8 +972,8 @@ static struct { {0x2286, "reflexsubset"}, {0x2287, "reflexsuperset"}, {0x00ae, "registered"}, - {0xf8e8, "registersans"}, - {0xf6da, "registerserif"}, + {0x00ae, "registersans"}, + {0x00ae, "registerserif"}, {0x2310, "revlogicalnot"}, {0x03c1, "rho"}, {0x02da, "ring"}, @@ -993,8 +1031,8 @@ static struct { {0x0303, "tildecomb"}, {0x0384, "tonos"}, {0x2122, "trademark"}, - {0xf8ea, "trademarksans"}, - {0xf6db, "trademarkserif"}, + {0x2122, "trademarksans"}, + {0x2122, "trademarkserif"}, {0x25bc, "triagdn"}, {0x25c4, "triaglf"}, {0x25ba, "triagrt"}, @@ -1051,5 +1089,9 @@ static struct { {0x0030, "zerooldstyle"}, {0x2070, "zerosuperior"}, {0x03b6, "zeta"}, + {0x007b, "{"}, + {0x007c, "|"}, + {0x007d, "}"}, + {0x007e, "~"}, { 0, NULL } }; diff --git a/pdf2swf/xpdf/Object.cc b/pdf2swf/xpdf/Object.cc index 6d92c6a..ddd6da6 100644 --- a/pdf2swf/xpdf/Object.cc +++ b/pdf2swf/xpdf/Object.cc @@ -2,15 +2,16 @@ // // Object.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "Object.h" #include "Array.h" @@ -57,6 +58,13 @@ Object *Object::initDict(XRef *xref) { return this; } +Object *Object::initDict(Dict *dictA) { + initObj(objDict); + dict = dictA; + dict->incRef(); + return this; +} + Object *Object::initStream(Stream *streamA) { initObj(objStream); stream = streamA; diff --git a/pdf2swf/xpdf/Object.h b/pdf2swf/xpdf/Object.h index 65d0be0..8b1807c 100644 --- a/pdf2swf/xpdf/Object.h +++ b/pdf2swf/xpdf/Object.h @@ -2,14 +2,16 @@ // // Object.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef OBJECT_H #define OBJECT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -93,6 +95,7 @@ public: { initObj(objNull); return this; } Object *initArray(XRef *xref); Object *initDict(XRef *xref); + Object *initDict(Dict *dictA); Object *initStream(Stream *streamA); Object *initRef(int numA, int genA) { initObj(objRef); ref.num = numA; ref.gen = genA; return this; } @@ -152,6 +155,7 @@ public: Ref getRef() { return ref; } int getRefNum() { return ref.num; } int getRefGen() { return ref.gen; } + char *getCmd() { return cmd; } // Array accessors. int arrayGetLength(); diff --git a/pdf2swf/xpdf/Outline.cc b/pdf2swf/xpdf/Outline.cc new file mode 100644 index 0000000..04891f3 --- /dev/null +++ b/pdf2swf/xpdf/Outline.cc @@ -0,0 +1,151 @@ +//======================================================================== +// +// Outline.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "GString.h" +#include "GList.h" +#include "Link.h" +#include "PDFDocEncoding.h" +#include "Outline.h" + +//------------------------------------------------------------------------ + +Outline::Outline(Object *outlineObj, XRef *xref) { + Object first, last; + + items = NULL; + if (!outlineObj->isDict()) { + return; + } + items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first), + outlineObj->dictLookupNF("Last", &last), + xref); + first.free(); + last.free(); +} + +Outline::~Outline() { + if (items) { + deleteGList(items, OutlineItem); + } +} + +//------------------------------------------------------------------------ + +OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { + Object obj1; + GString *s; + int i; + + xref = xrefA; + title = NULL; + action = NULL; + kids = NULL; + + if (dict->lookup("Title", &obj1)->isString()) { + s = obj1.getString(); + if ((s->getChar(0) & 0xff) == 0xfe && + (s->getChar(1) & 0xff) == 0xff) { + titleLen = (s->getLength() - 2) / 2; + title = (Unicode *)gmalloc(titleLen * sizeof(Unicode)); + for (i = 0; i < titleLen; ++i) { + title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | + (s->getChar(3 + 2*i) & 0xff); + } + } else { + titleLen = s->getLength(); + title = (Unicode *)gmalloc(titleLen * sizeof(Unicode)); + for (i = 0; i < titleLen; ++i) { + title[i] = pdfDocEncoding[s->getChar(i) & 0xff]; + } + } + } else { + titleLen = 0; + } + obj1.free(); + + if (!dict->lookup("Dest", &obj1)->isNull()) { + action = LinkAction::parseDest(&obj1); + } else { + obj1.free(); + if (dict->lookup("A", &obj1)) { + action = LinkAction::parseAction(&obj1); + } + } + obj1.free(); + + dict->lookupNF("First", &firstRef); + dict->lookupNF("Last", &lastRef); + dict->lookupNF("Next", &nextRef); + + startsOpen = gFalse; + if (dict->lookup("Count", &obj1)->isInt()) { + if (obj1.getInt() > 0) { + startsOpen = gTrue; + } + } + obj1.free(); +} + +OutlineItem::~OutlineItem() { + close(); + if (title) { + gfree(title); + } + if (action) { + delete action; + } + firstRef.free(); + lastRef.free(); + nextRef.free(); +} + +GList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef, + XRef *xrefA) { + GList *items; + OutlineItem *item; + Object obj; + Object *p; + + items = new GList(); + p = firstItemRef; + while (p->isRef()) { + if (!p->fetch(xrefA, &obj)->isDict()) { + obj.free(); + break; + } + item = new OutlineItem(obj.getDict(), xrefA); + obj.free(); + items->append(item); + if (p->getRef().num == lastItemRef->getRef().num && + p->getRef().gen == lastItemRef->getRef().gen) { + break; + } + p = &item->nextRef; + } + return items; +} + +void OutlineItem::open() { + if (!kids) { + kids = readItemList(&firstRef, &lastRef, xref); + } +} + +void OutlineItem::close() { + if (kids) { + deleteGList(kids, OutlineItem); + kids = NULL; + } +} diff --git a/pdf2swf/xpdf/Outline.h b/pdf2swf/xpdf/Outline.h new file mode 100644 index 0000000..f38f8d1 --- /dev/null +++ b/pdf2swf/xpdf/Outline.h @@ -0,0 +1,76 @@ +//======================================================================== +// +// Outline.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef OUTLINE_H +#define OUTLINE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" +#include "CharTypes.h" + +class GString; +class GList; +class XRef; +class LinkAction; + +//------------------------------------------------------------------------ + +class Outline { +public: + + Outline(Object *outlineObj, XRef *xref); + ~Outline(); + + GList *getItems() { return items; } + +private: + + GList *items; // NULL if document has no outline + // [OutlineItem] +}; + +//------------------------------------------------------------------------ + +class OutlineItem { +public: + + OutlineItem(Dict *dict, XRef *xrefA); + ~OutlineItem(); + + static GList *readItemList(Object *firstItemRef, Object *lastItemRef, + XRef *xrefA); + + void open(); + void close(); + + Unicode *getTitle() { return title; } + int getTitleLength() { return titleLen; } + LinkAction *getAction() { return action; } + GBool isOpen() { return startsOpen; } + GBool hasKids() { return firstRef.isRef(); } + GList *getKids() { return kids; } + +private: + + XRef *xref; + Unicode *title; + int titleLen; + LinkAction *action; + Object firstRef; + Object lastRef; + Object nextRef; + GBool startsOpen; + GList *kids; // NULL unless this item is open [OutlineItem] +}; + +#endif diff --git a/pdf2swf/xpdf/OutputDev.cc b/pdf2swf/xpdf/OutputDev.cc index 6d46542..e83882d 100644 --- a/pdf2swf/xpdf/OutputDev.cc +++ b/pdf2swf/xpdf/OutputDev.cc @@ -2,15 +2,16 @@ // // OutputDev.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "Object.h" #include "Stream.h" @@ -37,7 +38,7 @@ void OutputDev::setDefaultCTM(double *ctm) { defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det; } -void OutputDev::cvtDevToUser(int dx, int dy, double *ux, double *uy) { +void OutputDev::cvtDevToUser(double dx, double dy, double *ux, double *uy) { *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4]; *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5]; } @@ -59,7 +60,8 @@ void OutputDev::updateAll(GfxState *state) { updateFont(state); } -GBool OutputDev::beginType3Char(GfxState *state, +GBool OutputDev::beginType3Char(GfxState *state, double x, double y, + double dx, double dy, CharCode code, Unicode *u, int uLen) { return gFalse; } diff --git a/pdf2swf/xpdf/OutputDev.h b/pdf2swf/xpdf/OutputDev.h index 4a05f1a..fb7d8ab 100644 --- a/pdf2swf/xpdf/OutputDev.h +++ b/pdf2swf/xpdf/OutputDev.h @@ -2,14 +2,16 @@ // // OutputDev.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef OUTPUTDEV_H #define OUTPUTDEV_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -59,7 +61,7 @@ public: virtual void setDefaultCTM(double *ctm); // Start a page. - virtual void startPage(int pageNum, GfxState *state, double x1,double y1,double x2,double y2) {} + virtual void startPage(int pageNum, GfxState *state) {} // End a page. virtual void endPage() {} @@ -70,7 +72,7 @@ public: //----- coordinate conversion // Convert between device and user coordinates. - virtual void cvtDevToUser(int dx, int dy, double *ux, double *uy); + virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy); virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy); //----- link borders @@ -123,9 +125,11 @@ public: double originX, double originY, CharCode code, Unicode *u, int uLen) {} virtual void drawString(GfxState *state, GString *s) {} - virtual GBool beginType3Char(GfxState *state, + virtual GBool beginType3Char(GfxState *state, double x, double y, + double dx, double dy, CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state) {} + virtual void endTextObject(GfxState *state) {} //----- image drawing virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, diff --git a/pdf2swf/xpdf/PDFDoc.cc b/pdf2swf/xpdf/PDFDoc.cc index 29abba0..b5981d9 100644 --- a/pdf2swf/xpdf/PDFDoc.cc +++ b/pdf2swf/xpdf/PDFDoc.cc @@ -2,21 +2,23 @@ // // PDFDoc.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include #include #include "GString.h" #include "config.h" +#include "GlobalParams.h" #include "Page.h" #include "Catalog.h" #include "Stream.h" @@ -27,6 +29,9 @@ #include "ErrorCodes.h" #include "Lexer.h" #include "Parser.h" +#ifndef DISABLE_OUTLINE +#include "Outline.h" +#endif #include "PDFDoc.h" //------------------------------------------------------------------------ @@ -39,9 +44,9 @@ //------------------------------------------------------------------------ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, - GString *userPassword, GBool printCommandsA) { + GString *userPassword) { Object obj; - GString *fileName2; + GString *fileName1, *fileName2; ok = gFalse; errCode = errNone; @@ -51,19 +56,24 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, xref = NULL; catalog = NULL; links = NULL; - printCommands = printCommandsA; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif - // try to open file fileName = fileNameA; + fileName1 = fileName; + + + // try to open file fileName2 = NULL; #ifdef VMS - if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) { - error(-1, "Couldn't open file '%s'", fileName->getCString()); + if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) { + error(-1, "Couldn't open file '%s'", fileName1->getCString()); errCode = errOpenFile; return; } #else - if (!(file = fopen(fileName->getCString(), "rb"))) { + if (!(file = fopen(fileName1->getCString(), "rb"))) { fileName2 = fileName->copy(); fileName2->lowerCase(); if (!(file = fopen(fileName2->getCString(), "rb"))) { @@ -87,7 +97,7 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, } PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, - GString *userPassword, GBool printCommandsA) { + GString *userPassword) { ok = gFalse; errCode = errNone; fileName = NULL; @@ -96,11 +106,15 @@ PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, xref = NULL; catalog = NULL; links = NULL; - printCommands = printCommandsA; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif ok = setup(ownerPassword, userPassword); } GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { + str->reset(); + // check header checkHeader(); @@ -113,18 +127,28 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { } // read catalog - catalog = new Catalog(xref, printCommands); + catalog = new Catalog(xref); if (!catalog->isOk()) { error(-1, "Couldn't read page catalog"); errCode = errBadCatalog; return gFalse; } +#ifndef DISABLE_OUTLINE + // read outline + outline = new Outline(catalog->getOutline(), xref); +#endif + // done return gTrue; } PDFDoc::~PDFDoc() { +#ifndef DISABLE_OUTLINE + if (outline) { + delete outline; + } +#endif if (catalog) { delete catalog; } @@ -176,11 +200,13 @@ void PDFDoc::checkHeader() { } } -void PDFDoc::displayPage(OutputDev *out, int page, double zoom, - int rotate, GBool doLinks) { +void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, + int rotate, GBool crop, GBool doLinks, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { Page *p; - if (printCommands) { + if (globalParams->getPrintCommands()) { printf("***** page %d *****\n", page); } p = catalog->getPage(page); @@ -189,21 +215,41 @@ void PDFDoc::displayPage(OutputDev *out, int page, double zoom, delete links; } getLinks(p); - p->display(out, zoom, rotate, links, catalog); + p->display(out, hDPI, vDPI, rotate, crop, links, catalog, + abortCheckCbk, abortCheckCbkData); } else { - p->display(out, zoom, rotate, NULL, catalog); + p->display(out, hDPI, vDPI, rotate, crop, NULL, catalog, + abortCheckCbk, abortCheckCbkData); } } void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, - int zoom, int rotate, GBool doLinks) { + double hDPI, double vDPI, int rotate, + GBool crop, GBool doLinks, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { int page; for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, zoom, rotate, doLinks); + displayPage(out, page, hDPI, vDPI, rotate, crop, doLinks, + abortCheckCbk, abortCheckCbkData); } } +void PDFDoc::displayPageSlice(OutputDev *out, int page, + double hDPI, double vDPI, + int rotate, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + Page *p; + + p = catalog->getPage(page); + p->displaySlice(out, hDPI, vDPI, rotate, crop, + sliceX, sliceY, sliceW, sliceH, + NULL, catalog, abortCheckCbk, abortCheckCbkData); +} + GBool PDFDoc::isLinearized() { Parser *parser; Object obj1, obj2, obj3, obj4, obj5; diff --git a/pdf2swf/xpdf/PDFDoc.h b/pdf2swf/xpdf/PDFDoc.h index c12531e..bdcbd65 100644 --- a/pdf2swf/xpdf/PDFDoc.h +++ b/pdf2swf/xpdf/PDFDoc.h @@ -2,14 +2,16 @@ // // PDFDoc.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PDFDOC_H #define PDFDOC_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -25,6 +27,7 @@ class OutputDev; class Links; class LinkAction; class LinkDest; +class Outline; //------------------------------------------------------------------------ // PDFDoc @@ -34,9 +37,9 @@ class PDFDoc { public: PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, - GString *userPassword = NULL, GBool printCommandsA = gFalse); + GString *userPassword = NULL); PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, - GString *userPassword = NULL, GBool printCommandsA = gFalse); + GString *userPassword = NULL); ~PDFDoc(); // Was PDF document successfully opened? @@ -76,12 +79,25 @@ public: Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); } // Display a page. - void displayPage(OutputDev *out, int page, double zoom, - int rotate, GBool doLinks); + void displayPage(OutputDev *out, int page, double hDPI, double vDPI, + int rotate, GBool crop, GBool doLinks, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); // Display a range of pages. void displayPages(OutputDev *out, int firstPage, int lastPage, - int zoom, int rotate, GBool doLinks); + double hDPI, double vDPI, int rotate, + GBool crop, GBool doLinks, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display part of a page. + void displayPageSlice(OutputDev *out, int page, + double hDPI, double vDPI, + int rotate, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); // Find a page, given its object ID. Returns page number, or 0 if // not found. @@ -89,7 +105,8 @@ public: // If point , is in a link, return the associated action; // else return NULL. - LinkAction *findLink(double x, double y) { return links->find(x, y); } + LinkAction *findLink(double x, double y) + { return links ? links->find(x, y) : (LinkAction *)NULL; } // Return true if , is in a link. GBool onLink(double x, double y) { return links->onLink(x, y); } @@ -99,6 +116,11 @@ public: LinkDest *findDest(GString *name) { return catalog->findDest(name); } +#ifndef DISABLE_OUTLINE + // Return the outline object. + Outline *getOutline() { return outline; } +#endif + // Is the file encrypted? GBool isEncrypted() { return xref->isEncrypted(); } @@ -117,6 +139,7 @@ public: // Return the document's Info dictionary (if any). Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); } + Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); } // Return the PDF version specified by the file. double getPDFVersion() { return pdfVersion; } @@ -124,6 +147,7 @@ public: // Save this file with another name. GBool saveAs(GString *name); + private: GBool setup(GString *ownerPassword, GString *userPassword); @@ -137,7 +161,10 @@ private: XRef *xref; Catalog *catalog; Links *links; - GBool printCommands; +#ifndef DISABLE_OUTLINE + Outline *outline; +#endif + GBool ok; int errCode; diff --git a/pdf2swf/xpdf/PDFDocEncoding.cc b/pdf2swf/xpdf/PDFDocEncoding.cc new file mode 100644 index 0000000..89dc382 --- /dev/null +++ b/pdf2swf/xpdf/PDFDocEncoding.cc @@ -0,0 +1,44 @@ +//======================================================================== +// +// PDFDocEncoding.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include "PDFDocEncoding.h" + +Unicode pdfDocEncoding[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 10 + 0x02d8, 0x02c7, 0x02c6, 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20 + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30 + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40 + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50 + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60 + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70 + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000, + 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, // 80 + 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, + 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, // 90 + 0x0178, 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0x0000, + 0x20ac, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, // a0 + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, // b0 + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, // c0 + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, // d0 + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, // e0 + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, // f0 + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff +}; diff --git a/pdf2swf/xpdf/PDFDocEncoding.h b/pdf2swf/xpdf/PDFDocEncoding.h new file mode 100644 index 0000000..3259d3e --- /dev/null +++ b/pdf2swf/xpdf/PDFDocEncoding.h @@ -0,0 +1,16 @@ +//======================================================================== +// +// PDFDocEncoding.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PDFDOCENCODING_H +#define PDFDOCENCODING_H + +#include "CharTypes.h" + +extern Unicode pdfDocEncoding[256]; + +#endif diff --git a/pdf2swf/xpdf/PSTokenizer.cc b/pdf2swf/xpdf/PSTokenizer.cc index 8d654bd..a65c324 100644 --- a/pdf2swf/xpdf/PSTokenizer.cc +++ b/pdf2swf/xpdf/PSTokenizer.cc @@ -2,11 +2,13 @@ // // PSTokenizer.cc // -// Copyright 2002 Glyph & Cog, LLC +// Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif diff --git a/pdf2swf/xpdf/PSTokenizer.h b/pdf2swf/xpdf/PSTokenizer.h index 1053c67..4d5ee97 100644 --- a/pdf2swf/xpdf/PSTokenizer.h +++ b/pdf2swf/xpdf/PSTokenizer.h @@ -2,14 +2,16 @@ // // PSTokenizer.h // -// Copyright 2002 Glyph & Cog, LLC +// Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PSTOKENIZER_H #define PSTOKENIZER_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/Page.cc b/pdf2swf/xpdf/Page.cc index c601857..ab8504d 100644 --- a/pdf2swf/xpdf/Page.cc +++ b/pdf2swf/xpdf/Page.cc @@ -2,16 +2,18 @@ // // Page.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include +#include "GlobalParams.h" #include "Object.h" #include "Array.h" #include "Dict.h" @@ -57,8 +59,12 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { readBox(dict, "MediaBox", &mediaBox); // crop box - cropBox = mediaBox; - haveCropBox = readBox(dict, "CropBox", &cropBox); + if (readBox(dict, "CropBox", &cropBox)) { + haveCropBox = gTrue; + } + if (!haveCropBox) { + cropBox = mediaBox; + } // if the MediaBox is excessively larger than the CropBox, // just use the CropBox @@ -170,13 +176,10 @@ GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) { // Page //------------------------------------------------------------------------ -Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, - GBool printCommandsA) { - +Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) { ok = gTrue; xref = xrefA; num = numA; - printCommands = printCommandsA; // get attributes attrs = attrsA; @@ -215,22 +218,91 @@ Page::~Page() { contents.free(); } -void Page::display(OutputDev *out, double dpi, int rotate, - Links *links, Catalog *catalog) { +void Page::display(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool crop, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + displaySlice(out, hDPI, vDPI, rotate, crop, -1, -1, -1, -1, links, catalog, + abortCheckCbk, abortCheckCbkData); +} + +void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { #ifndef PDF_PARSER_ONLY - PDFRectangle *box, *cropBox; + PDFRectangle *mediaBox, *cropBox; + PDFRectangle box; Gfx *gfx; Object obj; Link *link; - int i; Annots *annotList; + double kx, ky; + int i; - box = getBox(); + rotate += getRotate(); + if (rotate >= 360) { + rotate -= 360; + } else if (rotate < 0) { + rotate += 360; + } + + mediaBox = getBox(); + if (sliceW >= 0 && sliceH >= 0) { + kx = 72.0 / hDPI; + ky = 72.0 / vDPI; + if (rotate == 90) { + if (out->upsideDown()) { + box.x1 = mediaBox->x1 + ky * sliceY; + box.x2 = mediaBox->x1 + ky * (sliceY + sliceH); + } else { + box.x1 = mediaBox->x2 - ky * (sliceY + sliceH); + box.x2 = mediaBox->x2 - ky * sliceY; + } + box.y1 = mediaBox->y1 + kx * sliceX; + box.y2 = mediaBox->y1 + kx * (sliceX + sliceW); + } else if (rotate == 180) { + box.x1 = mediaBox->x2 - kx * (sliceX + sliceW); + box.x2 = mediaBox->x2 - kx * sliceX; + if (out->upsideDown()) { + box.y1 = mediaBox->y1 + ky * sliceY; + box.y2 = mediaBox->y1 + ky * (sliceY + sliceH); + } else { + box.y1 = mediaBox->y2 - ky * (sliceY + sliceH); + box.y2 = mediaBox->y2 - ky * sliceY; + } + } else if (rotate == 270) { + if (out->upsideDown()) { + box.x1 = mediaBox->x2 - ky * (sliceY + sliceH); + box.x2 = mediaBox->x2 - ky * sliceY; + } else { + box.x1 = mediaBox->x1 + ky * sliceY; + box.x2 = mediaBox->x1 + ky * (sliceY + sliceH); + } + box.y1 = mediaBox->y2 - kx * (sliceX + sliceW); + box.y2 = mediaBox->y2 - kx * sliceX; + } else { + box.x1 = mediaBox->x1 + kx * sliceX; + box.x2 = mediaBox->x1 + kx * (sliceX + sliceW); + if (out->upsideDown()) { + box.y1 = mediaBox->y2 - ky * (sliceY + sliceH); + box.y2 = mediaBox->y2 - ky * sliceY; + } else { + box.y1 = mediaBox->y1 + ky * sliceY; + box.y2 = mediaBox->y1 + ky * (sliceY + sliceH); + } + } + } else { + box = *mediaBox; + } cropBox = getCropBox(); - if (printCommands) { + if (globalParams->getPrintCommands()) { printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", - box->x1, box->y1, box->x2, box->y2); + box.x1, box.y1, box.x2, box.y2); if (isCropped()) { printf("***** CropBox = ll:%g,%g ur:%g,%g\n", cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); @@ -238,35 +310,33 @@ void Page::display(OutputDev *out, double dpi, int rotate, printf("***** Rotate = %d\n", attrs->getRotate()); } - rotate += getRotate(); - if (rotate >= 360) { - rotate -= 360; - } else if (rotate < 0) { - rotate += 360; - } gfx = new Gfx(xref, out, num, attrs->getResourceDict(), - dpi, box, isCropped(), cropBox, rotate, printCommands); + hDPI, vDPI, &box, crop && isCropped(), cropBox, rotate, + abortCheckCbk, abortCheckCbkData); contents.fetch(xref, &obj); if (!obj.isNull()) { + gfx->saveState(); gfx->display(&obj); + gfx->restoreState(); } obj.free(); // draw links if (links) { + gfx->saveState(); for (i = 0; i < links->getNumLinks(); ++i) { link = links->getLink(i); out->drawLink(link, catalog); } + gfx->restoreState(); out->dump(); } // draw non-link annotations - //~ need to reset CTM ??? annotList = new Annots(xref, annots.fetch(xref, &obj)); obj.free(); if (annotList->getNumAnnots() > 0) { - if (printCommands) { + if (globalParams->getPrintCommands()) { printf("***** Annotations\n"); } for (i = 0; i < annotList->getNumAnnots(); ++i) { diff --git a/pdf2swf/xpdf/Page.h b/pdf2swf/xpdf/Page.h index 7207b20..2376cb4 100644 --- a/pdf2swf/xpdf/Page.h +++ b/pdf2swf/xpdf/Page.h @@ -2,14 +2,16 @@ // // Page.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PAGE_H #define PAGE_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -23,8 +25,14 @@ class Catalog; //------------------------------------------------------------------------ -struct PDFRectangle { +class PDFRectangle { +public: double x1, y1, x2, y2; + + PDFRectangle() { x1 = y1 = x2 = y2 = 0; } + PDFRectangle(double x1A, double y1A, double x2A, double y2A) + { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } + GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } }; //------------------------------------------------------------------------ @@ -97,8 +105,7 @@ class Page { public: // Constructor. - Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, - GBool printCommandsA); + Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA); // Destructor. ~Page(); @@ -134,8 +141,19 @@ public: Object *getContents(Object *obj) { return contents.fetch(xref, obj); } // Display a page. - void display(OutputDev *out, double dpi, int rotate, - Links *links, Catalog *catalog); + void display(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool crop, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display part of a page. + void displaySlice(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); private: @@ -144,7 +162,6 @@ private: PageAttrs *attrs; // page attributes Object annots; // annotations array Object contents; // page contents - GBool printCommands; // print the drawing commands (for debugging) GBool ok; // true if page is valid }; diff --git a/pdf2swf/xpdf/Parser.cc b/pdf2swf/xpdf/Parser.cc index 4df53c9..0aa66d3 100644 --- a/pdf2swf/xpdf/Parser.cc +++ b/pdf2swf/xpdf/Parser.cc @@ -2,15 +2,16 @@ // // Parser.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "Object.h" #include "Array.h" @@ -88,8 +89,10 @@ Object *Parser::getObj(Object *obj) { } else { key = copyString(buf1.getName()); shift(); - if (buf1.isEOF() || buf1.isError()) + if (buf1.isEOF() || buf1.isError()) { + gfree(key); break; + } #ifndef NO_DECRYPTION obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); #else @@ -173,10 +176,16 @@ Stream *Parser::makeStream(Object *dict) { } // check for length in damaged file - if (xref->getStreamEnd(pos, &endPos)) { + if (xref && xref->getStreamEnd(pos, &endPos)) { length = endPos - pos; } + // in badly damaged PDF files, we can run off the end of the input + // stream immediately after the "stream" token + if (!lexer->getStream()) { + return NULL; + } + // make base stream str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue, length, dict); @@ -190,17 +199,25 @@ Stream *Parser::makeStream(Object *dict) { // refill token buffers and check for 'endstream' shift(); // kill '>>' shift(); // kill 'stream' - if (buf1.isCmd("endstream")) + if (buf1.isCmd("endstream")) { shift(); - else + } else { error(getPos(), "Missing 'endstream'"); + str->ignoreLength(); + } return str; } void Parser::shift() { if (inlineImg > 0) { - ++inlineImg; + if (inlineImg < 2) { + ++inlineImg; + } else { + // in a damaged content stream, if 'ID' shows up in the middle + // of a dictionary, we need to reset + inlineImg = 0; + } } else if (buf2.isCmd("ID")) { lexer->skipChar(); // skip char after 'ID' command inlineImg = 1; diff --git a/pdf2swf/xpdf/Parser.h b/pdf2swf/xpdf/Parser.h index c11475b..3bc3ab2 100644 --- a/pdf2swf/xpdf/Parser.h +++ b/pdf2swf/xpdf/Parser.h @@ -2,14 +2,16 @@ // // Parser.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PARSER_H #define PARSER_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf2swf/xpdf/Stream-CCITT.h b/pdf2swf/xpdf/Stream-CCITT.h index f5a77b0..c4458fe 100644 --- a/pdf2swf/xpdf/Stream-CCITT.h +++ b/pdf2swf/xpdf/Stream-CCITT.h @@ -4,7 +4,7 @@ // // Tables for CCITT Fax decoding. // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf2swf/xpdf/Stream.cc b/pdf2swf/xpdf/Stream.cc index c47c5af..49bbb46 100644 --- a/pdf2swf/xpdf/Stream.cc +++ b/pdf2swf/xpdf/Stream.cc @@ -2,22 +2,21 @@ // // Stream.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include #ifndef WIN32 #include -#else -extern "C" int unlink(char *filename); #endif #include #include @@ -30,6 +29,8 @@ extern "C" int unlink(char *filename); #include "Decrypt.h" #endif #include "Stream.h" +#include "JBIG2Stream.h" +#include "JPXStream.h" #include "Stream-CCITT.h" #ifdef __DJGPP__ @@ -37,9 +38,6 @@ static GBool setDJSYSFLAGS = gFalse; #endif #ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif #ifdef __GNUC__ #define SEEK_SET 0 #define SEEK_CUR 1 @@ -47,10 +45,6 @@ extern "C" int unlink(char *filename); #endif #endif -#ifdef MACOS -#include "StuffItEngineLib.h" -#endif - //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ @@ -91,7 +85,7 @@ char *Stream::getLine(char *buf, int size) { return buf; } -GString *Stream::getPSFilter(char *indent) { +GString *Stream::getPSFilter(int psLevel, char *indent) { return new GString(); } @@ -147,7 +141,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { int encoding; GBool endOfLine, byteAlign, endOfBlock, black; int columns, rows; - Object obj; + Object globals, obj; if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { str = new ASCIIHexStream(str); @@ -257,6 +251,14 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { obj.free(); } str = new FlateStream(str, pred, columns, colors, bits); + } else if (!strcmp(name, "JBIG2Decode")) { + if (params->isDict()) { + params->dictLookup("JBIG2Globals", &globals); + } + str = new JBIG2Stream(str, &globals); + globals.free(); + } else if (!strcmp(name, "JPXDecode")) { + str = new JPXStream(str); } else { error(getPos(), "Unknown filter '%s'", name); str = new EOFStream(str); @@ -340,51 +342,54 @@ void ImageStream::reset() { } GBool ImageStream::getPixel(Guchar *pix) { + int i; + + if (imgIdx >= nVals) { + getLine(); + imgIdx = 0; + } + for (i = 0; i < nComps; ++i) { + pix[i] = imgLine[imgIdx++]; + } + return gTrue; +} + +Guchar *ImageStream::getLine() { Gulong buf, bitMask; int bits; int c; int i; - if (imgIdx >= nVals) { - - // read one line of image pixels - if (nBits == 1) { - for (i = 0; i < nVals; i += 8) { - c = str->getChar(); - imgLine[i+0] = (Guchar)((c >> 7) & 1); - imgLine[i+1] = (Guchar)((c >> 6) & 1); - imgLine[i+2] = (Guchar)((c >> 5) & 1); - imgLine[i+3] = (Guchar)((c >> 4) & 1); - imgLine[i+4] = (Guchar)((c >> 3) & 1); - imgLine[i+5] = (Guchar)((c >> 2) & 1); - imgLine[i+6] = (Guchar)((c >> 1) & 1); - imgLine[i+7] = (Guchar)(c & 1); - } - } else if (nBits == 8) { - for (i = 0; i < nVals; ++i) { - imgLine[i] = str->getChar(); - } - } else { - bitMask = (1 << nBits) - 1; - buf = 0; - bits = 0; - for (i = 0; i < nVals; ++i) { - if (bits < nBits) { - buf = (buf << 8) | (str->getChar() & 0xff); - bits += 8; - } - imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); - bits -= nBits; + if (nBits == 1) { + for (i = 0; i < nVals; i += 8) { + c = str->getChar(); + imgLine[i+0] = (Guchar)((c >> 7) & 1); + imgLine[i+1] = (Guchar)((c >> 6) & 1); + imgLine[i+2] = (Guchar)((c >> 5) & 1); + imgLine[i+3] = (Guchar)((c >> 4) & 1); + imgLine[i+4] = (Guchar)((c >> 3) & 1); + imgLine[i+5] = (Guchar)((c >> 2) & 1); + imgLine[i+6] = (Guchar)((c >> 1) & 1); + imgLine[i+7] = (Guchar)(c & 1); + } + } else if (nBits == 8) { + for (i = 0; i < nVals; ++i) { + imgLine[i] = str->getChar(); + } + } else { + bitMask = (1 << nBits) - 1; + buf = 0; + bits = 0; + for (i = 0; i < nVals; ++i) { + if (bits < nBits) { + buf = (buf << 8) | (str->getChar() & 0xff); + bits += 8; } + imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); + bits -= nBits; } - - // reset to start of line - imgIdx = 0; } - - for (i = 0; i < nComps; ++i) - pix[i] = imgLine[imgIdx++]; - return gTrue; + return imgLine; } void ImageStream::skipLine() { @@ -448,7 +453,7 @@ GBool StreamPredictor::getNextLine() { int i, j, k; // get PNG optimum predictor number - if (predictor == 15) { + if (predictor >= 10) { if ((curPred = str->getRawChar()) == EOF) { return gFalse; } @@ -465,7 +470,7 @@ GBool StreamPredictor::getNextLine() { upLeftBuf[1] = upLeftBuf[0]; upLeftBuf[0] = predLine[i]; if ((c = str->getRawChar()) == EOF) { - break; + return gFalse; } switch (curPred) { case 11: // PNG sub @@ -504,7 +509,6 @@ GBool StreamPredictor::getNextLine() { } // apply TIFF (component) predictor - //~ this is completely untested if (predictor == 2) { if (nBits == 1) { inBuf = predLine[pixBytes - 1]; @@ -579,7 +583,10 @@ Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, } void FileStream::reset() { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + savePos = (Guint)ftello(f); + fseeko(f, start, SEEK_SET); +#elif HAVE_FSEEK64 savePos = (Guint)ftell64(f); fseek64(f, start, SEEK_SET); #else @@ -597,7 +604,9 @@ void FileStream::reset() { void FileStream::close() { if (saved) { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, savePos, SEEK_SET); +#elif HAVE_FSEEK64 fseek64(f, savePos, SEEK_SET); #else fseek(f, savePos, SEEK_SET); @@ -641,14 +650,19 @@ void FileStream::setPos(Guint pos, int dir) { Guint size; if (dir >= 0) { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, pos, SEEK_SET); +#elif HAVE_FSEEK64 fseek64(f, pos, SEEK_SET); #else fseek(f, pos, SEEK_SET); #endif bufPos = pos; } else { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, 0, SEEK_END); + size = (Guint)ftello(f); +#elif HAVE_FSEEK64 fseek64(f, 0, SEEK_END); size = (Guint)ftell64(f); #else @@ -661,7 +675,10 @@ void FileStream::setPos(Guint pos, int dir) { //~ work around a bug in cygwin's implementation of fseek rewind(f); #endif -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftello(f); +#elif HAVE_FSEEK64 fseek64(f, -(int)pos, SEEK_END); bufPos = (Guint)ftell64(f); #else @@ -682,13 +699,14 @@ void FileStream::moveStart(int delta) { // MemStream //------------------------------------------------------------------------ -MemStream::MemStream(char *bufA, Guint lengthA, Object *dictA): +MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA): BaseStream(dictA) { buf = bufA; - needFree = gFalse; + start = startA; length = lengthA; - bufEnd = buf + length; - bufPtr = buf; + bufEnd = buf + start + length; + bufPtr = buf + start; + needFree = gFalse; } MemStream::~MemStream() { @@ -697,20 +715,22 @@ MemStream::~MemStream() { } } -Stream *MemStream::makeSubStream(Guint start, GBool limited, +Stream *MemStream::makeSubStream(Guint startA, GBool limited, Guint lengthA, Object *dictA) { + MemStream *subStr; Guint newLength; - if (!limited || start + lengthA > length) { - newLength = length - start; + if (!limited || startA + lengthA > start + length) { + newLength = start + length - startA; } else { newLength = lengthA; } - return new MemStream(buf + start, newLength, dictA); + subStr = new MemStream(buf, startA, newLength, dictA); + return subStr; } void MemStream::reset() { - bufPtr = buf; + bufPtr = buf + start; #ifndef NO_DECRYPTION if (decrypt) { decrypt->reset(); @@ -722,24 +742,24 @@ void MemStream::close() { } void MemStream::setPos(Guint pos, int dir) { + Guint i; + if (dir >= 0) { - if (pos > length) { - bufPtr = bufEnd; - } else { - bufPtr = buf + pos; - } + i = pos; } else { - if (pos > length) { - bufPtr = buf; - } else { - bufPtr = bufEnd - pos; - } + i = start + length - pos; + } + if (i < start) { + i = start; + } else if (i > start + length) { + i = start + length; } + bufPtr = buf + i; } void MemStream::moveStart(int delta) { - buf += delta; - bufPtr = buf; + start += delta; + bufPtr = buf + start; } #ifndef NO_DECRYPTION @@ -750,12 +770,13 @@ void MemStream::doDecryption(Guchar *fileKey, int keyLength, this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen); if (decrypt) { - newBuf = (char *)gmalloc(bufEnd - buf); - for (p = buf, q = newBuf; p < bufEnd; ++p, ++q) { + newBuf = (char *)gmalloc(length); + for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) { *q = (char)decrypt->decryptByte((Guchar)*p); } - bufEnd = newBuf + (bufEnd - buf); - bufPtr = newBuf + (bufPtr - buf); + bufEnd = newBuf + length; + bufPtr = newBuf + (bufPtr - (buf + start)); + start = 0; buf = newBuf; needFree = gTrue; } @@ -766,20 +787,38 @@ void MemStream::doDecryption(Guchar *fileKey, int keyLength, // EmbedStream //------------------------------------------------------------------------ -EmbedStream::EmbedStream(Stream *strA, Object *dictA): +EmbedStream::EmbedStream(Stream *strA, Object *dictA, + GBool limitedA, Guint lengthA): BaseStream(dictA) { str = strA; + limited = limitedA; + length = lengthA; } EmbedStream::~EmbedStream() { } -Stream *EmbedStream::makeSubStream(Guint start, GBool limited, - Guint length, Object *dictA) { +Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA) { error(-1, "Internal: called makeSubStream() on EmbedStream"); return NULL; } +int EmbedStream::getChar() { + if (limited && !length) { + return EOF; + } + --length; + return str->getChar(); +} + +int EmbedStream::lookChar() { + if (limited && !length) { + return EOF; + } + return str->lookChar(); +} + void EmbedStream::setPos(Guint pos, int dir) { error(-1, "Internal: called setPos() on EmbedStream"); } @@ -866,10 +905,13 @@ int ASCIIHexStream::lookChar() { return buf; } -GString *ASCIIHexStream::getPSFilter(char *indent) { +GString *ASCIIHexStream::getPSFilter(int psLevel, char *indent) { GString *s; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/ASCIIHexDecode filter\n"); @@ -944,10 +986,13 @@ int ASCII85Stream::lookChar() { return b[index]; } -GString *ASCII85Stream::getPSFilter(char *indent) { +GString *ASCII85Stream::getPSFilter(int psLevel, char *indent) { GString *s; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/ASCII85Decode filter\n"); @@ -971,21 +1016,12 @@ LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors, pred = NULL; } early = earlyA; - zPipe = NULL; - bufPtr = bufEnd = buf; + eof = gFalse; + inputBits = 0; + clearTable(); } LZWStream::~LZWStream() { - if (zPipe) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } if (pred) { delete pred; } @@ -996,275 +1032,149 @@ int LZWStream::getChar() { if (pred) { return pred->getChar(); } - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; } int LZWStream::lookChar() { if (pred) { return pred->lookChar(); } - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex]; } int LZWStream::getRawChar() { - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; } void LZWStream::reset() { - FILE *f; - GString *zCmd; - - //----- close old LZW stream - if (zPipe) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } + str->reset(); + eof = gFalse; + inputBits = 0; + clearTable(); +} - //----- tell Delorie runtime to spawn a new instance of COMMAND.COM - // to run gzip -#if __DJGPP__ - if (!setDJSYSFLAGS) { - setenv("DJSYSFLAGS", "0x0002", 0); - setDJSYSFLAGS = gTrue; - } -#endif +GBool LZWStream::processNextCode() { + int code; + int nextLength; + int i, j; - //----- create the .Z file - if (!openTempFile(&zName, &f, "wb", ".Z")) { - error(getPos(), "Couldn't create temporary file for LZW stream"); - return; + // check for EOF + if (eof) { + return gFalse; } - dumpFile(f); - fclose(f); - //----- execute uncompress / gzip -#ifdef WIN32 - zCmd = new GString("c:\\swftools\\gzip.exe"); -#else - zCmd = new GString(uncompressCmd); -#endif - zCmd->append(' '); - zCmd->append(zName); -#if defined(MACOS) - long magicCookie; - // first we open the engine up - OSErr err = OpenSITEngine(kUseExternalEngine, &magicCookie); - // if we found it - let's use it! - if (!err && magicCookie) { - // make sure we have the correct version of the Engine - if (GetSITEngineVersion(magicCookie) >= kFirstSupportedEngine) { - FSSpec myFSS; - Str255 pName; - strcpy((char *)pName, zName->getCString()); - c2pstr((char *)pName); - FSMakeFSSpec(0, 0, pName, &myFSS); - short ftype = DetermineFileType(magicCookie, &myFSS); - OSErr expandErr = ExpandFSSpec(magicCookie, ftype, &myFSS, - NULL, NULL, kCreateFolderNever, - kDeleteOriginal, kTextConvertSmart); - } - } -#elif defined(HAVE_POPEN) - if (!(zPipe = popen(zCmd->getCString(), POPEN_READ_MODE))) { - error(getPos(), "Couldn't popen '%s'", zCmd->getCString()); - unlink(zName->getCString()); - delete zName; - return; - } -#else // HAVE_POPEN - if (!executeCommand(zCmd->getCString())) { - error(getPos(), "Couldn't execute '%s'", zCmd->getCString()); - unlink(zName->getCString()); - delete zName; - return; + // check for eod and clear-table codes + start: + code = getCode(); + if (code == EOF || code == 257) { + eof = gTrue; + return gFalse; } - zName->del(zName->getLength() - 2, 2); - if (!(zPipe = fopen(zName->getCString(), "rb"))) { - error(getPos(), "Couldn't open uncompress file '%s'", zName->getCString()); - unlink(zName->getCString()); - delete zName; - return; + if (code == 256) { + clearTable(); + goto start; + } + if (nextCode >= 4097) { + error(getPos(), "Bad LZW stream - expected clear-table code"); + clearTable(); + } + + // process the next code + nextLength = seqLength + 1; + if (code < 256) { + seqBuf[0] = code; + seqLength = 1; + } else if (code < nextCode) { + seqLength = table[code].length; + for (i = seqLength - 1, j = code; i > 0; --i) { + seqBuf[i] = table[j].tail; + j = table[j].head; + } + seqBuf[0] = j; + } else if (code == nextCode) { + seqBuf[seqLength] = newChar; + ++seqLength; + } else { + error(getPos(), "Bad LZW stream - unexpected code"); + eof = gTrue; + return gFalse; } -#endif // HAVE_POPEN - - //----- clean up - delete zCmd; + newChar = seqBuf[0]; + if (first) { + first = gFalse; + } else { + table[nextCode].length = nextLength; + table[nextCode].head = prevCode; + table[nextCode].tail = newChar; + ++nextCode; + if (nextCode + early == 512) + nextBits = 10; + else if (nextCode + early == 1024) + nextBits = 11; + else if (nextCode + early == 2048) + nextBits = 12; + } + prevCode = code; + + // reset buffer + seqIndex = 0; - //----- initialize buffer - bufPtr = bufEnd = buf; + return gTrue; } -void LZWStream::dumpFile(FILE *f) { - int outCodeBits; // size of output code - int outBits; // max output code - int outBuf[8]; // output buffer - int outData; // temporary output buffer - int inCode, outCode; // input and output codes - int nextCode; // next code index - GBool eof; // set when EOF is reached - GBool clear; // set if table needs to be cleared - GBool first; // indicates first code word after clear - int i, j; - - str->reset(); - - // magic number - fputc(0x1f, f); - fputc(0x9d, f); - - // max code length, block mode flag - fputc(0x8c, f); - - // init input side - inCodeBits = 9; - inputBuf = 0; - inputBits = 0; - eof = gFalse; - - // init output side - outCodeBits = 9; - - // clear table - first = gTrue; +void LZWStream::clearTable() { nextCode = 258; - - clear = gFalse; - do { - for (i = 0; i < 8; ++i) { - // check for table overflow - if (nextCode + early > 0x1001) { - inCode = 256; - - // read input code - } else { - do { - inCode = getCode(); - if (inCode == EOF) { - eof = gTrue; - inCode = 0; - } - } while (first && inCode == 256); - } - - // compute output code - if (inCode < 256) { - outCode = inCode; - } else if (inCode == 256) { - outCode = 256; - clear = gTrue; - } else if (inCode == 257) { - outCode = 0; - eof = gTrue; - } else { - outCode = inCode - 1; - } - outBuf[i] = outCode; - - // next code index - if (first) - first = gFalse; - else - ++nextCode; - - // check input code size - if (nextCode + early == 0x200) - inCodeBits = 10; - else if (nextCode + early == 0x400) { - inCodeBits = 11; - } else if (nextCode + early == 0x800) { - inCodeBits = 12; - } - - // check for eof/clear - if (eof) - break; - if (clear) { - i = 8; - break; - } - } - - // write output block - outData = 0; - outBits = 0; - j = 0; - while (j < i || outBits > 0) { - if (outBits < 8 && j < i) { - outData = outData | (outBuf[j++] << outBits); - outBits += outCodeBits; - } - fputc(outData & 0xff, f); - outData >>= 8; - outBits -= 8; - } - - // check output code size - if (nextCode - 1 == 512 || - nextCode - 1 == 1024 || - nextCode - 1 == 2048 || - nextCode - 1 == 4096) { - outCodeBits = inCodeBits; - } - - // clear table if necessary - if (clear) { - inCodeBits = 9; - outCodeBits = 9; - first = gTrue; - nextCode = 258; - clear = gFalse; - } - } while (!eof); + nextBits = 9; + seqIndex = seqLength = 0; + first = gTrue; } int LZWStream::getCode() { int c; int code; - while (inputBits < inCodeBits) { + while (inputBits < nextBits) { if ((c = str->getChar()) == EOF) return EOF; inputBuf = (inputBuf << 8) | (c & 0xff); inputBits += 8; } - code = (inputBuf >> (inputBits - inCodeBits)) & ((1 << inCodeBits) - 1); - inputBits -= inCodeBits; + code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1); + inputBits -= nextBits; return code; } -GBool LZWStream::fillBuf() { - int n; - - if (!zPipe) - return gFalse; - if ((n = fread(buf, 1, 256, zPipe)) < 256) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } - bufPtr = buf; - bufEnd = buf + n; - return n > 0; -} - -GString *LZWStream::getPSFilter(char *indent) { +GString *LZWStream::getPSFilter(int psLevel, char *indent) { GString *s; - if (pred) { + if (psLevel < 2 || pred) { return NULL; } - if (!(s = str->getPSFilter(indent))) { + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/LZWDecode filter\n"); @@ -1295,10 +1205,13 @@ void RunLengthStream::reset() { eof = gFalse; } -GString *RunLengthStream::getPSFilter(char *indent) { +GString *RunLengthStream::getPSFilter(int psLevel, char *indent) { GString *s; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/RunLengthDecode filter\n"); @@ -1371,7 +1284,7 @@ CCITTFaxStream::~CCITTFaxStream() { } void CCITTFaxStream::reset() { - int n; + short code1; str->reset(); eof = gFalse; @@ -1383,16 +1296,13 @@ void CCITTFaxStream::reset() { a0 = 1; buf = EOF; - // get initial end-of-line marker and 2D encoding tag - if (endOfBlock) { - if (lookBits(12) == 0x001) { - eatBits(12); - } - } else { - for (n = 0; n < 11 && lookBits(n) == 0; ++n) ; - if (n == 11 && lookBits(12) == 0x001) { - eatBits(12); - } + // skip any initial zero bits and end-of-line marker, and get the 2D + // encoding tag + while ((code1 = lookBits(12)) == 0) { + eatBits(1); + } + if (code1 == 0x001) { + eatBits(12); } if (encoding > 0) { nextLine2D = !lookBits(1); @@ -1403,10 +1313,7 @@ void CCITTFaxStream::reset() { int CCITTFaxStream::lookChar() { short code1, code2, code3; int a0New; -#if 0 - GBool err; -#endif - GBool gotEOL; + GBool err, gotEOL; int ret; int bits, i; @@ -1416,9 +1323,7 @@ int CCITTFaxStream::lookChar() { } // read the next row -#if 0 err = gFalse; -#endif if (codingLine[a0] >= columns) { // 2-D encoding @@ -1455,12 +1360,14 @@ int CCITTFaxStream::lookChar() { code2 += code3 = getWhiteCode(); } while (code3 >= 64); } - codingLine[a0 + 1] = a0New + code1; - ++a0; - a0New = codingLine[a0 + 1] = codingLine[a0] + code2; - ++a0; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; + if (code1 > 0 || code2 > 0) { + codingLine[a0 + 1] = a0New + code1; + ++a0; + a0New = codingLine[a0 + 1] = codingLine[a0] + code2; + ++a0; + while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + b1 += 2; + } break; case twoDimVert0: a0New = codingLine[++a0] = refLine[b1]; @@ -1518,13 +1425,8 @@ int CCITTFaxStream::lookChar() { return EOF; default: error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); -#if 0 err = gTrue; break; -#else - eof = gTrue; - return EOF; -#endif } } while (codingLine[a0] < columns); @@ -1553,9 +1455,12 @@ int CCITTFaxStream::lookChar() { if (codingLine[a0] != columns) { error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]); -#if 0 + // force the row to be the correct length + while (codingLine[a0] > columns) { + --a0; + } + codingLine[++a0] = columns; err = gTrue; -#endif } // byte-align the row @@ -1611,30 +1516,25 @@ int CCITTFaxStream::lookChar() { } eof = gTrue; } - } -#if 0 - // This looks for an end-of-line marker after an error, however - // some (most?) CCITT streams in PDF files don't use end-of-line - // markers, and the just-plow-on technique works better in those - // cases. - else if (err) { + // look for an end-of-line marker after an error -- we only do + // this if we know the stream contains end-of-line markers because + // the "just plow on" technique tends to work better otherwise + } else if (err && endOfLine) { do { if (code1 == EOF) { eof = gTrue; return EOF; } eatBits(1); - code1 = look13Bits(); + code1 = lookBits(13); } while ((code1 >> 1) != 0x001); eatBits(12); - codingLine[++a0] = columns; if (encoding > 0) { eatBits(1); nextLine2D = !(code1 & 1); } } -#endif a0 = 0; outputBits = codingLine[1] - codingLine[0]; @@ -1845,11 +1745,14 @@ short CCITTFaxStream::lookBits(int n) { return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n)); } -GString *CCITTFaxStream::getPSFilter(char *indent) { +GString *CCITTFaxStream::getPSFilter(int psLevel, char *indent) { GString *s; char s1[50]; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("<< "); @@ -1888,7 +1791,6 @@ GBool CCITTFaxStream::isBinary(GBool last) { //------------------------------------------------------------------------ // IDCT constants (20.12 fixed point format) -#ifndef FP_IDCT #define dctCos1 4017 // cos(pi/16) #define dctSin1 799 // sin(pi/16) #define dctCos3 3406 // cos(3*pi/16) @@ -1897,19 +1799,6 @@ GBool CCITTFaxStream::isBinary(GBool last) { #define dctSin6 3784 // sin(6*pi/16) #define dctSqrt2 5793 // sqrt(2) #define dctSqrt1d2 2896 // sqrt(2) / 2 -#endif - -// IDCT constants -#ifdef FP_IDCT -#define dctCos1 0.98078528 // cos(pi/16) -#define dctSin1 0.19509032 // sin(pi/16) -#define dctCos3 0.83146961 // cos(3*pi/16) -#define dctSin3 0.55557023 // sin(3*pi/16) -#define dctCos6 0.38268343 // cos(6*pi/16) -#define dctSin6 0.92387953 // sin(6*pi/16) -#define dctSqrt2 1.41421356 // sqrt(2) -#define dctSqrt1d2 0.70710678 // sqrt(2) / 2 -#endif // color conversion parameters (16.16 fixed point format) #define dctCrToR 91881 // 1.4020 @@ -1945,14 +1834,18 @@ DCTStream::DCTStream(Stream *strA): FilterStream(strA) { int i, j; + progressive = interleaved = gFalse; width = height = 0; mcuWidth = mcuHeight = 0; numComps = 0; comp = 0; x = y = dy = 0; - for (i = 0; i < 4; ++i) - for (j = 0; j < 32; ++j) + for (i = 0; i < 4; ++i) { + for (j = 0; j < 32; ++j) { rowBuf[i][j] = NULL; + } + frameBuf[i] = NULL; + } if (!dctClipInit) { for (i = -256; i < 0; ++i) @@ -1969,53 +1862,178 @@ DCTStream::~DCTStream() { int i, j; delete str; - for (i = 0; i < numComps; ++i) - for (j = 0; j < mcuHeight; ++j) - gfree(rowBuf[i][j]); + if (progressive || !interleaved) { + for (i = 0; i < numComps; ++i) { + gfree(frameBuf[i]); + } + } else { + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + gfree(rowBuf[i][j]); + } + } + } } void DCTStream::reset() { + int minHSample, minVSample; + int i, j; + str->reset(); + + progressive = interleaved = gFalse; + width = height = 0; + numComps = 0; + numQuantTables = 0; + numDCHuffTables = 0; + numACHuffTables = 0; + colorXform = 0; + gotJFIFMarker = gFalse; + gotAdobeMarker = gFalse; + restartInterval = 0; + if (!readHeader()) { y = height; return; } - restartMarker = 0xd0; - restart(); -} -int DCTStream::getChar() { - int c; - - c = lookChar(); - if (c == EOF) - return EOF; - if (++comp == numComps) { - comp = 0; - if (++x == width) { - x = 0; - ++y; - ++dy; - } + // compute MCU size + mcuWidth = minHSample = compInfo[0].hSample; + mcuHeight = minVSample = compInfo[0].vSample; + for (i = 1; i < numComps; ++i) { + if (compInfo[i].hSample < minHSample) + minHSample = compInfo[i].hSample; + if (compInfo[i].vSample < minVSample) + minVSample = compInfo[i].vSample; + if (compInfo[i].hSample > mcuWidth) + mcuWidth = compInfo[i].hSample; + if (compInfo[i].vSample > mcuHeight) + mcuHeight = compInfo[i].vSample; } - if (y == height) - readTrailer(); - return c; -} + for (i = 0; i < numComps; ++i) { + compInfo[i].hSample /= minHSample; + compInfo[i].vSample /= minVSample; + } + mcuWidth = (mcuWidth / minHSample) * 8; + mcuHeight = (mcuHeight / minVSample) * 8; -int DCTStream::lookChar() { - if (y >= height) - return EOF; - if (dy >= mcuHeight) { - if (!readMCURow()) { - y = height; - return EOF; + // figure out color transform + if (!gotAdobeMarker && numComps == 3) { + if (gotJFIFMarker) { + colorXform = 1; + } else if (compInfo[0].id == 82 && compInfo[1].id == 71 && + compInfo[2].id == 66) { // ASCII "RGB" + colorXform = 0; + } else { + colorXform = 1; + } + } + + if (progressive || !interleaved) { + + // allocate a buffer for the whole image + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; + for (i = 0; i < numComps; ++i) { + frameBuf[i] = (int *)gmalloc(bufWidth * bufHeight * sizeof(int)); + memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); + } + + // read the image data + do { + restartMarker = 0xd0; + restart(); + readScan(); + } while (readHeader()); + + // decode + decodeImage(); + + // initialize counters + comp = 0; + x = 0; + y = 0; + + } else { + + // allocate a buffer for one row of MCUs + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); + } } + + // initialize counters comp = 0; x = 0; - dy = 0; + y = 0; + dy = mcuHeight; + + restartMarker = 0xd0; + restart(); + } +} + +int DCTStream::getChar() { + int c; + + if (y >= height) { + return EOF; + } + if (progressive || !interleaved) { + c = frameBuf[comp][y * bufWidth + x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + } + } + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; + x = 0; + dy = 0; + } + c = rowBuf[comp][dy][x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + ++dy; + if (y == height) { + readTrailer(); + } + } + } + } + return c; +} + +int DCTStream::lookChar() { + if (y >= height) { + return EOF; + } + if (progressive || !interleaved) { + return frameBuf[comp][y * bufWidth + x]; + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; + x = 0; + dy = 0; + } + return rowBuf[comp][dy][x]; } - return rowBuf[comp][dy][x]; } void DCTStream::restart() { @@ -2023,12 +2041,16 @@ void DCTStream::restart() { inputBits = 0; restartCtr = restartInterval; - for (i = 0; i < numComps; ++i) + for (i = 0; i < numComps; ++i) { compInfo[i].prevDC = 0; + } + eobRun = 0; } +// Read one row of MCUs from a sequential JPEG stream. GBool DCTStream::readMCURow() { - Guchar data[64]; + int data1[64]; + Guchar data2[64]; Guchar *p1, *p2; int pY, pCb, pCr, pR, pG, pB; int h, v, horiz, vert, hSub, vSub; @@ -2059,36 +2081,38 @@ GBool DCTStream::readMCURow() { vSub = vert / 8; for (y2 = 0; y2 < mcuHeight; y2 += vert) { for (x2 = 0; x2 < mcuWidth; x2 += horiz) { - if (!readDataUnit(&dcHuffTables[compInfo[cc].dcHuffTable], - &acHuffTables[compInfo[cc].acHuffTable], - quantTables[compInfo[cc].quantTable], + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], &compInfo[cc].prevDC, - data)) + data1)) { return gFalse; + } + transformDataUnit(quantTables[compInfo[cc].quantTable], + data1, data2); if (hSub == 1 && vSub == 1) { for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { p1 = &rowBuf[cc][y2+y3][x1+x2]; - p1[0] = data[i]; - p1[1] = data[i+1]; - p1[2] = data[i+2]; - p1[3] = data[i+3]; - p1[4] = data[i+4]; - p1[5] = data[i+5]; - p1[6] = data[i+6]; - p1[7] = data[i+7]; + p1[0] = data2[i]; + p1[1] = data2[i+1]; + p1[2] = data2[i+2]; + p1[3] = data2[i+3]; + p1[4] = data2[i+4]; + p1[5] = data2[i+5]; + p1[6] = data2[i+6]; + p1[7] = data2[i+7]; } } else if (hSub == 2 && vSub == 2) { for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { p1 = &rowBuf[cc][y2+y3][x1+x2]; p2 = &rowBuf[cc][y2+y3+1][x1+x2]; - p1[0] = p1[1] = p2[0] = p2[1] = data[i]; - p1[2] = p1[3] = p2[2] = p2[3] = data[i+1]; - p1[4] = p1[5] = p2[4] = p2[5] = data[i+2]; - p1[6] = p1[7] = p2[6] = p2[7] = data[i+3]; - p1[8] = p1[9] = p2[8] = p2[9] = data[i+4]; - p1[10] = p1[11] = p2[10] = p2[11] = data[i+5]; - p1[12] = p1[13] = p2[12] = p2[13] = data[i+6]; - p1[14] = p1[15] = p2[14] = p2[15] = data[i+7]; + p1[0] = p1[1] = p2[0] = p2[1] = data2[i]; + p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1]; + p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2]; + p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3]; + p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4]; + p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5]; + p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6]; + p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7]; } } else { i = 0; @@ -2096,7 +2120,7 @@ GBool DCTStream::readMCURow() { for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { for (y5 = 0; y5 < vSub; ++y5) for (x5 = 0; x5 < hSub; ++x5) - rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data[i]; + rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i]; ++i; } } @@ -2144,71 +2168,469 @@ GBool DCTStream::readMCURow() { return gTrue; } -// This IDCT algorithm is taken from: -// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, -// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", -// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, -// 988-991. -// The stage numbers mentioned in the comments refer to Figure 1 in this -// paper. -#ifndef FP_IDCT +// Read one scan from a progressive or non-interleaved JPEG stream. +void DCTStream::readScan() { + int data[64]; + int x1, y1, dx1, dy1, x2, y2, y3, cc, i; + int h, v, horiz, vert, vSub; + int *p1; + int c; + + if (scanInfo.numComps == 1) { + for (cc = 0; cc < numComps; ++cc) { + if (scanInfo.comp[cc]) { + break; + } + } + dx1 = mcuWidth / compInfo[cc].hSample; + dy1 = mcuHeight / compInfo[cc].vSample; + } else { + dx1 = mcuWidth; + dy1 = mcuHeight; + } + + for (y1 = 0; y1 < height; y1 += dy1) { + for (x1 = 0; x1 < width; x1 += dx1) { + + // deal with restart marker + if (restartInterval > 0 && restartCtr == 0) { + c = readMarker(); + if (c != restartMarker) { + error(getPos(), "Bad DCT data: incorrect restart marker"); + return; + } + if (++restartMarker == 0xd8) { + restartMarker = 0xd0; + } + restart(); + } + + // read one MCU + for (cc = 0; cc < numComps; ++cc) { + if (!scanInfo.comp[cc]) { + continue; + } + + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + vSub = vert / 8; + for (y2 = 0; y2 < dy1; y2 += vert) { + for (x2 = 0; x2 < dx1; x2 += horiz) { + + // pull out the current values + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + data[i] = p1[0]; + data[i+1] = p1[1]; + data[i+2] = p1[2]; + data[i+3] = p1[3]; + data[i+4] = p1[4]; + data[i+5] = p1[5]; + data[i+6] = p1[6]; + data[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // read one data unit + if (progressive) { + if (!readProgressiveDataUnit( + &dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } else { + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } + + // add the data unit into frameBuf + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = data[i]; + p1[1] = data[i+1]; + p1[2] = data[i+2]; + p1[3] = data[i+3]; + p1[4] = data[i+4]; + p1[5] = data[i+5]; + p1[6] = data[i+6]; + p1[7] = data[i+7]; + p1 += bufWidth * vSub; + } + } + } + } + --restartCtr; + } + } +} + +// Read one data unit from a sequential JPEG stream. GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, - Guchar quantTable[64], int *prevDC, - Guchar data[64]) { - int tmp1[64]; - int v0, v1, v2, v3, v4, v5, v6, v7, t; + int *prevDC, int data[64]) { int run, size, amp; int c; int i, j; - // Huffman decode and dequantize - size = readHuffSym(dcHuffTable); - if (size == 9999) + if ((size = readHuffSym(dcHuffTable)) == 9999) { return gFalse; + } if (size > 0) { - amp = readAmp(size); - if (amp == 9999) + if ((amp = readAmp(size)) == 9999) { return gFalse; + } } else { amp = 0; } - tmp1[0] = (*prevDC += amp) * quantTable[0]; - for (i = 1; i < 64; ++i) - tmp1[i] = 0; + data[0] = *prevDC += amp; + for (i = 1; i < 64; ++i) { + data[i] = 0; + } i = 1; while (i < 64) { run = 0; - while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) + while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) { run += 0x10; - if (c == 9999) + } + if (c == 9999) { return gFalse; + } if (c == 0x00) { break; } else { run += (c >> 4) & 0x0f; size = c & 0x0f; amp = readAmp(size); - if (amp == 9999) + if (amp == 9999) { return gFalse; + } i += run; + if (i < 64) { + j = dctZigZag[i++]; + data[j] = amp; + } + } + } + return gTrue; +} + +// Read one data unit from a sequential JPEG stream. +GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]) { + int run, size, amp, bit, c; + int i, j, k; + + // get the DC coefficient + i = scanInfo.firstCoeff; + if (i == 0) { + if (scanInfo.ah == 0) { + if ((size = readHuffSym(dcHuffTable)) == 9999) { + return gFalse; + } + if (size > 0) { + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + } else { + amp = 0; + } + data[0] += (*prevDC += amp) << scanInfo.al; + } else { + if ((bit = readBit()) == 9999) { + return gFalse; + } + data[0] += bit << scanInfo.al; + } + ++i; + } + if (scanInfo.lastCoeff == 0) { + return gTrue; + } + + // check for an EOB run + if (eobRun > 0) { + while (i <= scanInfo.lastCoeff) { j = dctZigZag[i++]; - tmp1[j] = amp * quantTable[j]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + --eobRun; + return gTrue; + } + + // read the AC coefficients + while (i <= scanInfo.lastCoeff) { + if ((c = readHuffSym(acHuffTable)) == 9999) { + return gFalse; + } + + // ZRL + if (c == 0xf0) { + k = 0; + while (k < 16) { + j = dctZigZag[i++]; + if (data[j] == 0) { + ++k; + } else { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + + // EOB run + } else if ((c & 0x0f) == 0x00) { + j = c >> 4; + eobRun = 0; + for (k = 0; k < j; ++k) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + eobRun = (eobRun << 1) | bit; + } + eobRun += 1 << j; + while (i <= scanInfo.lastCoeff) { + j = dctZigZag[i++]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + --eobRun; + break; + + // zero run and one AC coefficient + } else { + run = (c >> 4) & 0x0f; + size = c & 0x0f; + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + k = 0; + do { + j = dctZigZag[i++]; + while (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + j = dctZigZag[i++]; + } + ++k; + } while (k <= run); + data[j] = amp << scanInfo.al; + } + } + + return gTrue; +} + +// Decode a progressive JPEG image. +void DCTStream::decodeImage() { + int dataIn[64]; + Guchar dataOut[64]; + Guchar *quantTable; + int pY, pCb, pCr, pR, pG, pB; + int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; + int h, v, horiz, vert, hSub, vSub; + int *p0, *p1, *p2; + + for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) { + for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { + for (cc = 0; cc < numComps; ++cc) { + quantTable = quantTables[compInfo[cc].quantTable]; + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + hSub = horiz / 8; + vSub = vert / 8; + for (y2 = 0; y2 < mcuHeight; y2 += vert) { + for (x2 = 0; x2 < mcuWidth; x2 += horiz) { + + // pull out the coded data unit + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + dataIn[i] = p1[0]; + dataIn[i+1] = p1[1]; + dataIn[i+2] = p1[2]; + dataIn[i+3] = p1[3]; + dataIn[i+4] = p1[4]; + dataIn[i+5] = p1[5]; + dataIn[i+6] = p1[6]; + dataIn[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // transform + transformDataUnit(quantTable, dataIn, dataOut); + + // store back into frameBuf, doing replication for + // subsampled components + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + if (hSub == 1 && vSub == 1) { + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = dataOut[i] & 0xff; + p1[1] = dataOut[i+1] & 0xff; + p1[2] = dataOut[i+2] & 0xff; + p1[3] = dataOut[i+3] & 0xff; + p1[4] = dataOut[i+4] & 0xff; + p1[5] = dataOut[i+5] & 0xff; + p1[6] = dataOut[i+6] & 0xff; + p1[7] = dataOut[i+7] & 0xff; + p1 += bufWidth; + } + } else if (hSub == 2 && vSub == 2) { + p2 = p1 + bufWidth; + for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { + p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff; + p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff; + p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff; + p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff; + p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff; + p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff; + p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff; + p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff; + p1 += bufWidth * 2; + p2 += bufWidth * 2; + } + } else { + i = 0; + for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { + for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { + p2 = p1 + x4; + for (y5 = 0; y5 < vSub; ++y5) { + for (x5 = 0; x5 < hSub; ++x5) { + p2[x5] = dataOut[i] & 0xff; + } + p2 += bufWidth; + } + ++i; + } + p1 += bufWidth * vSub; + } + } + } + } + } + + // color space conversion + if (colorXform) { + // convert YCbCr to RGB + if (numComps == 3) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = dctClip[dctClipOffset + pB]; + } + } + // convert YCbCrK to CMYK (K is passed through unchanged) + } else if (numComps == 4) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = 255 - dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = 255 - dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = 255 - dctClip[dctClipOffset + pB]; + } + } + } + } } } +} + +// Transform one data unit -- this performs the dequantization and +// IDCT steps. This IDCT algorithm is taken from: +// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, +// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", +// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, +// 988-991. +// The stage numbers mentioned in the comments refer to Figure 1 in this +// paper. +void DCTStream::transformDataUnit(Guchar *quantTable, + int dataIn[64], Guchar dataOut[64]) { + int v0, v1, v2, v3, v4, v5, v6, v7, t; + int *p; + int i; + + // dequant + for (i = 0; i < 64; ++i) { + dataIn[i] *= quantTable[i]; + } // inverse DCT on rows for (i = 0; i < 64; i += 8) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1] == 0 && p[2] == 0 && p[3] == 0 && + p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) { + t = (dctSqrt2 * p[0] + 512) >> 10; + p[0] = t; + p[1] = t; + p[2] = t; + p[3] = t; + p[4] = t; + p[5] = t; + p[6] = t; + p[7] = t; + continue; + } // stage 4 - v0 = (dctSqrt2 * tmp1[i+0] + 128) >> 8; - v1 = (dctSqrt2 * tmp1[i+4] + 128) >> 8; - v2 = tmp1[i+2]; - v3 = tmp1[i+6]; - v4 = (dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]) + 128) >> 8; - v7 = (dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]) + 128) >> 8; - v5 = tmp1[i+3] << 4; - v6 = tmp1[i+5] << 4; + v0 = (dctSqrt2 * p[0] + 128) >> 8; + v1 = (dctSqrt2 * p[4] + 128) >> 8; + v2 = p[2]; + v3 = p[6]; + v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8; + v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8; + v5 = p[3] << 4; + v6 = p[5] << 4; // stage 3 t = (v0 - v1+ 1) >> 1; @@ -2239,28 +2661,44 @@ GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, v6 = t; // stage 1 - tmp1[i+0] = v0 + v7; - tmp1[i+7] = v0 - v7; - tmp1[i+1] = v1 + v6; - tmp1[i+6] = v1 - v6; - tmp1[i+2] = v2 + v5; - tmp1[i+5] = v2 - v5; - tmp1[i+3] = v3 + v4; - tmp1[i+4] = v3 - v4; + p[0] = v0 + v7; + p[7] = v0 - v7; + p[1] = v1 + v6; + p[6] = v1 - v6; + p[2] = v2 + v5; + p[5] = v2 - v5; + p[3] = v3 + v4; + p[4] = v3 - v4; } // inverse DCT on columns for (i = 0; i < 8; ++i) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 && + p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) { + t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14; + p[0*8] = t; + p[1*8] = t; + p[2*8] = t; + p[3*8] = t; + p[4*8] = t; + p[5*8] = t; + p[6*8] = t; + p[7*8] = t; + continue; + } // stage 4 - v0 = (dctSqrt2 * tmp1[0*8+i] + 2048) >> 12; - v1 = (dctSqrt2 * tmp1[4*8+i] + 2048) >> 12; - v2 = tmp1[2*8+i]; - v3 = tmp1[6*8+i]; - v4 = (dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]) + 2048) >> 12; - v7 = (dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]) + 2048) >> 12; - v5 = tmp1[3*8+i]; - v6 = tmp1[5*8+i]; + v0 = (dctSqrt2 * p[0*8] + 2048) >> 12; + v1 = (dctSqrt2 * p[4*8] + 2048) >> 12; + v2 = p[2*8]; + v3 = p[6*8]; + v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12; + v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12; + v5 = p[3*8]; + v6 = p[5*8]; // stage 3 t = (v0 - v1 + 1) >> 1; @@ -2291,181 +2729,21 @@ GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, v6 = t; // stage 1 - tmp1[0*8+i] = v0 + v7; - tmp1[7*8+i] = v0 - v7; - tmp1[1*8+i] = v1 + v6; - tmp1[6*8+i] = v1 - v6; - tmp1[2*8+i] = v2 + v5; - tmp1[5*8+i] = v2 - v5; - tmp1[3*8+i] = v3 + v4; - tmp1[4*8+i] = v3 - v4; + p[0*8] = v0 + v7; + p[7*8] = v0 - v7; + p[1*8] = v1 + v6; + p[6*8] = v1 - v6; + p[2*8] = v2 + v5; + p[5*8] = v2 - v5; + p[3*8] = v3 + v4; + p[4*8] = v3 - v4; } // convert to 8-bit integers - for (i = 0; i < 64; ++i) - data[i] = dctClip[dctClipOffset + 128 + ((tmp1[i] + 8) >> 4)]; - - return gTrue; -} -#endif - -#ifdef FP_IDCT -GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - Guchar quantTable[64], int *prevDC, - Guchar data[64]) { - double tmp1[64]; - double v0, v1, v2, v3, v4, v5, v6, v7, t; - int run, size, amp; - int c; - int i, j; - - // Huffman decode and dequantize - size = readHuffSym(dcHuffTable); - if (size == 9999) - return gFalse; - if (size > 0) { - amp = readAmp(size); - if (amp == 9999) - return gFalse; - } else { - amp = 0; + for (i = 0; i < 64; ++i) { + dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)]; } - tmp1[0] = (*prevDC += amp) * quantTable[0]; - for (i = 1; i < 64; ++i) - tmp1[i] = 0; - i = 1; - while (i < 64) { - run = 0; - while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) - run += 0x10; - if (c == 9999) - return gFalse; - if (c == 0x00) { - break; - } else { - run += (c >> 4) & 0x0f; - size = c & 0x0f; - amp = readAmp(size); - if (amp == 9999) - return gFalse; - i += run; - j = dctZigZag[i++]; - tmp1[j] = amp * quantTable[j]; - } - } - - // inverse DCT on rows - for (i = 0; i < 64; i += 8) { - - // stage 4 - v0 = dctSqrt2 * tmp1[i+0]; - v1 = dctSqrt2 * tmp1[i+4]; - v2 = tmp1[i+2]; - v3 = tmp1[i+6]; - v4 = dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]); - v7 = dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]); - v5 = tmp1[i+3]; - v6 = tmp1[i+5]; - - // stage 3 - t = 0.5 * (v0 - v1); - v0 = 0.5 * (v0 + v1); - v1 = t; - t = v2 * dctSin6 + v3 * dctCos6; - v2 = v2 * dctCos6 - v3 * dctSin6; - v3 = t; - t = 0.5 * (v4 - v6); - v4 = 0.5 * (v4 + v6); - v6 = t; - t = 0.5 * (v7 + v5); - v5 = 0.5 * (v7 - v5); - v7 = t; - - // stage 2 - t = 0.5 * (v0 - v3); - v0 = 0.5 * (v0 + v3); - v3 = t; - t = 0.5 * (v1 - v2); - v1 = 0.5 * (v1 + v2); - v2 = t; - t = v4 * dctSin3 + v7 * dctCos3; - v4 = v4 * dctCos3 - v7 * dctSin3; - v7 = t; - t = v5 * dctSin1 + v6 * dctCos1; - v5 = v5 * dctCos1 - v6 * dctSin1; - v6 = t; - - // stage 1 - tmp1[i+0] = v0 + v7; - tmp1[i+7] = v0 - v7; - tmp1[i+1] = v1 + v6; - tmp1[i+6] = v1 - v6; - tmp1[i+2] = v2 + v5; - tmp1[i+5] = v2 - v5; - tmp1[i+3] = v3 + v4; - tmp1[i+4] = v3 - v4; - } - - // inverse DCT on columns - for (i = 0; i < 8; ++i) { - - // stage 4 - v0 = dctSqrt2 * tmp1[0*8+i]; - v1 = dctSqrt2 * tmp1[4*8+i]; - v2 = tmp1[2*8+i]; - v3 = tmp1[6*8+i]; - v4 = dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]); - v7 = dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]); - v5 = tmp1[3*8+i]; - v6 = tmp1[5*8+i]; - - // stage 3 - t = 0.5 * (v0 - v1); - v0 = 0.5 * (v0 + v1); - v1 = t; - t = v2 * dctSin6 + v3 * dctCos6; - v2 = v2 * dctCos6 - v3 * dctSin6; - v3 = t; - t = 0.5 * (v4 - v6); - v4 = 0.5 * (v4 + v6); - v6 = t; - t = 0.5 * (v7 + v5); - v5 = 0.5 * (v7 - v5); - v7 = t; - - // stage 2 - t = 0.5 * (v0 - v3); - v0 = 0.5 * (v0 + v3); - v3 = t; - t = 0.5 * (v1 - v2); - v1 = 0.5 * (v1 + v2); - v2 = t; - t = v4 * dctSin3 + v7 * dctCos3; - v4 = v4 * dctCos3 - v7 * dctSin3; - v7 = t; - t = v5 * dctSin1 + v6 * dctCos1; - v5 = v5 * dctCos1 - v6 * dctSin1; - v6 = t; - - // stage 1 - tmp1[0*8+i] = v0 + v7; - tmp1[7*8+i] = v0 - v7; - tmp1[1*8+i] = v1 + v6; - tmp1[6*8+i] = v1 - v6; - tmp1[2*8+i] = v2 + v5; - tmp1[5*8+i] = v2 - v5; - tmp1[3*8+i] = v3 + v4; - tmp1[4*8+i] = v3 - v4; - } - - // convert to 8-bit integers - for (i = 0; i < 64; ++i) - data[i] = dctClip[dctClipOffset + (int)(tmp1[i] + 128.5)]; - - return gTrue; } -#endif int DCTStream::readHuffSym(DCTHuffTable *table) { Gushort code; @@ -2533,20 +2811,9 @@ int DCTStream::readBit() { GBool DCTStream::readHeader() { GBool doScan; - int minHSample, minVSample; - int bufWidth; int n; int c = 0; - int i, j; - - width = height = 0; - numComps = 0; - numQuantTables = 0; - numDCHuffTables = 0; - numACHuffTables = 0; - colorXform = 0; - gotAdobeMarker = gFalse; - restartInterval = 0; + int i; // read headers doScan = gFalse; @@ -2554,31 +2821,49 @@ GBool DCTStream::readHeader() { c = readMarker(); switch (c) { case 0xc0: // SOF0 - if (!readFrameInfo()) + if (!readBaselineSOF()) { return gFalse; + } + break; + case 0xc2: // SOF2 + if (!readProgressiveSOF()) { + return gFalse; + } break; case 0xc4: // DHT - if (!readHuffmanTables()) + if (!readHuffmanTables()) { return gFalse; + } break; case 0xd8: // SOI break; + case 0xd9: // EOI + return gFalse; case 0xda: // SOS - if (!readScanInfo()) + if (!readScanInfo()) { return gFalse; + } doScan = gTrue; break; case 0xdb: // DQT - if (!readQuantTables()) + if (!readQuantTables()) { return gFalse; + } break; case 0xdd: // DRI - if (!readRestartInterval()) + if (!readRestartInterval()) { return gFalse; + } + break; + case 0xe0: // APP0 + if (!readJFIFMarker()) { + return gFalse; + } break; case 0xee: // APP14 - if (!readAdobeMarker()) + if (!readAdobeMarker()) { return gFalse; + } break; case EOF: error(getPos(), "Bad DCT header"); @@ -2587,8 +2872,9 @@ GBool DCTStream::readHeader() { // skip APPn / COM / etc. if (c >= 0xe0) { n = read16() - 2; - for (i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { str->getChar(); + } } else { error(getPos(), "Unknown DCT marker <%02x>", c); return gFalse; @@ -2597,107 +2883,105 @@ GBool DCTStream::readHeader() { } } - // compute MCU size - mcuWidth = minHSample = compInfo[0].hSample; - mcuHeight = minVSample = compInfo[0].vSample; - for (i = 1; i < numComps; ++i) { - if (compInfo[i].hSample < minHSample) - minHSample = compInfo[i].hSample; - if (compInfo[i].vSample < minVSample) - minVSample = compInfo[i].vSample; - if (compInfo[i].hSample > mcuWidth) - mcuWidth = compInfo[i].hSample; - if (compInfo[i].vSample > mcuHeight) - mcuHeight = compInfo[i].vSample; - } - for (i = 0; i < numComps; ++i) { - compInfo[i].hSample /= minHSample; - compInfo[i].vSample /= minVSample; - } - mcuWidth = (mcuWidth / minHSample) * 8; - mcuHeight = (mcuHeight / minVSample) * 8; + return gTrue; +} - // allocate buffers - bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; - for (i = 0; i < numComps; ++i) - for (j = 0; j < mcuHeight; ++j) - rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); +GBool DCTStream::readBaselineSOF() { + int length; + int prec; + int i; + int c; - // figure out color transform - if (!gotAdobeMarker && numComps == 3) { - if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) { - colorXform = 1; - } + length = read16(); + prec = str->getChar(); + height = read16(); + width = read16(); + numComps = str->getChar(); + if (prec != 8) { + error(getPos(), "Bad DCT precision %d", prec); + return gFalse; } - - // initialize counters - comp = 0; - x = 0; - y = 0; - dy = mcuHeight; - + for (i = 0; i < numComps; ++i) { + compInfo[i].id = str->getChar(); + c = str->getChar(); + compInfo[i].hSample = (c >> 4) & 0x0f; + compInfo[i].vSample = c & 0x0f; + compInfo[i].quantTable = str->getChar(); + } + progressive = gFalse; return gTrue; } -GBool DCTStream::readFrameInfo() { +GBool DCTStream::readProgressiveSOF() { int length; int prec; int i; int c; - length = read16() - 2; + length = read16(); prec = str->getChar(); height = read16(); width = read16(); numComps = str->getChar(); - length -= 6; if (prec != 8) { error(getPos(), "Bad DCT precision %d", prec); return gFalse; } for (i = 0; i < numComps; ++i) { compInfo[i].id = str->getChar(); - compInfo[i].inScan = gFalse; c = str->getChar(); compInfo[i].hSample = (c >> 4) & 0x0f; compInfo[i].vSample = c & 0x0f; compInfo[i].quantTable = str->getChar(); - compInfo[i].dcHuffTable = 0; - compInfo[i].acHuffTable = 0; } + progressive = gTrue; return gTrue; } GBool DCTStream::readScanInfo() { int length; - int scanComps, id, c; + int id, c; int i, j; length = read16() - 2; - scanComps = str->getChar(); + scanInfo.numComps = str->getChar(); --length; - if (length != 2 * scanComps + 3) { + if (length != 2 * scanInfo.numComps + 3) { error(getPos(), "Bad DCT scan info block"); return gFalse; } - for (i = 0; i < scanComps; ++i) { + interleaved = scanInfo.numComps == numComps; + for (j = 0; j < numComps; ++j) { + scanInfo.comp[j] = gFalse; + } + for (i = 0; i < scanInfo.numComps; ++i) { id = str->getChar(); - for (j = 0; j < numComps; ++j) { - if (id == compInfo[j].id) - break; - } - if (j == numComps) { - error(getPos(), "Bad DCT component ID in scan info block"); - return gFalse; + // some (broken) DCT streams reuse ID numbers, but at least they + // keep the components in order, so we check compInfo[i] first to + // work around the problem + if (id == compInfo[i].id) { + j = i; + } else { + for (j = 0; j < numComps; ++j) { + if (id == compInfo[j].id) { + break; + } + } + if (j == numComps) { + error(getPos(), "Bad DCT component ID in scan info block"); + return gFalse; + } } - compInfo[j].inScan = gTrue; + scanInfo.comp[j] = gTrue; c = str->getChar(); - compInfo[j].dcHuffTable = (c >> 4) & 0x0f; - compInfo[j].acHuffTable = c & 0x0f; + scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f; + scanInfo.acHuffTable[j] = c & 0x0f; } - str->getChar(); - str->getChar(); - str->getChar(); + scanInfo.firstCoeff = str->getChar(); + scanInfo.lastCoeff = str->getChar(); + c = str->getChar(); + scanInfo.ah = (c >> 4) & 0x0f; + scanInfo.al = c & 0x0f; return gTrue; } @@ -2779,23 +3063,61 @@ GBool DCTStream::readRestartInterval() { return gTrue; } +GBool DCTStream::readJFIFMarker() { + int length, i; + char buf[5]; + int c; + + length = read16(); + length -= 2; + if (length >= 5) { + for (i = 0; i < 5; ++i) { + if ((c = str->getChar()) == EOF) { + error(getPos(), "Bad DCT APP0 marker"); + return gFalse; + } + buf[i] = c; + } + length -= 5; + if (!memcmp(buf, "JFIF\0", 5)) { + gotJFIFMarker = gTrue; + } + } + while (length > 0) { + if (str->getChar() == EOF) { + error(getPos(), "Bad DCT APP0 marker"); + return gFalse; + } + --length; + } + return gTrue; +} + GBool DCTStream::readAdobeMarker() { int length, i; char buf[12]; int c; length = read16(); - if (length != 14) + if (length < 14) { goto err; + } for (i = 0; i < 12; ++i) { - if ((c = str->getChar()) == EOF) + if ((c = str->getChar()) == EOF) { goto err; + } buf[i] = c; } - if (strncmp(buf, "Adobe", 5)) + if (strncmp(buf, "Adobe", 5)) { goto err; + } colorXform = buf[11]; gotAdobeMarker = gTrue; + for (i = 14; i < length; ++i) { + if (str->getChar() == EOF) { + goto err; + } + } return gTrue; err: @@ -2838,10 +3160,13 @@ int DCTStream::read16() { return (c1 << 8) + c2; } -GString *DCTStream::getPSFilter(char *indent) { +GString *DCTStream::getPSFilter(int psLevel, char *indent) { GString *s; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("<< >> /DCTDecode filter\n"); @@ -2933,9 +3258,13 @@ FlateStream::FlateStream(Stream *strA, int predictor, int columns, } else { pred = NULL; } + litCodeTab.codes = NULL; + distCodeTab.codes = NULL; } FlateStream::~FlateStream() { + gfree(litCodeTab.codes); + gfree(distCodeTab.codes); if (pred) { delete pred; } @@ -3024,8 +3353,17 @@ int FlateStream::getRawChar() { return c; } -GString *FlateStream::getPSFilter(char *indent) { - return NULL; +GString *FlateStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 3 || pred) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< >> /FlateDecode filter\n"); + return s; } GBool FlateStream::isBinary(GBool last) { @@ -3102,6 +3440,12 @@ GBool FlateStream::startBlock() { int c; int check; + // free the code tables from the previous block + gfree(litCodeTab.codes); + litCodeTab.codes = NULL; + gfree(distCodeTab.codes); + distCodeTab.codes = NULL; + // read block header blockHdr = getCodeWord(3); if (blockHdr & 1) @@ -3136,8 +3480,9 @@ GBool FlateStream::startBlock() { // compressed block with dynamic codes } else if (blockHdr == 2) { compressedBlock = gTrue; - if (!readDynamicCodes()) + if (!readDynamicCodes()) { goto err; + } // unknown block type } else { @@ -3156,186 +3501,196 @@ err: void FlateStream::loadFixedCodes() { int i; - // set up code arrays - litCodeTab.codes = allCodes; - distCodeTab.codes = allCodes + flateMaxLitCodes; - - // initialize literal code table - for (i = 0; i <= 143; ++i) - litCodeTab.codes[i].len = 8; - for (i = 144; i <= 255; ++i) - litCodeTab.codes[i].len = 9; - for (i = 256; i <= 279; ++i) - litCodeTab.codes[i].len = 7; - for (i = 280; i <= 287; ++i) - litCodeTab.codes[i].len = 8; - compHuffmanCodes(&litCodeTab, flateMaxLitCodes); - - // initialize distance code table - for (i = 0; i <= 5; ++i) { - distCodeTab.start[i] = 0; + // build the literal code table + for (i = 0; i <= 143; ++i) { + codeLengths[i] = 8; + } + for (i = 144; i <= 255; ++i) { + codeLengths[i] = 9; } - for (i = 6; i <= flateMaxHuffman+1; ++i) { - distCodeTab.start[i] = flateMaxDistCodes; + for (i = 256; i <= 279; ++i) { + codeLengths[i] = 7; } + for (i = 280; i <= 287; ++i) { + codeLengths[i] = 8; + } + compHuffmanCodes(codeLengths, flateMaxLitCodes, &litCodeTab); + + // build the distance code table for (i = 0; i < flateMaxDistCodes; ++i) { - distCodeTab.codes[i].len = 5; - distCodeTab.codes[i].code = i; - distCodeTab.codes[i].val = i; + codeLengths[i] = 5; } + compHuffmanCodes(codeLengths, flateMaxDistCodes, &distCodeTab); } GBool FlateStream::readDynamicCodes() { int numCodeLenCodes; int numLitCodes; int numDistCodes; - FlateCode codeLenCodes[flateMaxCodeLenCodes]; + int codeLenCodeLengths[flateMaxCodeLenCodes]; FlateHuffmanTab codeLenCodeTab; int len, repeat, code; int i; + codeLenCodeTab.codes = NULL; + // read lengths - if ((numLitCodes = getCodeWord(5)) == EOF) + if ((numLitCodes = getCodeWord(5)) == EOF) { goto err; + } numLitCodes += 257; - if ((numDistCodes = getCodeWord(5)) == EOF) + if ((numDistCodes = getCodeWord(5)) == EOF) { goto err; + } numDistCodes += 1; - if ((numCodeLenCodes = getCodeWord(4)) == EOF) + if ((numCodeLenCodes = getCodeWord(4)) == EOF) { goto err; + } numCodeLenCodes += 4; if (numLitCodes > flateMaxLitCodes || numDistCodes > flateMaxDistCodes || - numCodeLenCodes > flateMaxCodeLenCodes) + numCodeLenCodes > flateMaxCodeLenCodes) { goto err; + } - // read code length code table - codeLenCodeTab.codes = codeLenCodes; - for (i = 0; i < flateMaxCodeLenCodes; ++i) - codeLenCodes[i].len = 0; + // build the code length code table + for (i = 0; i < flateMaxCodeLenCodes; ++i) { + codeLenCodeLengths[i] = 0; + } for (i = 0; i < numCodeLenCodes; ++i) { - if ((codeLenCodes[codeLenCodeMap[i]].len = getCodeWord(3)) == -1) + if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) { goto err; + } } - compHuffmanCodes(&codeLenCodeTab, flateMaxCodeLenCodes); + compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab); - // set up code arrays - litCodeTab.codes = allCodes; - distCodeTab.codes = allCodes + numLitCodes; - - // read literal and distance code tables + // build the literal and distance code tables len = 0; repeat = 0; i = 0; while (i < numLitCodes + numDistCodes) { - if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) + if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) { goto err; + } if (code == 16) { - if ((repeat = getCodeWord(2)) == EOF) + if ((repeat = getCodeWord(2)) == EOF) { + goto err; + } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { goto err; - for (repeat += 3; repeat > 0; --repeat) - allCodes[i++].len = len; + } + for (; repeat > 0; --repeat) { + codeLengths[i++] = len; + } } else if (code == 17) { - if ((repeat = getCodeWord(3)) == EOF) + if ((repeat = getCodeWord(3)) == EOF) { + goto err; + } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { goto err; + } len = 0; - for (repeat += 3; repeat > 0; --repeat) - allCodes[i++].len = 0; + for (; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } } else if (code == 18) { - if ((repeat = getCodeWord(7)) == EOF) + if ((repeat = getCodeWord(7)) == EOF) { + goto err; + } + repeat += 11; + if (i + repeat > numLitCodes + numDistCodes) { goto err; + } len = 0; - for (repeat += 11; repeat > 0; --repeat) - allCodes[i++].len = 0; + for (; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } } else { - allCodes[i++].len = len = code; + codeLengths[i++] = len = code; } } - compHuffmanCodes(&litCodeTab, numLitCodes); - compHuffmanCodes(&distCodeTab, numDistCodes); + compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab); + compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab); + gfree(codeLenCodeTab.codes); return gTrue; err: error(getPos(), "Bad dynamic code table in flate stream"); + gfree(codeLenCodeTab.codes); return gFalse; } -// On entry, the codes> array contains the lengths of each code, -// stored in code value order. This function computes the code words. -// The result is sorted in order of (1) code length and (2) code word. -// The length values are no longer valid. The start> array is -// filled with the indexes of the first code of each length. -void FlateStream::compHuffmanCodes(FlateHuffmanTab *tab, int n) { - int numLengths[flateMaxHuffman+1]; - int nextCode[flateMaxHuffman+1]; - int nextIndex[flateMaxHuffman+2]; - int code; - int i, j; +// Convert an array of lengths, in value order, into a +// Huffman code lookup table. +void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { + int tabSize, len, code, code2, skip, val, i, t; - // count number of codes for each code length - for (i = 0; i <= flateMaxHuffman; ++i) - numLengths[i] = 0; - for (i = 0; i < n; ++i) - ++numLengths[tab->codes[i].len]; + // find max code length + tab->maxLen = 0; + for (val = 0; val < n; ++val) { + if (lengths[val] > tab->maxLen) { + tab->maxLen = lengths[val]; + } + } - // compute first index for each length - tab->start[0] = nextIndex[0] = 0; - for (i = 1; i <= flateMaxHuffman + 1; ++i) - tab->start[i] = nextIndex[i] = tab->start[i-1] + numLengths[i-1]; + // allocate the table + tabSize = 1 << tab->maxLen; + tab->codes = (FlateCode *)gmalloc(tabSize * sizeof(FlateCode)); - // compute first code for each length - code = 0; - numLengths[0] = 0; - for (i = 1; i <= flateMaxHuffman; ++i) { - code = (code + numLengths[i-1]) << 1; - nextCode[i] = code; + // clear the table + for (i = 0; i < tabSize; ++i) { + tab->codes[i].len = 0; + tab->codes[i].val = 0; } - // compute the codes -- this permutes the codes array from value - // order to length/code order - for (i = 0; i < n; ++i) { - j = nextIndex[tab->codes[i].len]++; - if (tab->codes[i].len == 0) - tab->codes[j].code = 0; - else - tab->codes[j].code = nextCode[tab->codes[i].len]++; - tab->codes[j].val = i; + // build the table + for (len = 1, code = 0, skip = 2; + len <= tab->maxLen; + ++len, code <<= 1, skip <<= 1) { + for (val = 0; val < n; ++val) { + if (lengths[val] == len) { + + // bit-reverse the code + code2 = 0; + t = code; + for (i = 0; i < len; ++i) { + code2 = (code2 << 1) | (t & 1); + t >>= 1; + } + + // fill in the table entries + for (i = code2; i < tabSize; i += skip) { + tab->codes[i].len = (Gushort)len; + tab->codes[i].val = (Gushort)val; + } + + ++code; + } + } } } int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { - int len; - int code; + FlateCode *code; int c; - int i, j; - code = 0; - for (len = 1; len <= flateMaxHuffman; ++len) { - - // add a bit to the code - if (codeSize == 0) { - if ((c = str->getChar()) == EOF) - return EOF; - codeBuf = c & 0xff; - codeSize = 8; - } - code = (code << 1) | (codeBuf & 1); - codeBuf >>= 1; - --codeSize; - - // look for code - i = tab->start[len]; - j = tab->start[len + 1]; - if (i < j && code >= tab->codes[i].code && code <= tab->codes[j-1].code) { - i += code - tab->codes[i].code; - return tab->codes[i].val; + while (codeSize < tab->maxLen) { + if ((c = str->getChar()) == EOF) { + break; } + codeBuf |= (c & 0xff) << codeSize; + codeSize += 8; } - - // not found - error(getPos(), "Bad code (%04x) in flate stream", code); - return EOF; + code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)]; + if (codeSize == 0 || codeSize < code->len || code->len == 0) { + return EOF; + } + codeBuf >>= code->len; + codeSize -= code->len; + return (int)code->val; } int FlateStream::getCodeWord(int bits) { @@ -3385,9 +3740,6 @@ void FixedLengthEncoder::reset() { count = 0; } -void FixedLengthEncoder::close() { -} - int FixedLengthEncoder::getChar() { if (length >= 0 && count >= length) return EOF; @@ -3401,6 +3753,10 @@ int FixedLengthEncoder::lookChar() { return str->getChar(); } +GBool FixedLengthEncoder::isBinary(GBool last) { + return str->isBinary(gTrue); +} + //------------------------------------------------------------------------ // ASCIIHexEncoder //------------------------------------------------------------------------ @@ -3425,9 +3781,6 @@ void ASCIIHexEncoder::reset() { eof = gFalse; } -void ASCIIHexEncoder::close() { -} - GBool ASCIIHexEncoder::fillBuf() { static char *hex = "0123456789abcdef"; int c; @@ -3474,9 +3827,6 @@ void ASCII85Encoder::reset() { eof = gFalse; } -void ASCII85Encoder::close() { -} - GBool ASCII85Encoder::fillBuf() { Gulong t; char buf1[5]; @@ -3544,9 +3894,6 @@ void RunLengthEncoder::reset() { eof = gFalse; } -void RunLengthEncoder::close() { -} - // // When fillBuf finishes, buf[] looks like this: // +-----+--------------+-----------------+-- diff --git a/pdf2swf/xpdf/Stream.h b/pdf2swf/xpdf/Stream.h index 3319dcc..0b70afa 100644 --- a/pdf2swf/xpdf/Stream.h +++ b/pdf2swf/xpdf/Stream.h @@ -2,14 +2,16 @@ // // Stream.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef STREAM_H #define STREAM_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -33,6 +35,8 @@ enum StreamKind { strCCITTFax, strDCT, strFlate, + strJBIG2, + strJPX, strWeird // internal-use stream types }; @@ -84,12 +88,12 @@ public: virtual void setPos(Guint pos, int dir = 0) = 0; // Get PostScript command for the filter(s). - virtual GString *getPSFilter(char *indent); + virtual GString *getPSFilter(int psLevel, char *indent); // Does this stream type potentially contain non-printable chars? virtual GBool isBinary(GBool last = gTrue) = 0; - // Get the BaseStream or EmbedStream of this stream. + // Get the BaseStream of this stream. virtual BaseStream *getBaseStream() = 0; // Get the dictionary associated with this stream. @@ -102,6 +106,11 @@ public: // Returns the new stream. Stream *addFilters(Object *dict); + // Tell this stream to ignore any length limitation -- this only + // applies to BaseStream subclasses, and is used as a hack to work + // around broken PDF files with incorrect stream lengths. + virtual void ignoreLength() {} + private: Stream *makeFilter(char *name, Stream *str, Object *params); @@ -123,6 +132,7 @@ public: virtual Stream *makeSubStream(Guint start, GBool limited, Guint length, Object *dict) = 0; virtual void setPos(Guint pos, int dir = 0) = 0; + virtual GBool isBinary(GBool last = gTrue) { return last; } virtual BaseStream *getBaseStream() { return this; } virtual Dict *getDict() { return dict.getDict(); } @@ -163,6 +173,7 @@ public: virtual void setPos(Guint pos, int dir = 0); virtual BaseStream *getBaseStream() { return str->getBaseStream(); } virtual Dict *getDict() { return str->getDict(); } + virtual void ignoreLength() { str->ignoreLength(); } protected: @@ -190,6 +201,10 @@ public: // at least nComps elements. Returns false at end of file. GBool getPixel(Guchar *pix); + // Returns a pointer to the next line of pixels. Returns NULL at + // end of file. + Guchar *getLine(); + // Skip an entire line from the image. void skipLine(); @@ -260,7 +275,7 @@ public: { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual int getPos() { return bufPos + (bufPtr - buf); } virtual void setPos(Guint pos, int dir = 0); - virtual GBool isBinary(GBool last = gTrue) { return last; } + virtual void ignoreLength() { limited = gFalse; } virtual Guint getStart() { return start; } virtual void moveStart(int delta); @@ -287,7 +302,7 @@ private: class MemStream: public BaseStream { public: - MemStream(char *bufA, Guint lengthA, Object *dictA); + MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA); virtual ~MemStream(); virtual Stream *makeSubStream(Guint start, GBool limited, Guint lengthA, Object *dictA); @@ -298,10 +313,9 @@ public: { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; } virtual int lookChar() { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } - virtual int getPos() { return bufPtr - buf; } + virtual int getPos() { return (int)(bufPtr - buf); } virtual void setPos(Guint pos, int dir = 0); - virtual GBool isBinary(GBool last = gTrue) { return last; } - virtual Guint getStart() { return 0; } + virtual Guint getStart() { return start; } virtual void moveStart(int delta); #ifndef NO_DECRYPTION virtual void doDecryption(Guchar *fileKey, int keyLength, @@ -311,10 +325,11 @@ public: private: char *buf; + Guint start; Guint length; - GBool needFree; char *bufEnd; char *bufPtr; + GBool needFree; }; //------------------------------------------------------------------------ @@ -330,23 +345,24 @@ private: class EmbedStream: public BaseStream { public: - EmbedStream(Stream *strA, Object *dictA); + EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA); virtual ~EmbedStream(); - virtual Stream *makeSubStream(Guint start, GBool limited, - Guint length, Object *dictA); + virtual Stream *makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA); virtual StreamKind getKind() { return str->getKind(); } virtual void reset() {} - virtual int getChar() { return str->getChar(); } - virtual int lookChar() { return str->lookChar(); } + virtual int getChar(); + virtual int lookChar(); virtual int getPos() { return str->getPos(); } virtual void setPos(Guint pos, int dir = 0); - virtual GBool isBinary(GBool last = gTrue) { return last; } virtual Guint getStart(); virtual void moveStart(int delta); private: Stream *str; + GBool limited; + Guint length; }; //------------------------------------------------------------------------ @@ -363,7 +379,7 @@ public: virtual int getChar() { int c = lookChar(); buf = EOF; return c; } virtual int lookChar(); - virtual GString *getPSFilter(char *indent); + virtual GString *getPSFilter(int psLevel, char *indent); virtual GBool isBinary(GBool last = gTrue); private: @@ -386,7 +402,7 @@ public: virtual int getChar() { int ch = lookChar(); ++index; return ch; } virtual int lookChar(); - virtual GString *getPSFilter(char *indent); + virtual GString *getPSFilter(int psLevel, char *indent); virtual GBool isBinary(GBool last = gTrue); private: @@ -412,25 +428,33 @@ public: virtual int getChar(); virtual int lookChar(); virtual int getRawChar(); - virtual GString *getPSFilter(char *indent); + virtual GString *getPSFilter(int psLevel, char *indent); virtual GBool isBinary(GBool last = gTrue); private: StreamPredictor *pred; // predictor int early; // early parameter - FILE *zPipe; // uncompress pipe - GString *zName; // .Z file name + GBool eof; // true if at eof int inputBuf; // input buffer int inputBits; // number of bits in input buffer - int inCodeBits; // size of input code - char buf[256]; // buffer - char *bufPtr; // next char to read - char *bufEnd; // end of buffer - - void dumpFile(FILE *f); + struct { // decoding table + int length; + int head; + Guchar tail; + } table[4097]; + int nextCode; // next code to be used + int nextBits; // number of bits in next code word + int prevCode; // previous code used in stream + int newChar; // next char to be added to table + Guchar seqBuf[4097]; // buffer for current sequence + int seqLength; // length of current sequence + int seqIndex; // index into current sequence + GBool first; // first code after a table clear + + GBool processNextCode(); + void clearTable(); int getCode(); - GBool fillBuf(); }; //------------------------------------------------------------------------ @@ -448,7 +472,7 @@ public: { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(char *indent); + virtual GString *getPSFilter(int psLevel, char *indent); virtual GBool isBinary(GBool last = gTrue); private: @@ -479,7 +503,7 @@ public: virtual int getChar() { int c = lookChar(); buf = EOF; return c; } virtual int lookChar(); - virtual GString *getPSFilter(char *indent); + virtual GString *getPSFilter(int psLevel, char *indent); virtual GBool isBinary(GBool last = gTrue); private: @@ -517,13 +541,21 @@ private: // DCT component info struct DCTCompInfo { int id; // component ID - GBool inScan; // is this component in the current scan? int hSample, vSample; // horiz/vert sampling resolutions int quantTable; // quantization table number - int dcHuffTable, acHuffTable; // Huffman table numbers int prevDC; // DC coefficient accumulator }; +struct DCTScanInfo { + GBool comp[4]; // comp[i] is set if component i is + // included in this scan + int numComps; // number of components in the scan + int dcHuffTable[4]; // DC Huffman table numbers + int acHuffTable[4]; // AC Huffman table numbers + int firstCoeff, lastCoeff; // first and last DCT coefficient + int ah, al; // successive approximation parameters +}; + // DCT Huffman decoding table struct DCTHuffTable { Guchar firstSym[17]; // first symbol for this bit length @@ -541,17 +573,22 @@ public: virtual void reset(); virtual int getChar(); virtual int lookChar(); - virtual GString *getPSFilter(char *indent); + virtual GString *getPSFilter(int psLevel, char *indent); virtual GBool isBinary(GBool last = gTrue); Stream *getRawStream() { return str; } private: + GBool progressive; // set if in progressive mode + GBool interleaved; // set if in interleaved mode int width, height; // image size int mcuWidth, mcuHeight; // size of min coding unit, in data units + int bufWidth, bufHeight; // frameBuf size DCTCompInfo compInfo[4]; // info for each component + DCTScanInfo scanInfo; // info for the current scan int numComps; // number of components in image int colorXform; // need YCbCr-to-RGB transform? + GBool gotJFIFMarker; // set if APP0 JFIF marker was present GBool gotAdobeMarker; // set if APP14 Adobe marker was present int restartInterval; // restart interval, in MCUs Guchar quantTables[4][64]; // quantization tables @@ -560,26 +597,38 @@ private: DCTHuffTable acHuffTables[4]; // AC Huffman tables int numDCHuffTables; // number of DC Huffman tables int numACHuffTables; // number of AC Huffman tables - Guchar *rowBuf[4][32]; // buffer for one MCU + Guchar *rowBuf[4][32]; // buffer for one MCU (non-progressive mode) + int *frameBuf[4]; // buffer for frame (progressive mode) int comp, x, y, dy; // current position within image/MCU int restartCtr; // MCUs left until restart int restartMarker; // next restart marker + int eobRun; // number of EOBs left in the current run int inputBuf; // input buffer for variable length codes int inputBits; // number of valid bits in input buffer void restart(); GBool readMCURow(); - GBool readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, - Guchar quantTable[64], int *prevDC, Guchar data[64]); + void readScan(); + GBool readDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]); + GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]); + void decodeImage(); + void transformDataUnit(Guchar *quantTable, + int dataIn[64], Guchar dataOut[64]); int readHuffSym(DCTHuffTable *table); int readAmp(int size); int readBit(); GBool readHeader(); - GBool readFrameInfo(); + GBool readBaselineSOF(); + GBool readProgressiveSOF(); GBool readScanInfo(); GBool readQuantTables(); GBool readHuffmanTables(); GBool readRestartInterval(); + GBool readJFIFMarker(); GBool readAdobeMarker(); GBool readTrailer(); int readMarker(); @@ -599,15 +648,13 @@ private: // Huffman code table entry struct FlateCode { - int len; // code length in bits - int code; // code word - int val; // value represented by this code + Gushort len; // code length, in bits + Gushort val; // value represented by this code }; -// Huffman code table struct FlateHuffmanTab { - int start[flateMaxHuffman+2]; // indexes of first code of each length - FlateCode *codes; // codes, sorted by length and code word + FlateCode *codes; + int maxLen; }; // Decoding info for length and distance code words @@ -627,7 +674,7 @@ public: virtual int getChar(); virtual int lookChar(); virtual int getRawChar(); - virtual GString *getPSFilter(char *indent); + virtual GString *getPSFilter(int psLevel, char *indent); virtual GBool isBinary(GBool last = gTrue); private: @@ -638,8 +685,8 @@ private: int remain; // number valid bytes in output buffer int codeBuf; // input buffer int codeSize; // number of bits in input buffer - FlateCode // literal and distance codes - allCodes[flateMaxLitCodes + flateMaxDistCodes]; + int // literal and distance code lengths + codeLengths[flateMaxLitCodes + flateMaxDistCodes]; FlateHuffmanTab litCodeTab; // literal code table FlateHuffmanTab distCodeTab; // distance code table GBool compressedBlock; // set if reading a compressed block @@ -658,7 +705,7 @@ private: GBool startBlock(); void loadFixedCodes(); GBool readDynamicCodes(); - void compHuffmanCodes(FlateHuffmanTab *tab, int n); + void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab); int getHuffmanCodeWord(FlateHuffmanTab *tab); int getCodeWord(int bits); }; @@ -676,7 +723,7 @@ public: virtual void reset() {} virtual int getChar() { return EOF; } virtual int lookChar() { return EOF; } - virtual GString *getPSFilter(char *indent) { return NULL; } + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } }; @@ -691,11 +738,10 @@ public: ~FixedLengthEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); - virtual void close(); virtual int getChar(); virtual int lookChar(); - virtual GString *getPSFilter(char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue) { return gFalse; } + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } + virtual GBool isBinary(GBool last = gTrue); virtual GBool isEncoder() { return gTrue; } private: @@ -715,12 +761,11 @@ public: virtual ~ASCIIHexEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); - virtual void close(); virtual int getChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(char *indent) { return NULL; } + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } virtual GBool isEncoder() { return gTrue; } @@ -746,12 +791,11 @@ public: virtual ~ASCII85Encoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); - virtual void close(); virtual int getChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(char *indent) { return NULL; } + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } virtual GBool isEncoder() { return gTrue; } @@ -777,13 +821,12 @@ public: virtual ~RunLengthEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); - virtual void close(); virtual int getChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue) { return gFalse; } + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } + virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } private: diff --git a/pdf2swf/xpdf/UTF8.h b/pdf2swf/xpdf/UTF8.h index d707e2f..8536dbf 100644 --- a/pdf2swf/xpdf/UTF8.h +++ b/pdf2swf/xpdf/UTF8.h @@ -2,7 +2,7 @@ // // UTF8.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf2swf/xpdf/UnicodeMap.cc b/pdf2swf/xpdf/UnicodeMap.cc index 75f23d2..300d802 100644 --- a/pdf2swf/xpdf/UnicodeMap.cc +++ b/pdf2swf/xpdf/UnicodeMap.cc @@ -2,15 +2,16 @@ // // UnicodeMap.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include "gmem.h" @@ -101,37 +102,52 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { ++line; } + fclose(f); + return map; } UnicodeMap::UnicodeMap(GString *encodingNameA) { encodingName = encodingNameA; + unicodeOut = gFalse; kind = unicodeMapUser; ranges = NULL; len = 0; eMaps = NULL; eMapsLen = 0; refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif } -UnicodeMap::UnicodeMap(char *encodingNameA, +UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA, UnicodeMapRange *rangesA, int lenA) { encodingName = new GString(encodingNameA); + unicodeOut = unicodeOutA; kind = unicodeMapResident; ranges = rangesA; len = lenA; eMaps = NULL; eMapsLen = 0; refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif } -UnicodeMap::UnicodeMap(char *encodingNameA, UnicodeMapFunc funcA) { +UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapFunc funcA) { encodingName = new GString(encodingNameA); + unicodeOut = unicodeOutA; kind = unicodeMapFunc; func = funcA; eMaps = NULL; eMapsLen = 0; refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif } UnicodeMap::~UnicodeMap() { @@ -142,14 +158,32 @@ UnicodeMap::~UnicodeMap() { if (eMaps) { gfree(eMaps); } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif } void UnicodeMap::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif } void UnicodeMap::decRefCnt() { - if (--refCnt == 0) { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { delete this; } } @@ -168,29 +202,28 @@ int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) { a = 0; b = len; - if (u < ranges[a].start) { - return 0; - } - // invariant: ranges[a].start <= u < ranges[b].start - while (b - a > 1) { - m = (a + b) / 2; - if (u >= ranges[m].start) { - a = m; - } else if (u < ranges[m].start) { - b = m; - } - } - if (u <= ranges[a].end) { - n = ranges[a].nBytes; - if (n > bufSize) { - return 0; + if (u >= ranges[a].start) { + // invariant: ranges[a].start <= u < ranges[b].start + while (b - a > 1) { + m = (a + b) / 2; + if (u >= ranges[m].start) { + a = m; + } else if (u < ranges[m].start) { + b = m; + } } - code = ranges[a].code + (u - ranges[a].start); - for (i = n - 1; i >= 0; --i) { - buf[i] = (char)(code & 0xff); - code >>= 8; + if (u <= ranges[a].end) { + n = ranges[a].nBytes; + if (n > bufSize) { + return 0; + } + code = ranges[a].code + (u - ranges[a].start); + for (i = n - 1; i >= 0; --i) { + buf[i] = (char)(code & 0xff); + code >>= 8; + } + return n; } - return n; } for (i = 0; i < eMapsLen; ++i) { diff --git a/pdf2swf/xpdf/UnicodeMap.h b/pdf2swf/xpdf/UnicodeMap.h index 274c447..6fd4ed2 100644 --- a/pdf2swf/xpdf/UnicodeMap.h +++ b/pdf2swf/xpdf/UnicodeMap.h @@ -4,20 +4,26 @@ // // Mapping from Unicode to an encoding. // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef UNICODEMAP_H #define UNICODEMAP_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "CharTypes.h" +#if MULTITHREADED +#include "GMutex.h" +#endif + class GString; //------------------------------------------------------------------------ @@ -47,12 +53,13 @@ public: static UnicodeMap *parse(GString *encodingNameA); // Create a resident UnicodeMap. - UnicodeMap(char *encodingNameA, + UnicodeMap(char *encodingNameA, GBool unicodeOutA, UnicodeMapRange *rangesA, int lenA); // Create a resident UnicodeMap that uses a function instead of a // list of ranges. - UnicodeMap(char *encodingNameA, UnicodeMapFunc funcA); + UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapFunc funcA); ~UnicodeMap(); @@ -61,6 +68,8 @@ public: GString *getEncodingName() { return encodingName; } + GBool isUnicode() { return unicodeOut; } + // Return true if this UnicodeMap matches the specified // . GBool match(GString *encodingNameA); @@ -77,6 +86,7 @@ private: GString *encodingName; UnicodeMapKind kind; + GBool unicodeOut; union { UnicodeMapRange *ranges; // (user, resident) UnicodeMapFunc func; // (func) @@ -85,6 +95,9 @@ private: UnicodeMapExt *eMaps; // (user) int eMapsLen; // (user) int refCnt; +#ifdef MULTITHREADED + GMutex mutex; +#endif }; //------------------------------------------------------------------------ diff --git a/pdf2swf/xpdf/UnicodeMapTables.h b/pdf2swf/xpdf/UnicodeMapTables.h index 51dee98..9c51034 100644 --- a/pdf2swf/xpdf/UnicodeMapTables.h +++ b/pdf2swf/xpdf/UnicodeMapTables.h @@ -2,7 +2,7 @@ // // UnicodeMapTables.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf2swf/xpdf/XRef.cc b/pdf2swf/xpdf/XRef.cc index 0e1bbc9..e0d82d2 100644 --- a/pdf2swf/xpdf/XRef.cc +++ b/pdf2swf/xpdf/XRef.cc @@ -2,15 +2,16 @@ // // XRef.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -46,12 +47,148 @@ #endif //------------------------------------------------------------------------ +// ObjectStream +//------------------------------------------------------------------------ + +class ObjectStream { +public: + + // Create an object stream, using object number , + // generation 0. + ObjectStream(XRef *xref, int objStrNumA); + + ~ObjectStream(); + + // Return the object number of this object stream. + int getObjStrNum() { return objStrNum; } + + // Get the th object from this stream, which should be + // object number , generation 0. + Object *getObject(int objIdx, int objNum, Object *obj); + +private: + + int objStrNum; // object number of the object stream + int nObjects; // number of objects in the stream + Object *objs; // the objects (length = nObjects) + int *objNums; // the object numbers (length = nObjects) +}; + +ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { + Stream *str; + Parser *parser; + int *offsets; + Object objStr, obj1, obj2; + int first, i; + + objStrNum = objStrNumA; + nObjects = 0; + objs = NULL; + objNums = NULL; + + if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { + goto err1; + } + + if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { + obj1.free(); + goto err1; + } + nObjects = obj1.getInt(); + obj1.free(); + if (nObjects == 0) { + goto err1; + } + + if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { + obj1.free(); + goto err1; + } + first = obj1.getInt(); + obj1.free(); + + objs = new Object[nObjects]; + objNums = (int *)gmalloc(nObjects * sizeof(int)); + offsets = (int *)gmalloc(nObjects * sizeof(int)); + + // parse the header: object numbers and offsets + objStr.streamReset(); + obj1.initNull(); + str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); + parser = new Parser(xref, new Lexer(xref, str)); + for (i = 0; i < nObjects; ++i) { + parser->getObj(&obj1); + parser->getObj(&obj2); + if (!obj1.isInt() || !obj2.isInt()) { + obj1.free(); + obj2.free(); + delete parser; + gfree(offsets); + goto err1; + } + objNums[i] = obj1.getInt(); + offsets[i] = obj2.getInt(); + obj1.free(); + obj2.free(); + } + while (str->getChar() != EOF) ; + delete parser; + + // skip to the first object - this shouldn't be necessary because + // the First key is supposed to be equal to offsets[0], but just in + // case... + for (i = first; i < offsets[0]; ++i) { + objStr.getStream()->getChar(); + } + + // parse the objects + for (i = 0; i < nObjects; ++i) { + obj1.initNull(); + if (i == nObjects - 1) { + str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0); + } else { + str = new EmbedStream(objStr.getStream(), &obj1, gTrue, + offsets[i+1] - offsets[i]); + } + parser = new Parser(xref, new Lexer(xref, str)); + parser->getObj(&objs[i]); + while (str->getChar() != EOF) ; + delete parser; + } + + gfree(offsets); + + err1: + objStr.free(); + return; +} + +ObjectStream::~ObjectStream() { + int i; + + if (objs) { + for (i = 0; i < nObjects; ++i) { + objs[i].free(); + } + delete[] objs; + } + gfree(objNums); +} + +Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { + if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) { + return obj->initNull(); + } + return objs[objIdx].copy(obj); +} + +//------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { Guint pos; - int i; + Object obj; ok = gTrue; errCode = errNone; @@ -59,35 +196,28 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { entries = NULL; streamEnds = NULL; streamEndsLen = 0; + objStr = NULL; // read the trailer str = strA; start = str->getStart(); - pos = readTrailer(); + pos = getStartXref(); - // if there was a problem with the trailer, - // try to reconstruct the xref table + // if there was a problem with the 'startxref' position, try to + // reconstruct the xref table if (pos == 0) { if (!(ok = constructXRef())) { errCode = errDamaged; return; } - // trailer is ok - read the xref table + // read the xref table } else { - entries = (XRefEntry *)gmalloc(size * sizeof(XRefEntry)); - for (i = 0; i < size; ++i) { - entries[i].offset = 0xffffffff; - entries[i].used = gFalse; - } while (readXRef(&pos)) ; // if there was a problem with the xref table, // try to reconstruct it if (!ok) { - gfree(entries); - size = 0; - entries = NULL; if (!(ok = constructXRef())) { errCode = errDamaged; return; @@ -95,6 +225,20 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { } } + // get the root dictionary (catalog) object + trailerDict.dictLookupNF("Root", &obj); + if (obj.isRef()) { + rootNum = obj.getRefNum(); + rootGen = obj.getRefGen(); + obj.free(); + } else { + obj.free(); + if (!(ok = constructXRef())) { + errCode = errDamaged; + return; + } + } + // now set the trailer dictionary's xref pointer so we can fetch // indirect objects from it trailerDict.getDict()->setXRef(this); @@ -116,188 +260,154 @@ XRef::~XRef() { if (streamEnds) { gfree(streamEnds); } + if (objStr) { + delete objStr; + } } -// Read startxref position, xref table size, and root. Returns -// first xref position. -Guint XRef::readTrailer() { - Parser *parser; - Object obj; +// Read the 'startxref' position. +Guint XRef::getStartXref() { char buf[xrefSearchSize+1]; - int n; - Guint pos, pos1; char *p; - int c; - int i; + int c, n, i; // read last xrefSearchSize bytes str->setPos(xrefSearchSize, -1); for (n = 0; n < xrefSearchSize; ++n) { - if ((c = str->getChar()) == EOF) + if ((c = str->getChar()) == EOF) { break; + } buf[n] = c; } buf[n] = '\0'; // find startxref for (i = n - 9; i >= 0; --i) { - if (!strncmp(&buf[i], "startxref", 9)) + if (!strncmp(&buf[i], "startxref", 9)) { break; + } } - if (i < 0) + if (i < 0) { return 0; + } for (p = &buf[i+9]; isspace(*p); ++p) ; - pos = lastXRefPos = strToUnsigned(p); - - // find trailer dict by looking after first xref table - // (NB: we can't just use the trailer dict at the end of the file -- - // this won't work for linearized files.) - str->setPos(start + pos); - for (i = 0; i < 4; ++i) - buf[i] = str->getChar(); - if (strncmp(buf, "xref", 4)) - return 0; - pos1 = pos + 4; - while (1) { - str->setPos(start + pos1); - for (i = 0; i < 35; ++i) { - if ((c = str->getChar()) == EOF) - return 0; - buf[i] = c; - } - if (!strncmp(buf, "trailer", 7)) - break; - p = buf; - while (isspace(*p)) ++p; - while ('0' <= *p && *p <= '9') ++p; - while (isspace(*p)) ++p; - n = atoi(p); - while ('0' <= *p && *p <= '9') ++p; - while (isspace(*p)) ++p; - if (p == buf) - return 0; - pos1 += (p - buf) + n * 20; - } - pos1 += 7; - - // read trailer dict + lastXRefPos = strToUnsigned(p); + + return lastXRefPos; +} + +// Read one xref table section. Also reads the associated trailer +// dictionary, and returns the prev pointer (if any). +GBool XRef::readXRef(Guint *pos) { + Parser *parser; + Object obj; + GBool more; + + // start up a parser, parse one token obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, - str->makeSubStream(start + pos1, gFalse, 0, &obj))); - parser->getObj(&trailerDict); - if (trailerDict.isDict()) { - trailerDict.dictLookupNF("Size", &obj); - if (obj.isInt()) - size = obj.getInt(); - else - pos = 0; + str->makeSubStream(start + *pos, gFalse, 0, &obj))); + parser->getObj(&obj); + + // parse an old-style xref table + if (obj.isCmd("xref")) { obj.free(); - trailerDict.dictLookupNF("Root", &obj); - if (obj.isRef()) { - rootNum = obj.getRefNum(); - rootGen = obj.getRefGen(); - } else { - pos = 0; + more = readXRefTable(parser, pos); + + // parse an xref stream + } else if (obj.isInt()) { + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + obj.free(); + if (!parser->getObj(&obj)->isCmd("obj")) { + goto err1; } obj.free(); + if (!parser->getObj(&obj)->isStream()) { + goto err1; + } + more = readXRefStream(obj.getStream(), pos); + obj.free(); + } else { - pos = 0; + goto err1; } + delete parser; + return more; - // return first xref position - return pos; + err1: + obj.free(); + delete parser; + ok = gFalse; + return gFalse; } -// Read an xref table and the prev pointer from the trailer. -GBool XRef::readXRef(Guint *pos) { - Parser *parser; - Object obj, obj2; - char s[20]; +GBool XRef::readXRefTable(Parser *parser, Guint *pos) { + XRefEntry entry; GBool more; - int first, newSize, n, i, j; - int c; - - // seek to xref in stream - str->setPos(start + *pos); - - // make sure it's an xref table - while ((c = str->getChar()) != EOF && isspace(c)) ; - s[0] = (char)c; - s[1] = (char)str->getChar(); - s[2] = (char)str->getChar(); - s[3] = (char)str->getChar(); - if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f')) { - goto err2; - } + Object obj, obj2; + Guint pos2; + int first, n, newSize, i; - // read xref while (1) { - while ((c = str->lookChar()) != EOF && isspace(c)) { - str->getChar(); - } - if (c == 't') { + parser->getObj(&obj); + if (obj.isCmd("trailer")) { + obj.free(); break; } - for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) { - s[i] = (char)c; - } - if (i == 0) { - goto err2; + if (!obj.isInt()) { + goto err1; } - s[i] = '\0'; - first = atoi(s); - while ((c = str->lookChar()) != EOF && isspace(c)) { - str->getChar(); - } - for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) { - s[i] = (char)c; - } - if (i == 0) { - goto err2; - } - s[i] = '\0'; - n = atoi(s); - while ((c = str->lookChar()) != EOF && isspace(c)) { - str->getChar(); + first = obj.getInt(); + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; } - // check for buggy PDF files with an incorrect (too small) xref - // table size + n = obj.getInt(); + obj.free(); if (first + n > size) { - newSize = size + 256; + for (newSize = size ? 2 * size : 1024; + first + n > newSize; + newSize <<= 1) ; entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; - entries[i].used = gFalse; + entries[i].type = xrefEntryFree; } size = newSize; } for (i = first; i < first + n; ++i) { - for (j = 0; j < 20; ++j) { - if ((c = str->getChar()) == EOF) { - goto err2; - } - s[j] = (char)c; + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + entry.offset = (Guint)obj.getInt(); + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; } + entry.gen = obj.getInt(); + obj.free(); + parser->getObj(&obj); + if (obj.isCmd("n")) { + entry.type = xrefEntryUncompressed; + } else if (obj.isCmd("f")) { + entry.type = xrefEntryFree; + } else { + goto err1; + } + obj.free(); if (entries[i].offset == 0xffffffff) { - s[10] = '\0'; - entries[i].offset = strToUnsigned(s); - s[16] = '\0'; - entries[i].gen = atoi(&s[11]); - if (s[17] == 'n') { - entries[i].used = gTrue; - } else if (s[17] == 'f') { - entries[i].used = gFalse; - } else { - goto err2; - } + entries[i] = entry; // PDF files of patents from the IBM Intellectual Property // Network have a bug: the xref table claims to start at 1 // instead of 0. if (i == 1 && first == 1 && entries[1].offset == 0 && entries[1].gen == 65535 && - !entries[1].used) { + entries[1].type == xrefEntryFree) { i = first = 0; entries[0] = entries[1]; entries[1].offset = 0xffffffff; @@ -306,44 +416,203 @@ GBool XRef::readXRef(Guint *pos) { } } - // read prev pointer from trailer dictionary - obj.initNull(); - parser = new Parser(NULL, - new Lexer(NULL, - str->makeSubStream(str->getPos(), gFalse, 0, &obj))); - parser->getObj(&obj); - if (!obj.isCmd("trailer")) { - goto err1; - } - obj.free(); - parser->getObj(&obj); - if (!obj.isDict()) { + // read the trailer dictionary + if (!parser->getObj(&obj)->isDict()) { goto err1; } + + // get the 'Prev' pointer obj.getDict()->lookupNF("Prev", &obj2); if (obj2.isInt()) { *pos = (Guint)obj2.getInt(); more = gTrue; + } else if (obj2.isRef()) { + // certain buggy PDF generators generate "/Prev NNN 0 R" instead + // of "/Prev NNN" + *pos = (Guint)obj2.getRefNum(); + more = gTrue; } else { more = gFalse; } - obj.free(); obj2.free(); - delete parser; + // save the first trailer dictionary + if (trailerDict.isNone()) { + obj.copy(&trailerDict); + } + + // check for an 'XRefStm' key + if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { + pos2 = obj2.getInt(); + readXRef(&pos2); + if (!ok) { + goto err1; + } + } + obj2.free(); + + obj.free(); return more; err1: obj.free(); - err2: ok = gFalse; return gFalse; } +GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { + Dict *dict; + int w[3]; + GBool more; + Object obj, obj2, idx; + int newSize, first, n, i; + + dict = xrefStr->getDict(); + + if (!dict->lookupNF("Size", &obj)->isInt()) { + goto err1; + } + newSize = obj.getInt(); + obj.free(); + if (newSize > size) { + entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + + if (!dict->lookupNF("W", &obj)->isArray() || + obj.arrayGetLength() < 3) { + goto err1; + } + for (i = 0; i < 3; ++i) { + if (!obj.arrayGet(i, &obj2)->isInt()) { + obj2.free(); + goto err1; + } + w[i] = obj2.getInt(); + obj2.free(); + } + obj.free(); + + xrefStr->reset(); + dict->lookupNF("Index", &idx); + if (idx.isArray()) { + for (i = 0; i+1 < idx.arrayGetLength(); i += 2) { + if (!idx.arrayGet(i, &obj)->isInt()) { + idx.free(); + goto err1; + } + first = obj.getInt(); + obj.free(); + if (!idx.arrayGet(i+1, &obj)->isInt()) { + idx.free(); + goto err1; + } + n = obj.getInt(); + obj.free(); + if (!readXRefStreamSection(xrefStr, w, first, n)) { + idx.free(); + goto err0; + } + } + } else { + if (!readXRefStreamSection(xrefStr, w, 0, size)) { + idx.free(); + goto err0; + } + } + idx.free(); + + dict->lookupNF("Prev", &obj); + if (obj.isInt()) { + *pos = (Guint)obj.getInt(); + more = gTrue; + } else { + more = gFalse; + } + obj.free(); + if (trailerDict.isNone()) { + trailerDict.initDict(dict); + } + + return more; + + err1: + obj.free(); + err0: + ok = gFalse; + return gFalse; +} + +GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { + Guint offset; + int type, gen, c, newSize, i, j; + + if (first + n > size) { + for (newSize = size ? 2 * size : 1024; + first + n > newSize; + newSize <<= 1) ; + entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + for (i = first; i < first + n; ++i) { + if (w[0] == 0) { + type = 1; + } else { + for (type = 0, j = 0; j < w[0]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + type = (type << 8) + c; + } + } + for (offset = 0, j = 0; j < w[1]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + offset = (offset << 8) + c; + } + for (gen = 0, j = 0; j < w[2]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + gen = (gen << 8) + c; + } + switch (type) { + case 0: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryFree; + break; + case 1: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryUncompressed; + break; + case 2: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryCompressed; + break; + default: + return gFalse; + } + } + + return gTrue; +} + // Attempt to construct an xref table for a damaged file. GBool XRef::constructXRef() { Parser *parser; - Object obj; + Object newTrailerDict, obj; char buf[256]; Guint pos; int num, gen; @@ -353,6 +622,10 @@ GBool XRef::constructXRef() { int i; GBool gotRoot; + gfree(entries); + size = 0; + entries = NULL; + error(0, "PDF file is damaged - attempting to reconstruct xref table..."); gotRoot = gFalse; streamEndsLen = streamEndsSize = 0; @@ -371,20 +644,21 @@ GBool XRef::constructXRef() { parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(start + pos + 7, gFalse, 0, &obj))); - if (!trailerDict.isNone()) - trailerDict.free(); - parser->getObj(&trailerDict); - if (trailerDict.isDict()) { - trailerDict.dictLookupNF("Root", &obj); + parser->getObj(&newTrailerDict); + if (newTrailerDict.isDict()) { + newTrailerDict.dictLookupNF("Root", &obj); if (obj.isRef()) { rootNum = obj.getRefNum(); rootGen = obj.getRefGen(); + if (!trailerDict.isNone()) { + trailerDict.free(); + } + newTrailerDict.copy(&trailerDict); gotRoot = gTrue; } obj.free(); - } else { - pos = 0; } + newTrailerDict.free(); delete parser; // look for object @@ -413,14 +687,15 @@ GBool XRef::constructXRef() { grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; - entries[i].used = gFalse; + entries[i].type = xrefEntryFree; } size = newSize; } - if (!entries[num].used || gen >= entries[num].gen) { + if (entries[num].type == xrefEntryFree || + gen >= entries[num].gen) { entries[num].offset = pos - start; entries[num].gen = gen; - entries[num].used = gTrue; + entries[num].type = xrefEntryUncompressed; } } } @@ -451,9 +726,12 @@ GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { GBool encrypted1; GBool ret; + keyLength = 0; + encVersion = encRevision = 0; ret = gFalse; permFlags = defPermFlags; + ownerPasswordOk = gFalse; trailerDict.dictLookup("Encrypt", &encrypt); if ((encrypted1 = encrypt.isDict())) { ret = gTrue; @@ -544,38 +822,34 @@ GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { GBool XRef::okToPrint(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION - if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permPrint)) { - return gFalse; - } -#endif + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); +#else return gTrue; +#endif } GBool XRef::okToChange(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION - if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permChange)) { - return gFalse; - } -#endif + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange); +#else return gTrue; +#endif } GBool XRef::okToCopy(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION - if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permCopy)) { - return gFalse; - } -#endif + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy); +#else return gTrue; +#endif } GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { #ifndef NO_DECRYPTION - if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permNotes)) { - return gFalse; - } -#endif + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes); +#else return gTrue; +#endif } Object *XRef::fetch(int num, int gen, Object *obj) { @@ -585,12 +859,16 @@ Object *XRef::fetch(int num, int gen, Object *obj) { // check for bogus ref - this can happen in corrupted PDF files if (num < 0 || num >= size) { - obj->initNull(); - return obj; + goto err; } e = &entries[num]; - if (e->gen == gen && e->offset != 0xffffffff) { + switch (e->type) { + + case xrefEntryUncompressed: + if (e->gen != gen) { + goto err; + } obj1.initNull(); parser = new Parser(this, new Lexer(this, @@ -598,26 +876,44 @@ Object *XRef::fetch(int num, int gen, Object *obj) { parser->getObj(&obj1); parser->getObj(&obj2); parser->getObj(&obj3); - if (obj1.isInt() && obj1.getInt() == num && - obj2.isInt() && obj2.getInt() == gen && - obj3.isCmd("obj")) { + if (!obj1.isInt() || obj1.getInt() != num || + !obj2.isInt() || obj2.getInt() != gen || + !obj3.isCmd("obj")) { + goto err; + } #ifndef NO_DECRYPTION - parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, - num, gen); + parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, + num, gen); #else - parser->getObj(obj); + parser->getObj(obj); #endif - } else { - obj->initNull(); - } obj1.free(); obj2.free(); obj3.free(); delete parser; - } else { - obj->initNull(); + break; + + case xrefEntryCompressed: + if (gen != 0) { + goto err; + } + if (!objStr || objStr->getObjStrNum() != (int)e->offset) { + if (objStr) { + delete objStr; + } + objStr = new ObjectStream(this, e->offset); + } + objStr->getObject(e->gen, num, obj); + break; + + default: + goto err; } + return obj; + + err: + return obj->initNull(); } Object *XRef::getDocInfo(Object *obj) { diff --git a/pdf2swf/xpdf/XRef.h b/pdf2swf/xpdf/XRef.h index 7876fa6..bec487a 100644 --- a/pdf2swf/xpdf/XRef.h +++ b/pdf2swf/xpdf/XRef.h @@ -2,14 +2,16 @@ // // XRef.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef XREF_H #define XREF_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -18,15 +20,23 @@ class Dict; class Stream; +class Parser; +class ObjectStream; //------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ +enum XRefEntryType { + xrefEntryFree, + xrefEntryUncompressed, + xrefEntryCompressed +}; + struct XRefEntry { Guint offset; int gen; - GBool used; + XRefEntryType type; }; class XRef { @@ -81,6 +91,11 @@ public: // Returns false if unknown or file is not damaged. GBool getStreamEnd(Guint streamStart, Guint *streamEnd); + // Direct access. + int getSize() { return size; } + XRefEntry *getEntry(int i) { return &entries[i]; } + Object *getTrailerDict() { return &trailerDict; } + private: BaseStream *str; // input stream @@ -96,6 +111,7 @@ private: Guint *streamEnds; // 'endstream' positions - only used in // damaged files int streamEndsLen; // number of valid entries in streamEnds + ObjectStream *objStr; // cached object stream #ifndef NO_DECRYPTION GBool encrypted; // true if file is encrypted int encVersion; // encryption algorithm @@ -106,8 +122,11 @@ private: GBool ownerPasswordOk; // true if owner password is correct #endif - Guint readTrailer(); + Guint getStartXref(); GBool readXRef(Guint *pos); + GBool readXRefTable(Parser *parser, Guint *pos); + GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); + GBool readXRefStream(Stream *xrefStr, Guint *pos); GBool constructXRef(); GBool checkEncrypted(GString *ownerPassword, GString *userPassword); Guint strToUnsigned(char *s); diff --git a/pdf2swf/xpdf/aconf.h b/pdf2swf/xpdf/aconf.h index d288e79..524ccee 100644 --- a/pdf2swf/xpdf/aconf.h +++ b/pdf2swf/xpdf/aconf.h @@ -19,5 +19,6 @@ // SELECT_TAKES_INT // HAVE_FSEEK64 // HAVE_MKSTEMPS +// HAVE_FSEEKO 1 #endif diff --git a/pdf2swf/xpdf/config.h b/pdf2swf/xpdf/config.h index 39cb291..bf6baf4 100644 --- a/pdf2swf/xpdf/config.h +++ b/pdf2swf/xpdf/config.h @@ -2,7 +2,7 @@ // // config.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2004 Glyph & Cog, LLC // //======================================================================== @@ -14,15 +14,23 @@ //------------------------------------------------------------------------ // xpdf version - -#define xpdfVersion "1.01" +#define xpdfVersion "3.00" +#define xpdfVersionNum 3.00 +#define xpdfMajorVersion 3 +#define xpdfMinorVersion 0 +#define xpdfMajorVersionStr "3" +#define xpdfMinorVersionStr "0" // supported PDF version -#define supportedPDFVersionStr "1.4" -#define supportedPDFVersionNum 1.4 +#define supportedPDFVersionStr "1.5" +#define supportedPDFVersionNum 1.5 // copyright notice -#define xpdfCopyright "Copyright 1996-2002 Glyph & Cog, LLC" +#define xpdfCopyright "Copyright 1996-2004 Glyph & Cog, LLC" + +// Windows resource file stuff +#define winxpdfVersion "WinXpdf 3.00" +#define xpdfCopyrightAmp "Copyright 1996-2004 Glyph && Cog, LLC" //------------------------------------------------------------------------ // paper size @@ -74,46 +82,18 @@ // popen //------------------------------------------------------------------------ -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__BORLANDC__) #define popen _popen #define pclose _pclose #endif -#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(__CYGWIN32__) || defined(MACOS) +#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(MACOS) #define POPEN_READ_MODE "rb" #else #define POPEN_READ_MODE "r" #endif //------------------------------------------------------------------------ -// uncompress program -//------------------------------------------------------------------------ - -#ifdef HAVE_POPEN - -// command to uncompress to stdout -# ifdef USE_GZIP -# define uncompressCmd "gzip -d -c -q" -# else -# ifdef __EMX__ -# define uncompressCmd "compress -d -c" -# else -# define uncompressCmd "uncompress -c" -# endif // __EMX__ -# endif // USE_GZIP - -#else // HAVE_POPEN - -// command to uncompress a file -# ifdef USE_GZIP -# define uncompressCmd "gzip -d -q" -# else -# define uncompressCmd "uncompress" -# endif // USE_GZIP - -#endif // HAVE_POPEN - -//------------------------------------------------------------------------ // Win32 stuff //------------------------------------------------------------------------ @@ -121,7 +101,7 @@ #undef CDECL #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__BORLANDC__) #define CDECL __cdecl #else #define CDECL diff --git a/pdf2swf/xpdf/gfile.cc b/pdf2swf/xpdf/gfile.cc index b4d88cd..11f5cf6 100644 --- a/pdf2swf/xpdf/gfile.cc +++ b/pdf2swf/xpdf/gfile.cc @@ -4,20 +4,13 @@ // // Miscellaneous file and directory name manipulation. // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include -#include "../../config.h" -#ifdef WIN32 - extern "C" { -//# ifndef _MSC_VER -//# include -//# endif - } -#else // !WIN32 +#ifndef WIN32 # if defined(MACOS) # include # elif !defined(ACORN) @@ -443,58 +436,11 @@ time_t getModTime(char *fileName) { return statBuf.st_mtime; #endif } - -static char* getTempDir() -{ -#ifdef WIN32 - char*dir = getenv("TMP"); - if(!dir) dir = getenv("TEMP"); - if(!dir) dir = getenv("tmp"); - if(!dir) dir = getenv("temp"); - if(!dir) dir = "C:\\"; -#else - char* dir = "/tmp/"; -#endif - return dir; -} - -char* mktmpname(char*ptr) { - static char tmpbuf[128]; - char*dir = getTempDir(); - int l = strlen(dir); - char*sep = ""; - if(!ptr) - ptr = tmpbuf; - if(l && dir[l-1]!='/' && dir[l-1]!='\\') { -#ifdef WIN32 - sep = "\\"; -#else - sep = "/"; -#endif - } - - // used to be mktemp. This does remove the warnings, but - // It's not exactly an improvement. -#ifdef HAVE_LRAND48 - sprintf(ptr, "%s%s%08x%08x",dir,sep,lrand48(),lrand48()); -#else -# ifdef HAVE_RAND - sprintf(ptr, "%s%s%08x%08x",dir,sep,rand(),rand()); -# else - static int count = 1; - sprintf(ptr, "%s%s%08x%04x%04x",dir,sep,time(0),(unsigned int)tmpbuf^((unsigned int)tmpbuf)>>16,count); - count ++; -# endif -#endif - return ptr; -} GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { #if defined(WIN32) //---------- Win32 ---------- char *s; - char buf[_MAX_PATH]; - char *fp; if (!(s = _tempnam(getenv("TEMP"), NULL))) { return gFalse; @@ -517,7 +463,7 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { // with this file name after the tmpnam call and before the fopen // call. I will happily accept fixes to this function for non-Unix // OSs. - if (!(s = mktmpname(NULL))) { //was: tmpnam + if (!(s = tmpnam(NULL))) { return gFalse; } *name = new GString(s); @@ -544,7 +490,7 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { (*name)->append("/XXXXXX")->append(ext); fd = mkstemps((*name)->getCString(), strlen(ext)); #else - if (!(s = mktmpname(NULL))) { //was: tmpnam + if (!(s = tmpnam(NULL))) { return gFalse; } *name = new GString(s); @@ -561,7 +507,7 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { (*name)->append("/XXXXXX"); fd = mkstemp((*name)->getCString()); #else // HAVE_MKSTEMP - if (!(s = mktmpname(NULL))) { //was: tmpnam + if (!(s = tmpnam(NULL))) { return gFalse; } *name = new GString(s); @@ -692,36 +638,48 @@ GDir::~GDir() { } GDirEntry *GDir::getNextEntry() { - struct dirent *ent; GDirEntry *e; - e = NULL; #if defined(WIN32) - e = new GDirEntry(path->getCString(), ffd.cFileName, doStat); - if (hnd && !FindNextFile(hnd, &ffd)) { - FindClose(hnd); - hnd = NULL; + if (hnd) { + e = new GDirEntry(path->getCString(), ffd.cFileName, doStat); + if (hnd && !FindNextFile(hnd, &ffd)) { + FindClose(hnd); + hnd = NULL; + } + } else { + e = NULL; } #elif defined(ACORN) #elif defined(MACOS) -#else +#elif defined(VMS) + struct dirent *ent; + e = NULL; if (dir) { -#ifdef VMS if (needParent) { e = new GDirEntry(path->getCString(), "-", doStat); needParent = gFalse; return e; } -#endif ent = readdir(dir); -#ifndef VMS - if (ent && !strcmp(ent->d_name, ".")) + if (ent) { + e = new GDirEntry(path->getCString(), ent->d_name, doStat); + } + } +#else + struct dirent *ent; + e = NULL; + if (dir) { + ent = readdir(dir); + if (ent && !strcmp(ent->d_name, ".")) { ent = readdir(dir); -#endif - if (ent) + } + if (ent) { e = new GDirEntry(path->getCString(), ent->d_name, doStat); + } } #endif + return e; } @@ -734,6 +692,7 @@ void GDir::rewind() { tmp = path->copy(); tmp->append("/*.*"); hnd = FindFirstFile(tmp->getCString(), &ffd); + delete tmp; #elif defined(ACORN) #elif defined(MACOS) #else diff --git a/pdf2swf/xpdf/gfile.h b/pdf2swf/xpdf/gfile.h index aa5e9d8..82f1d7a 100644 --- a/pdf2swf/xpdf/gfile.h +++ b/pdf2swf/xpdf/gfile.h @@ -4,7 +4,7 @@ // // Miscellaneous file and directory name manipulation. // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -14,14 +14,12 @@ #include #include #include -#include "./aconf.h" #if defined(WIN32) # include # ifdef FPTEX # include # else # include -# include # endif #elif defined(ACORN) #elif defined(MACOS) @@ -137,7 +135,4 @@ private: #endif }; -/* create a temporary filename */ -char* mktmpname(char*ptr); - #endif diff --git a/pdf2swf/xpdf/gmem.h b/pdf2swf/xpdf/gmem.h index 93ccb94..587e7fa 100644 --- a/pdf2swf/xpdf/gmem.h +++ b/pdf2swf/xpdf/gmem.h @@ -3,7 +3,7 @@ * * Memory routines with out-of-memory checking. * - * Copyright 1996-2002 Glyph & Cog, LLC + * Copyright 1996-2003 Glyph & Cog, LLC */ #ifndef GMEM_H diff --git a/pdf2swf/xpdf/gtypes.h b/pdf2swf/xpdf/gtypes.h index 1879b88..9f64f57 100644 --- a/pdf2swf/xpdf/gtypes.h +++ b/pdf2swf/xpdf/gtypes.h @@ -3,7 +3,7 @@ * * Some useful simple types. * - * Copyright 1996-2002 Glyph & Cog, LLC + * Copyright 1996-2003 Glyph & Cog, LLC */ #ifndef GTYPES_H