From: kramm Date: Sat, 3 Dec 2005 14:28:56 +0000 (+0000) Subject: upgraded to xpdf-3.01pl1 X-Git-Tag: xpdf-3-01~4 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=85c46a8011c7fd5e4bda282266006c972ea7606b upgraded to xpdf-3.01pl1 --- diff --git a/pdf2swf/xpdf/Annot.cc b/pdf2swf/xpdf/Annot.cc index 245780d..68bfb6d 100644 --- a/pdf2swf/xpdf/Annot.cc +++ b/pdf2swf/xpdf/Annot.cc @@ -12,42 +12,26 @@ #pragma implementation #endif +#include #include "gmem.h" #include "Object.h" +#include "Catalog.h" #include "Gfx.h" +#include "Lexer.h" #include "Annot.h" //------------------------------------------------------------------------ // Annot //------------------------------------------------------------------------ -Annot::Annot(XRef *xrefA, Dict *dict) { +Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) { Object apObj, asObj, obj1, obj2; + GBool regen, isTextField; double t; ok = gFalse; xref = xrefA; - - if (dict->lookup("AP", &apObj)->isDict()) { - if (dict->lookup("AS", &asObj)->isName()) { - if (apObj.dictLookup("N", &obj1)->isDict()) { - if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { - obj2.copy(&appearance); - ok = gTrue; - } - obj2.free(); - } - obj1.free(); - } else { - if (apObj.dictLookupNF("N", &obj1)->isRef()) { - obj1.copy(&appearance); - ok = gTrue; - } - obj1.free(); - } - asObj.free(); - } - apObj.free(); + appearBuf = NULL; if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) { @@ -76,10 +60,204 @@ Annot::Annot(XRef *xrefA, Dict *dict) { xMax = yMax = 1; } obj1.free(); + + // check if field apperances need to be regenerated + regen = gFalse; + if (acroForm) { + acroForm->lookup("NeedAppearances", &obj1); + if (obj1.isBool() && obj1.getBool()) { + regen = gTrue; + } + obj1.free(); + } + + // check for a text-type field + isTextField = dict->lookup("FT", &obj1)->isName("Tx"); + obj1.free(); + +#if 0 //~ appearance stream generation is not finished yet + if (regen && isTextField) { + generateAppearance(acroForm, dict); + } else { +#endif + if (dict->lookup("AP", &apObj)->isDict()) { + if (dict->lookup("AS", &asObj)->isName()) { + if (apObj.dictLookup("N", &obj1)->isDict()) { + if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { + obj2.copy(&appearance); + ok = gTrue; + } else { + obj2.free(); + if (obj1.dictLookupNF("Off", &obj2)->isRef()) { + obj2.copy(&appearance); + ok = gTrue; + } + } + obj2.free(); + } + obj1.free(); + } else { + if (apObj.dictLookupNF("N", &obj1)->isRef()) { + obj1.copy(&appearance); + ok = gTrue; + } + obj1.free(); + } + asObj.free(); + } + apObj.free(); +#if 0 //~ appearance stream generation is not finished yet + } +#endif } Annot::~Annot() { appearance.free(); + if (appearBuf) { + delete appearBuf; + } +} + +void Annot::generateAppearance(Dict *acroForm, Dict *dict) { + MemStream *appearStream; + Object daObj, vObj, drObj, appearDict, obj1, obj2; + GString *daStr, *daStr1, *vStr, *s; + char buf[256]; + double fontSize; + int c; + int i0, i1; + + //~ DA can be inherited + if (dict->lookup("DA", &daObj)->isString()) { + daStr = daObj.getString(); + + // look for a font size + //~ may want to parse the DS entry in place of this (if it exists) + daStr1 = NULL; + fontSize = 10; + for (i1 = daStr->getLength() - 2; i1 >= 0; --i1) { + if (daStr->getChar(i1) == 'T' && daStr->getChar(i1+1) == 'f') { + for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ; + for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ; + if (i0 >= 0) { + ++i0; + ++i1; + s = new GString(daStr, i0, i1 - i0); + fontSize = atof(s->getCString()); + delete s; + + // autosize the font + if (fontSize == 0) { + fontSize = 0.67 * (yMax - yMin); + daStr1 = new GString(daStr, 0, i0); + sprintf(buf, "%.2f", fontSize); + daStr1->append(buf); + daStr1->append(daStr->getCString() + i1, + daStr->getLength() - i1); + } + } + break; + } + } + + // build the appearance stream contents + appearBuf = new GString(); + appearBuf->append("/Tx BMC\n"); + appearBuf->append("q BT\n"); + appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n"); + if (dict->lookup("V", &vObj)->isString()) { + //~ handle quadding -- this requires finding the font and using + //~ the encoding and char widths + sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize); + appearBuf->append(buf); + sprintf(buf, "%g TL\n", fontSize); + appearBuf->append(buf); + vStr = vObj.getString(); + i0 = 0; + while (i0 < vStr->getLength()) { + for (i1 = i0; + i1 < vStr->getLength() && + vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r'; + ++i1) ; + if (i0 > 0) { + appearBuf->append("T*\n"); + } + appearBuf->append('('); + for (; i0 < i1; ++i0) { + c = vStr->getChar(i0); + if (c == '(' || c == ')' || c == '\\') { + appearBuf->append('\\'); + appearBuf->append(c); + } else if (c < 0x20 || c >= 0x80) { + sprintf(buf, "\\%03o", c); + appearBuf->append(buf); + } else { + appearBuf->append(c); + } + } + appearBuf->append(") Tj\n"); + if (i1 + 1 < vStr->getLength() && + vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') { + i0 = i1 + 2; + } else { + i0 = i1 + 1; + } + } + } + vObj.free(); + appearBuf->append("ET Q\n"); + appearBuf->append("EMC\n"); + + // build the appearance stream dictionary + appearDict.initDict(xref); + appearDict.dictAdd(copyString("Length"), + obj1.initInt(appearBuf->getLength())); + appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form")); + obj1.initArray(xref); + obj1.arrayAdd(obj2.initReal(0)); + obj1.arrayAdd(obj2.initReal(0)); + obj1.arrayAdd(obj2.initReal(xMax - xMin)); + obj1.arrayAdd(obj2.initReal(yMax - yMin)); + appearDict.dictAdd(copyString("BBox"), &obj1); + + // find the resource dictionary + dict->lookup("DR", &drObj); + if (!drObj.isDict()) { + dict->lookup("Parent", &obj1); + while (obj1.isDict()) { + drObj.free(); + obj1.dictLookup("DR", &drObj); + if (drObj.isDict()) { + break; + } + obj1.dictLookup("Parent", &obj2); + obj1.free(); + obj1 = obj2; + } + obj1.free(); + if (!drObj.isDict()) { + if (acroForm) { + drObj.free(); + acroForm->lookup("DR", &drObj); + } + } + } + if (drObj.isDict()) { + appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1)); + } + drObj.free(); + + // build the appearance stream + appearStream = new MemStream(appearBuf->getCString(), 0, + appearBuf->getLength(), &appearDict); + appearance.initStream(appearStream); + ok = gTrue; + + if (daStr1) { + delete daStr1; + } + } + daObj.free(); } void Annot::draw(Gfx *gfx) { @@ -95,7 +273,8 @@ void Annot::draw(Gfx *gfx) { // Annots //------------------------------------------------------------------------ -Annots::Annots(XRef *xref, Object *annotsObj) { +Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) { + Dict *acroForm; Annot *annot; Object obj1; int size; @@ -105,14 +284,16 @@ Annots::Annots(XRef *xref, Object *annotsObj) { size = 0; nAnnots = 0; + acroForm = catalog->getAcroForm()->isDict() ? + catalog->getAcroForm()->getDict() : NULL; if (annotsObj->isArray()) { for (i = 0; i < annotsObj->arrayGetLength(); ++i) { if (annotsObj->arrayGet(i, &obj1)->isDict()) { - annot = new Annot(xref, obj1.getDict()); + annot = new Annot(xref, acroForm, obj1.getDict()); if (annot->isOk()) { if (nAnnots >= size) { size += 16; - annots = (Annot **)grealloc(annots, size * sizeof(Annot *)); + annots = (Annot **)greallocn(annots, size, sizeof(Annot *)); } annots[nAnnots++] = annot; } else { diff --git a/pdf2swf/xpdf/Annot.h b/pdf2swf/xpdf/Annot.h index 89dde0f..e5fd841 100644 --- a/pdf2swf/xpdf/Annot.h +++ b/pdf2swf/xpdf/Annot.h @@ -16,6 +16,7 @@ #endif class XRef; +class Catalog; class Gfx; //------------------------------------------------------------------------ @@ -25,7 +26,7 @@ class Gfx; class Annot { public: - Annot(XRef *xrefA, Dict *dict); + Annot(XRef *xrefA, Dict *acroForm, Dict *dict); ~Annot(); GBool isOk() { return ok; } @@ -35,10 +36,13 @@ public: Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); } private: + + void generateAppearance(Dict *acroForm, Dict *dict); XRef *xref; // the xref table for this PDF file Object appearance; // a reference to the Form XObject stream // for the normal appearance + GString *appearBuf; double xMin, yMin, // annotation rectangle xMax, yMax; GBool ok; @@ -52,7 +56,7 @@ class Annots { public: // Extract non-link annotations from array of annotations. - Annots(XRef *xref, Object *annotsObj); + Annots(XRef *xref, Catalog *catalog, Object *annotsObj); ~Annots(); diff --git a/pdf2swf/xpdf/Array.cc b/pdf2swf/xpdf/Array.cc index a6c6db1..10ded14 100644 --- a/pdf2swf/xpdf/Array.cc +++ b/pdf2swf/xpdf/Array.cc @@ -44,7 +44,7 @@ void Array::add(Object *elem) { } else { size *= 2; } - elems = (Object *)grealloc(elems, size * sizeof(Object)); + elems = (Object *)greallocn(elems, size, sizeof(Object)); } elems[length] = *elem; ++length; diff --git a/pdf2swf/xpdf/BuiltinFont.cc b/pdf2swf/xpdf/BuiltinFont.cc index a687e73..ce98957 100644 --- a/pdf2swf/xpdf/BuiltinFont.cc +++ b/pdf2swf/xpdf/BuiltinFont.cc @@ -24,7 +24,7 @@ BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) { int i, h; size = sizeA; - tab = (BuiltinFontWidth **)gmalloc(size * sizeof(BuiltinFontWidth *)); + tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *)); for (i = 0; i < size; ++i) { tab[i] = NULL; } diff --git a/pdf2swf/xpdf/CMap.cc b/pdf2swf/xpdf/CMap.cc index 25f3af7..303cf09 100644 --- a/pdf2swf/xpdf/CMap.cc +++ b/pdf2swf/xpdf/CMap.cc @@ -49,7 +49,7 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA, PSTokenizer *pst; char tok1[256], tok2[256], tok3[256]; int n1, n2, n3; - Guint start, end; + Guint start, end, code; if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) { @@ -99,6 +99,30 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA, } } pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincidchar")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcidchar")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcidchar")) { + error(-1, "Illegal entry in cidchar block in CMap"); + break; + } + if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' && + n1 >= 4 && (n1 & 1) == 0)) { + error(-1, "Illegal entry in cidchar block in CMap"); + continue; + } + tok1[n1 - 1] = '\0'; + if (sscanf(tok1 + 1, "%x", &code) != 1) { + error(-1, "Illegal entry in cidchar block in CMap"); + continue; + } + n1 = (n1 - 2) / 2; + cmap->addCIDs(code, code, n1, (CID)atoi(tok2)); + } + pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "begincidrange")) { while (pst->getToken(tok1, sizeof(tok1), &n1)) { if (!strcmp(tok1, "endcidrange")) { @@ -138,7 +162,7 @@ CMap::CMap(GString *collectionA, GString *cMapNameA) { collection = collectionA; cMapName = cMapNameA; wMode = 0; - vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); + vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (i = 0; i < 256; ++i) { vector[i].isVector = gFalse; vector[i].cid = 0; @@ -182,7 +206,7 @@ void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) { if (!dest[i].isVector) { dest[i].isVector = gTrue; dest[i].vector = - (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); + (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (j = 0; j < 256; ++j) { dest[i].vector[j].isVector = gFalse; dest[i].vector[j].cid = 0; @@ -213,7 +237,7 @@ void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, if (!vec[i].isVector) { vec[i].isVector = gTrue; vec[i].vector = - (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry)); + (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (j = 0; j < 256; ++j) { vec[i].vector[j].isVector = gFalse; vec[i].vector[j].cid = 0; @@ -234,7 +258,7 @@ void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { for (i = nBytes - 1; i >= 1; --i) { byte = (start >> (8 * i)) & 0xff; if (!vec[byte].isVector) { - error(-1, "Invalid CID (%*x - %*x) in CMap", + error(-1, "Invalid CID (%0*x - %0*x) in CMap", 2*nBytes, start, 2*nBytes, end); return; } @@ -243,7 +267,7 @@ void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { cid = firstCID; for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) { if (vec[byte].isVector) { - error(-1, "Invalid CID (%*x - %*x) in CMap", + error(-1, "Invalid CID (%0*x - %0*x) in CMap", 2*nBytes, start, 2*nBytes, end); } else { vec[byte].cid = cid; diff --git a/pdf2swf/xpdf/CMap.h b/pdf2swf/xpdf/CMap.h index eff2a81..c321a57 100644 --- a/pdf2swf/xpdf/CMap.h +++ b/pdf2swf/xpdf/CMap.h @@ -73,7 +73,7 @@ private: CMapVectorEntry *vector; // vector for first byte (NULL for // identity CMap) int refCnt; -#ifdef MULTITHREADED +#if MULTITHREADED GMutex mutex; #endif }; diff --git a/pdf2swf/xpdf/Catalog.cc b/pdf2swf/xpdf/Catalog.cc index c645fd0..fd235d6 100644 --- a/pdf2swf/xpdf/Catalog.cc +++ b/pdf2swf/xpdf/Catalog.cc @@ -64,8 +64,8 @@ Catalog::Catalog(XRef *xrefA) { } pagesSize = numPages0 = (int)obj.getNum(); obj.free(); - pages = (Page **)gmalloc(pagesSize * sizeof(Page *)); - pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref)); + pages = (Page **)gmallocn(pagesSize, sizeof(Page *)); + pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref)); for (i = 0; i < pagesSize; ++i) { pages[i] = NULL; pageRefs[i].num = -1; @@ -105,6 +105,9 @@ Catalog::Catalog(XRef *xrefA) { // get the outline dictionary catDict.dictLookup("Outlines", &outline); + // get the AcroForm dictionary + catDict.dictLookup("AcroForm", &acroForm); + catDict.free(); return; @@ -139,6 +142,7 @@ Catalog::~Catalog() { metadata.free(); structTreeRoot.free(); outline.free(); + acroForm.free(); } GString *Catalog::readMetadata() { @@ -191,8 +195,8 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { } if (start >= pagesSize) { pagesSize += 32; - pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *)); - pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref)); + pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *)); + pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref)); for (j = pagesSize - 32; j < pagesSize; ++j) { pages[j] = NULL; pageRefs[j].num = -1; @@ -216,7 +220,6 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { } else { error(-1, "Kid object (page %d) is wrong type (%s)", start+1, kid.getTypeName()); - goto err2; } kid.free(); } diff --git a/pdf2swf/xpdf/Catalog.h b/pdf2swf/xpdf/Catalog.h index 8ab7c61..c38f109 100644 --- a/pdf2swf/xpdf/Catalog.h +++ b/pdf2swf/xpdf/Catalog.h @@ -67,6 +67,8 @@ public: Object *getOutline() { return &outline; } + Object *getAcroForm() { return &acroForm; } + private: XRef *xref; // the xref table for this PDF file @@ -80,6 +82,7 @@ private: Object metadata; // metadata stream Object structTreeRoot; // structure tree root dictionary Object outline; // outline dictionary + Object acroForm; // AcroForm dictionary GBool ok; // true if catalog is valid int readPageTree(Dict *pages, PageAttrs *attrs, int start); diff --git a/pdf2swf/xpdf/CharCodeToUnicode.cc b/pdf2swf/xpdf/CharCodeToUnicode.cc index 2e2ad47..3702a16 100644 --- a/pdf2swf/xpdf/CharCodeToUnicode.cc +++ b/pdf2swf/xpdf/CharCodeToUnicode.cc @@ -70,13 +70,13 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName, } size = 32768; - mapA = (Unicode *)gmalloc(size * sizeof(Unicode)); + mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); mapLenA = 0; while (getLine(buf, sizeof(buf), f)) { if (mapLenA == size) { size *= 2; - mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode)); + mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); } if (sscanf(buf, "%x", &u) == 1) { mapA[mapLenA] = u; @@ -115,7 +115,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( } size = 4096; - mapA = (Unicode *)gmalloc(size * sizeof(Unicode)); + mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); memset(mapA, 0, size * sizeof(Unicode)); len = 0; sMapA = NULL; @@ -152,7 +152,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( while (u0 >= size) { size *= 2; } - mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode)); + mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode)); } if (n == 1) { @@ -162,7 +162,7 @@ CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( if (sMapLenA == sMapSizeA) { sMapSizeA += 16; sMapA = (CharCodeToUnicodeString *) - grealloc(sMapA, sMapSizeA * sizeof(CharCodeToUnicodeString)); + greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString)); } sMapA[sMapLenA].c = u0; for (i = 0; i < n; ++i) { @@ -251,7 +251,7 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); continue; } - addMapping(code1, tok2 + 1, n2 - 1, 0); + addMapping(code1, tok2 + 1, n2 - 2, 0); } pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "beginbfrange")) { @@ -320,7 +320,7 @@ void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, if (code >= mapLen) { oldLen = mapLen; mapLen = (code + 256) & ~255; - map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode)); + map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode)); for (i = oldLen; i < mapLen; ++i) { map[i] = 0; } @@ -335,7 +335,7 @@ void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, if (sMapLen >= sMapSize) { sMapSize = sMapSize + 16; sMap = (CharCodeToUnicodeString *) - grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); + greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); } map[code] = 0; sMap[sMapLen].c = code; @@ -357,7 +357,7 @@ CharCodeToUnicode::CharCodeToUnicode(GString *tagA) { tag = tagA; mapLen = 256; - map = (Unicode *)gmalloc(mapLen * sizeof(Unicode)); + map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); for (i = 0; i < mapLen; ++i) { map[i] = 0; } @@ -376,7 +376,7 @@ CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA, tag = tagA; mapLen = mapLenA; if (copyMap) { - map = (Unicode *)gmalloc(mapLen * sizeof(Unicode)); + map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); memcpy(map, mapA, mapLen * sizeof(Unicode)); } else { map = mapA; @@ -433,23 +433,30 @@ GBool CharCodeToUnicode::match(GString *tagA) { } void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) { - int i; + int i, j; if (len == 1) { map[c] = u[0]; } else { - map[c] = 0; - if (sMapLen == sMapSize) { - sMapSize += 8; - sMap = (CharCodeToUnicodeString *) - grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString)); + for (i = 0; i < sMapLen; ++i) { + if (sMap[i].c == c) { + break; + } } - sMap[sMapLen].c = c; - sMap[sMapLen].len = len; - for (i = 0; i < len && i < maxUnicodeString; ++i) { - sMap[sMapLen].u[i] = u[i]; + if (i == sMapLen) { + if (sMapLen == sMapSize) { + sMapSize += 8; + sMap = (CharCodeToUnicodeString *) + greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); + } + ++sMapLen; + } + map[c] = 0; + sMap[i].c = c; + sMap[i].len = len; + for (j = 0; j < len && j < maxUnicodeString; ++j) { + sMap[i].u[j] = u[j]; } - ++sMapLen; } } @@ -480,7 +487,7 @@ CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) { int i; size = sizeA; - cache = (CharCodeToUnicode **)gmalloc(size * sizeof(CharCodeToUnicode *)); + cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *)); for (i = 0; i < size; ++i) { cache[i] = NULL; } diff --git a/pdf2swf/xpdf/CharCodeToUnicode.h b/pdf2swf/xpdf/CharCodeToUnicode.h index 605e2bd..04852ae 100644 --- a/pdf2swf/xpdf/CharCodeToUnicode.h +++ b/pdf2swf/xpdf/CharCodeToUnicode.h @@ -67,6 +67,10 @@ public: // Map a CharCode to Unicode. int mapToUnicode(CharCode c, Unicode *u, int size); + // Return the mapping's length, i.e., one more than the max char + // code supported by the mapping. + CharCode getLength() { return mapLen; } + private: void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); @@ -83,7 +87,7 @@ private: CharCodeToUnicodeString *sMap; int sMapLen, sMapSize; int refCnt; -#ifdef MULTITHREADED +#if MULTITHREADED GMutex mutex; #endif }; diff --git a/pdf2swf/xpdf/Decrypt.cc b/pdf2swf/xpdf/Decrypt.cc index dab0750..91eb452 100644 --- a/pdf2swf/xpdf/Decrypt.cc +++ b/pdf2swf/xpdf/Decrypt.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include "gmem.h" #include "Decrypt.h" @@ -65,7 +66,8 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, - Guchar *fileKey, GBool *ownerPasswordOk) { + Guchar *fileKey, GBool encryptMetadata, + GBool *ownerPasswordOk) { Guchar test[32], test2[32]; GString *userPassword2; Guchar fState[256]; @@ -110,7 +112,8 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, } userPassword2 = new GString((char *)test2, 32); if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword2, fileKey)) { + permissions, fileID, userPassword2, fileKey, + encryptMetadata)) { *ownerPasswordOk = gTrue; delete userPassword2; return gTrue; @@ -120,13 +123,15 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, // try using the supplied user password return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword, fileKey); + permissions, fileID, userPassword, fileKey, + encryptMetadata); } GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey) { + GString *userPassword, Guchar *fileKey, + GBool encryptMetadata) { Guchar *buf; Guchar test[32]; Guchar fState[256]; @@ -136,7 +141,7 @@ GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, GBool ok; // generate file key - buf = (Guchar *)gmalloc(68 + fileID->getLength()); + buf = (Guchar *)gmalloc(72 + fileID->getLength()); if (userPassword) { len = userPassword->getLength(); if (len < 32) { @@ -154,7 +159,14 @@ GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, buf[66] = (permissions >> 16) & 0xff; buf[67] = (permissions >> 24) & 0xff; memcpy(buf + 68, fileID->getCString(), fileID->getLength()); - md5(buf, 68 + fileID->getLength(), fileKey); + len = 68 + fileID->getLength(); + if (!encryptMetadata) { + buf[len++] = 0xff; + buf[len++] = 0xff; + buf[len++] = 0xff; + buf[len++] = 0xff; + } + md5(buf, len, fileKey); if (encRevision == 3) { for (i = 0; i < 50; ++i) { md5(fileKey, keyLength, fileKey); diff --git a/pdf2swf/xpdf/Decrypt.h b/pdf2swf/xpdf/Decrypt.h index 71f9457..2beba58 100644 --- a/pdf2swf/xpdf/Decrypt.h +++ b/pdf2swf/xpdf/Decrypt.h @@ -43,14 +43,16 @@ public: GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, - Guchar *fileKey, GBool *ownerPasswordOk); + Guchar *fileKey, GBool encryptMetadata, + GBool *ownerPasswordOk); private: static GBool makeFileKey2(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey); + GString *userPassword, Guchar *fileKey, + GBool encryptMetadata); int objKeyLength; Guchar objKey[21]; diff --git a/pdf2swf/xpdf/Dict.cc b/pdf2swf/xpdf/Dict.cc index 6274590..dd1517f 100644 --- a/pdf2swf/xpdf/Dict.cc +++ b/pdf2swf/xpdf/Dict.cc @@ -47,7 +47,7 @@ void Dict::add(char *key, Object *val) { } else { size *= 2; } - entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry)); + entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry)); } entries[length].key = key; entries[length].val = *val; diff --git a/pdf2swf/xpdf/FoFiTrueType.cc b/pdf2swf/xpdf/FoFiTrueType.cc index a4cf43c..46b61ec 100644 --- a/pdf2swf/xpdf/FoFiTrueType.cc +++ b/pdf2swf/xpdf/FoFiTrueType.cc @@ -13,6 +13,7 @@ #endif #include +#include #include "gtypes.h" #include "gmem.h" #include "GString.h" @@ -77,6 +78,10 @@ //------------------------------------------------------------------------ +#define ttcfTag 0x74746366 + +//------------------------------------------------------------------------ + struct TrueTypeTable { Guint tag; Guint checksum; @@ -102,6 +107,7 @@ struct TrueTypeLoca { #define cmapTag 0x636d6170 #define glyfTag 0x676c7966 +#define headTag 0x68656164 #define locaTag 0x6c6f6361 #define nameTag 0x6e616d65 #define postTag 0x706f7374 @@ -153,9 +159,11 @@ static T42Table t42Tables[nT42Tables] = { { "vhea", gFalse }, { "vmtx", gFalse } }; -#define t42HeadTable 3 -#define t42LocaTable 6 -#define t42GlyfTable 2 +#define t42HeadTable 3 +#define t42LocaTable 6 +#define t42GlyfTable 2 +#define t42VheaTable 9 +#define t42VmtxTable 10 //------------------------------------------------------------------------ @@ -276,7 +284,9 @@ FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA): FoFiTrueType::~FoFiTrueType() { gfree(tables); gfree(cmaps); - delete nameToGID; + if (nameToGID) { + delete nameToGID; + } } int FoFiTrueType::getNumCmaps() { @@ -432,7 +442,7 @@ void FoFiTrueType::convertToType42(char *psName, char **encoding, // write the guts of the dictionary cvtEncoding(encoding, outputFunc, outputStream); cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); - cvtSfnts(outputFunc, outputStream, NULL); + cvtSfnts(outputFunc, outputStream, NULL, gFalse); // end the dictionary and define the font (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); @@ -440,6 +450,7 @@ void FoFiTrueType::convertToType42(char *psName, char **encoding, void FoFiTrueType::convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream) { char buf[512]; @@ -540,7 +551,7 @@ void FoFiTrueType::convertToCIDType2(char *psName, (*outputFunc)(outputStream, " end readonly def\n", 19); // write the guts of the dictionary - cvtSfnts(outputFunc, outputStream, NULL); + cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics); // end the dictionary and define the font (*outputFunc)(outputStream, @@ -549,6 +560,7 @@ void FoFiTrueType::convertToCIDType2(char *psName, } void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream) { char buf[512]; @@ -557,7 +569,7 @@ void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, // write the Type 42 sfnts array sfntsName = (new GString(psName))->append("_sfnts"); - cvtSfnts(outputFunc, outputStream, sfntsName); + cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics); delete sfntsName; // write the descendant Type 42 fonts @@ -620,18 +632,28 @@ void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, } void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, - void *outputStream) { - static char cmapTab[20] = { + void *outputStream, char *name, + Gushort *codeToGID) { + // this substitute cmap table maps char codes 0000-ffff directly to + // glyphs 0000-ffff + static char cmapTab[36] = { 0, 0, // table version number 0, 1, // number of encoding tables 0, 1, // platform ID 0, 0, // encoding ID 0, 0, 0, 12, // offset of subtable - 0, 0, // subtable format - 0, 1, // subtable length - 0, 1, // subtable version - 0, // map char 0 -> glyph 0 - 0 // pad to multiple of four bytes + 0, 4, // subtable format + 0, 24, // subtable length + 0, 0, // subtable version + 0, 2, // segment count * 2 + 0, 2, // 2 * 2 ^ floor(log2(segCount)) + 0, 0, // floor(log2(segCount)) + 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) + (char)0xff, (char)0xff, // endCount[0] + 0, 0, // reserved + 0, 0, // startCount[0] + 0, 0, // idDelta[0] + 0, 0 // pad to a mulitple of four bytes }; static char nameTab[8] = { 0, 0, // format @@ -654,9 +676,11 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, int nZeroLengthTables; TrueTypeLoca *locaTable; TrueTypeTable *newTables; - int nNewTables, cmapIdx, cmapLen, glyfLen; + char *newNameTab, *newCmapTab; + int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; + Guint locaChecksum, glyfChecksum, fileChecksum; char *tableDir; - char locaBuf[4]; + char locaBuf[4], checksumBuf[4]; GBool ok; Guint t; int pos, i, j, k, n; @@ -667,7 +691,7 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, missingPost = seekTable("post") < 0; // read the loca table, check to see if it's sorted - locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca)); + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); unsortedLoca = gFalse; i = seekTable("loca"); pos = tables[i].offset; @@ -710,7 +734,7 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, // if nothing is broken, just write the TTF file as is if (!missingCmap && !missingName && !missingPost && !unsortedLoca && - !badCmapLen && nZeroLengthTables == 0) { + !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) { (*outputFunc)(outputStream, (char *)file, len); goto done1; } @@ -742,46 +766,206 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, glyfLen = pos; } + // compute checksums for the loca and glyf tables + locaChecksum = glyfChecksum = 0; + if (unsortedLoca) { + if (locaFmt) { + for (j = 0; j <= nGlyphs; ++j) { + locaChecksum += locaTable[j].newOffset; + } + } else { + for (j = 0; j <= nGlyphs; j += 2) { + locaChecksum += locaTable[j].newOffset << 16; + if (j + 1 <= nGlyphs) { + locaChecksum += locaTable[j+1].newOffset; + } + } + } + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + glyfChecksum += computeTableChecksum(file + pos + k, n); + } + } + } + } + + // construct the new name table + if (name) { + n = strlen(name); + newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; + newNameTab = (char *)gmalloc(newNameLen); + memset(newNameTab, 0, newNameLen); + newNameTab[0] = 0; // format selector + newNameTab[1] = 0; + newNameTab[2] = 0; // number of name records + newNameTab[3] = 4; + newNameTab[4] = 0; // offset to start of string storage + newNameTab[5] = 6 + 4*12; + next = 0; + for (i = 0; i < 4; ++i) { + newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft + newNameTab[6 + i*12 + 1] = 3; + newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode + newNameTab[6 + i*12 + 3] = 1; + newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English + newNameTab[6 + i*12 + 5] = 0x09; + newNameTab[6 + i*12 + 6] = 0; // name ID + newNameTab[6 + i*12 + 7] = i + 1; + newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length + newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); + newNameTab[6 + i*12 + 10] = next >> 8; // string offset + newNameTab[6 + i*12 + 11] = next & 0xff; + if (i+1 == 2) { + memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); + next += 14; + } else { + for (j = 0; j < n; ++j) { + newNameTab[6 + 4*12 + next + 2*j] = 0; + newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; + } + next += 2*n; + } + } + } else { + newNameLen = 0; + newNameTab = NULL; + } + + // construct the new cmap table + if (codeToGID) { + newCmapLen = 44 + 256 * 2; + newCmapTab = (char *)gmalloc(newCmapLen); + newCmapTab[0] = 0; // table version number = 0 + newCmapTab[1] = 0; + newCmapTab[2] = 0; // number of encoding tables = 1 + newCmapTab[3] = 1; + newCmapTab[4] = 0; // platform ID = Microsoft + newCmapTab[5] = 3; + newCmapTab[6] = 0; // encoding ID = Unicode + newCmapTab[7] = 1; + newCmapTab[8] = 0; // offset of subtable + newCmapTab[9] = 0; + newCmapTab[10] = 0; + newCmapTab[11] = 12; + newCmapTab[12] = 0; // subtable format = 4 + newCmapTab[13] = 4; + newCmapTab[14] = 0x02; // subtable length + newCmapTab[15] = 0x20; + newCmapTab[16] = 0; // subtable version = 0 + newCmapTab[17] = 0; + newCmapTab[18] = 0; // segment count * 2 + newCmapTab[19] = 4; + newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) + newCmapTab[21] = 4; + newCmapTab[22] = 0; // floor(log2(segCount)) + newCmapTab[23] = 1; + newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) + newCmapTab[25] = 0; + newCmapTab[26] = 0x00; // endCount[0] + newCmapTab[27] = (char)0xff; + newCmapTab[28] = (char)0xff; // endCount[1] + newCmapTab[29] = (char)0xff; + newCmapTab[30] = 0; // reserved + newCmapTab[31] = 0; + newCmapTab[32] = 0x00; // startCount[0] + newCmapTab[33] = 0x00; + newCmapTab[34] = (char)0xff; // startCount[1] + newCmapTab[35] = (char)0xff; + newCmapTab[36] = 0; // idDelta[0] + newCmapTab[37] = 0; + newCmapTab[38] = 0; // idDelta[1] + newCmapTab[39] = 1; + newCmapTab[40] = 0; // idRangeOffset[0] + newCmapTab[41] = 4; + newCmapTab[42] = 0; // idRangeOffset[1] + newCmapTab[43] = 0; + for (i = 0; i < 256; ++i) { + newCmapTab[44 + 2*i] = codeToGID[i] >> 8; + newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; + } + } else { + newCmapLen = 0; + newCmapTab = NULL; + } + // construct the new table directory: // - keep all original tables with non-zero length // - fix the cmap table's length, if necessary // - add missing tables // - sort the table by tag // - compute new table positions, including 4-byte alignment + // - (re)compute table checksums nNewTables = nTables - nZeroLengthTables + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + (missingPost ? 1 : 0); - newTables = (TrueTypeTable *)gmalloc(nNewTables * sizeof(TrueTypeTable)); + newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); j = 0; for (i = 0; i < nTables; ++i) { if (tables[i].len > 0) { newTables[j] = tables[i]; newTables[j].origOffset = tables[i].offset; - if (newTables[j].tag == cmapTag && badCmapLen) { + if (checkRegion(tables[i].offset, newTables[i].len)) { + newTables[j].checksum = + computeTableChecksum(file + tables[i].offset, tables[i].len); + if (tables[i].tag == headTag) { + // don't include the file checksum + newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); + } + } + if (newTables[j].tag == cmapTag && codeToGID) { + newTables[j].len = newCmapLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + } else if (newTables[j].tag == cmapTag && badCmapLen) { newTables[j].len = cmapLen; } else if (newTables[j].tag == locaTag && unsortedLoca) { newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); + newTables[j].checksum = locaChecksum; } else if (newTables[j].tag == glyfTag && unsortedLoca) { newTables[j].len = glyfLen; + newTables[j].checksum = glyfChecksum; + } else if (newTables[j].tag == nameTag && name) { + newTables[j].len = newNameLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); } ++j; } } if (missingCmap) { newTables[j].tag = cmapTag; - newTables[j].checksum = 0; //~ should compute the checksum - newTables[j].len = sizeof(cmapTab); + if (codeToGID) { + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + newTables[j].len = newCmapLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, + sizeof(cmapTab)); + newTables[j].len = sizeof(cmapTab); + } ++j; } if (missingName) { newTables[j].tag = nameTag; - newTables[j].checksum = 0; //~ should compute the checksum - newTables[j].len = sizeof(nameTab); + if (name) { + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + newTables[j].len = newNameLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, + sizeof(nameTab)); + newTables[j].len = sizeof(nameTab); + } ++j; } if (missingPost) { newTables[j].tag = postTag; - newTables[j].checksum = 0; //~ should compute the checksum + newTables[j].checksum = computeTableChecksum((Guchar *)postTab, + sizeof(postTab)); newTables[j].len = sizeof(postTab); ++j; } @@ -835,10 +1019,38 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); + // compute the file checksum + fileChecksum = computeTableChecksum((Guchar *)tableDir, + 12 + nNewTables * 16); + for (i = 0; i < nNewTables; ++i) { + fileChecksum += newTables[i].checksum; + } + fileChecksum = 0xb1b0afba - fileChecksum; + // write the tables for (i = 0; i < nNewTables; ++i) { - if (newTables[i].tag == cmapTag && missingCmap) { + if (newTables[i].tag == headTag) { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); + checksumBuf[0] = fileChecksum >> 24; + checksumBuf[1] = fileChecksum >> 16; + checksumBuf[2] = fileChecksum >> 8; + checksumBuf[3] = fileChecksum; + (*outputFunc)(outputStream, checksumBuf, 4); + (*outputFunc)(outputStream, + (char *)file + newTables[i].origOffset + 12, + newTables[i].len - 12); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } else if (newTables[i].tag == cmapTag && codeToGID) { + (*outputFunc)(outputStream, newCmapTab, newTables[i].len); + } else if (newTables[i].tag == cmapTag && missingCmap) { (*outputFunc)(outputStream, cmapTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && name) { + (*outputFunc)(outputStream, newNameTab, newTables[i].len); } else if (newTables[i].tag == nameTag && missingName) { (*outputFunc)(outputStream, nameTab, newTables[i].len); } else if (newTables[i].tag == postTag && missingPost) { @@ -890,6 +1102,8 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } } + gfree(newCmapTab); + gfree(newNameTab); gfree(tableDir); gfree(newTables); done1: @@ -974,7 +1188,8 @@ void FoFiTrueType::cvtCharStrings(char **encoding, } void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, - void *outputStream, GString *name) { + void *outputStream, GString *name, + GBool needVerticalMetrics) { Guchar headData[54]; TrueTypeLoca *locaTable; Guchar *locaData; @@ -984,6 +1199,28 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, Guint checksum; int nNewTables; int length, pos, glyfPos, i, j, k; + Guchar vheaTab[36] = { + 0, 1, 0, 0, // table version number + 0, 0, // ascent + 0, 0, // descent + 0, 0, // reserved + 0, 0, // max advance height + 0, 0, // min top side bearing + 0, 0, // min bottom side bearing + 0, 0, // y max extent + 0, 0, // caret slope rise + 0, 1, // caret slope run + 0, 0, // caret offset + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // metric data format + 0, 1 // number of advance heights in vmtx table + }; + Guchar *vmtxTab; + GBool needVhea, needVmtx; + int advance; // construct the 'head' table, zero out the font checksum i = seekTable("head"); @@ -1001,7 +1238,7 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, // 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)); + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); i = seekTable("loca"); pos = tables[i].offset; ok = gTrue; @@ -1031,7 +1268,7 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, } // construct the new 'loca' table - locaData = (Guchar *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); + locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); for (i = 0; i <= nGlyphs; ++i) { pos = locaTable[i].newOffset; if (locaFmt) { @@ -1053,6 +1290,22 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, ++nNewTables; } } + vmtxTab = NULL; // make gcc happy + advance = 0; // make gcc happy + if (needVerticalMetrics) { + needVhea = seekTable("vhea") < 0; + needVmtx = seekTable("vmtx") < 0; + if (needVhea || needVmtx) { + i = seekTable("head"); + advance = getU16BE(tables[i].offset + 18, &ok); // units per em + if (needVhea) { + ++nNewTables; + } + if (needVmtx) { + ++nNewTables; + } + } + } // construct the new table headers, including table checksums // (pad each table out to a multiple of 4 bytes) @@ -1088,6 +1341,21 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, if (checkRegion(tables[j].offset, length)) { checksum = computeTableChecksum(file + tables[j].offset, length); } + } else if (needVerticalMetrics && i == t42VheaTable) { + vheaTab[10] = advance / 256; // max advance height + vheaTab[11] = advance % 256; + length = sizeof(vheaTab); + checksum = computeTableChecksum(vheaTab, length); + } else if (needVerticalMetrics && i == t42VmtxTable) { + length = 4 + (nGlyphs - 1) * 4; + vmtxTab = (Guchar *)gmalloc(length); + vmtxTab[0] = advance / 256; + vmtxTab[1] = advance % 256; + for (j = 2; j < length; j += 2) { + vmtxTab[j] = 0; + vmtxTab[j+1] = 0; + } + checksum = computeTableChecksum(vmtxTab, length); } else if (t42Tables[i].required) { //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", //~ t42Tables[i].tag); @@ -1193,6 +1461,11 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, checkRegion(tables[j].offset, tables[j].len)) { dumpString(file + tables[j].offset, tables[j].len, outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VheaTable) { + dumpString(vheaTab, length, outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VmtxTable) { + dumpString(vmtxTab, length, outputFunc, outputStream); + gfree(vmtxTab); } } } @@ -1263,17 +1536,32 @@ Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { } void FoFiTrueType::parse() { + Guint topTag; int pos, i, j; parsedOk = gTrue; + // look for a collection (TTC) + topTag = getU32BE(0, &parsedOk); + if (!parsedOk) { + return; + } + if (topTag == ttcfTag) { + pos = getU32BE(12, &parsedOk); + if (!parsedOk) { + return; + } + } else { + pos = 0; + } + // read the table directory - nTables = getU16BE(4, &parsedOk); + nTables = getU16BE(pos + 4, &parsedOk); if (!parsedOk) { return; } - tables = (TrueTypeTable *)gmalloc(nTables * sizeof(TrueTypeTable)); - pos = 12; + tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); + pos += 12; for (i = 0; i < nTables; ++i) { tables[i].tag = getU32BE(pos, &parsedOk); tables[i].checksum = getU32BE(pos + 4, &parsedOk); @@ -1309,7 +1597,7 @@ void FoFiTrueType::parse() { if (!parsedOk) { return; } - cmaps = (TrueTypeCmap *)gmalloc(nCmaps * sizeof(TrueTypeCmap)); + cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); for (j = 0; j < nCmaps; ++j) { cmaps[j].platform = getU16BE(pos, &parsedOk); cmaps[j].encoding = getU16BE(pos + 2, &parsedOk); @@ -1343,25 +1631,45 @@ void FoFiTrueType::parse() { return; } - // read the post table - readPostTable(); + // make sure the loca table is sane (correct length and entries are + // in bounds) + i = seekTable("loca"); + if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { + parsedOk = gFalse; + return; + } + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk); + } else { + pos = getU16BE(tables[i].offset + j*2, &parsedOk); + } + if (pos < 0 || pos > len) { + parsedOk = gFalse; + } + } if (!parsedOk) { return; } + + // read the post table + readPostTable(); } void FoFiTrueType::readPostTable() { GString *name; int tablePos, postFmt, stringIdx, stringPos; + GBool ok; int i, j, n, m; + ok = gTrue; if ((i = seekTable("post")) < 0) { return; } tablePos = tables[i].offset; - postFmt = getU32BE(tablePos, &parsedOk); - if (!parsedOk) { - return; + postFmt = getU32BE(tablePos, &ok); + if (!ok) { + goto err; } if (postFmt == 0x00010000) { nameToGID = new GHash(gTrue); @@ -1370,9 +1678,9 @@ void FoFiTrueType::readPostTable() { } } else if (postFmt == 0x00020000) { nameToGID = new GHash(gTrue); - n = getU16BE(tablePos + 32, &parsedOk); - if (!parsedOk) { - return; + n = getU16BE(tablePos + 32, &ok); + if (!ok) { + goto err; } if (n > nGlyphs) { n = nGlyphs; @@ -1380,7 +1688,7 @@ void FoFiTrueType::readPostTable() { stringIdx = 0; stringPos = tablePos + 34 + 2*n; for (i = 0; i < n; ++i) { - j = getU16BE(tablePos + 34 + 2*i, &parsedOk); + j = getU16BE(tablePos + 34 + 2*i, &ok); if (j < 258) { nameToGID->removeInt(macGlyphNames[j]); nameToGID->add(new GString(macGlyphNames[j]), i); @@ -1389,15 +1697,14 @@ void FoFiTrueType::readPostTable() { if (j != stringIdx) { for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; stringIdx < j; - ++stringIdx, stringPos += 1 + getU8(stringPos, &parsedOk)) ; - if (!parsedOk) { - return; + ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; + if (!ok) { + goto err; } } - m = getU8(stringPos, &parsedOk); - if (!parsedOk || !checkRegion(stringPos + 1, m)) { - parsedOk = gFalse; - return; + m = getU8(stringPos, &ok); + if (!ok || !checkRegion(stringPos + 1, m)) { + goto err; } name = new GString((char *)&file[stringPos + 1], m); nameToGID->removeInt(name); @@ -1409,9 +1716,9 @@ void FoFiTrueType::readPostTable() { } else if (postFmt == 0x00028000) { nameToGID = new GHash(gTrue); for (i = 0; i < nGlyphs; ++i) { - j = getU8(tablePos + 32 + i, &parsedOk); - if (!parsedOk) { - return; + j = getU8(tablePos + 32 + i, &ok); + if (!ok) { + goto err; } if (j < 258) { nameToGID->removeInt(macGlyphNames[j]); @@ -1419,6 +1726,14 @@ void FoFiTrueType::readPostTable() { } } } + + return; + + err: + if (nameToGID) { + delete nameToGID; + nameToGID = NULL; + } } int FoFiTrueType::seekTable(char *tag) { diff --git a/pdf2swf/xpdf/FoFiTrueType.h b/pdf2swf/xpdf/FoFiTrueType.h index ea05eec..f7b09d6 100644 --- a/pdf2swf/xpdf/FoFiTrueType.h +++ b/pdf2swf/xpdf/FoFiTrueType.h @@ -18,6 +18,7 @@ #include "gtypes.h" #include "FoFiBase.h" +class GString; class GHash; struct TrueTypeTable; struct TrueTypeCmap; @@ -83,6 +84,7 @@ public: // font). The array maps CIDs to GIDs; it has // entries. void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 0 (but non-CID) composite font, suitable for @@ -91,12 +93,16 @@ public: // table in the font). The array maps CIDs to GIDs; it has // entries. void convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, 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); + // various other errors. If is non-NULL, the font is renamed + // to . If is non-NULL, the font is re-encoded, + // using a Windows Unicode cmap. If is NULL and the font is + // complete and correct, it will be written unmodified. + void writeTTF(FoFiOutputFunc outputFunc, void *outputStream, + char *name = NULL, Gushort *codeToGID = NULL); private: @@ -109,7 +115,8 @@ private: FoFiOutputFunc outputFunc, void *outputStream); void cvtSfnts(FoFiOutputFunc outputFunc, - void *outputStream, GString *name); + void *outputStream, GString *name, + GBool needVerticalMetrics); void dumpString(Guchar *s, int length, FoFiOutputFunc outputFunc, void *outputStream); diff --git a/pdf2swf/xpdf/FoFiType1.cc b/pdf2swf/xpdf/FoFiType1.cc index fe54a63..a8a69fd 100644 --- a/pdf2swf/xpdf/FoFiType1.cc +++ b/pdf2swf/xpdf/FoFiType1.cc @@ -108,6 +108,9 @@ void FoFiType1::writeEncoded(char **newEncoding, for (line = getNextLine(line); line && strncmp(line, "readonly def", 12); line = getNextLine(line)) ; + if (line) { + line = getNextLine(line); + } } if (line) { (*outputFunc)(outputStream, line, ((char *)file + len) - line); @@ -156,13 +159,13 @@ void FoFiType1::parse() { encoding = fofiType1StandardEncoding; } else if (!encoding && !strncmp(line, "/Encoding 256 array", 19)) { - encoding = (char **)gmalloc(256 * sizeof(char *)); + encoding = (char **)gmallocn(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); + for (j = 0, line = getNextLine(line); + j < 300 && line && (line1 = getNextLine(line)); + ++j, line = line1) { if ((n = line1 - line) > 255) { n = 255; } @@ -187,20 +190,22 @@ void FoFiType1::parse() { } } } else { - if (strtok(buf, " \t") && - (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { - break; + p = strtok(buf, " \t\n\r"); + if (p) + { + if (!strcmp(p, "def")) break; + if (!strcmp(p, "readonly")) break; + // the spec does not says this but i'm mantaining old xpdf behaviour that accepts "foo def" as end of the encoding array + p = strtok(buf, " \t\n\r"); + if (p && !strcmp(p, "def")) break; } } - line = line1; } //~ check for getinterval/putinterval junk } else { line = getNextLine(line); } - - ++i; } parsed = gTrue; diff --git a/pdf2swf/xpdf/FoFiType1C.h b/pdf2swf/xpdf/FoFiType1C.h index e6f2b64..62649ed 100644 --- a/pdf2swf/xpdf/FoFiType1C.h +++ b/pdf2swf/xpdf/FoFiType1C.h @@ -51,6 +51,9 @@ struct Type1CTopDict { int paintType; int charstringType; double fontMatrix[6]; + GBool hasFontMatrix; // CID fonts are allowed to put their + // FontMatrix in the FD instead of the + // top dict int uniqueID; double fontBBox[4]; double strokeWidth; @@ -73,6 +76,8 @@ struct Type1CTopDict { #define type1CMaxStemSnap 12 struct Type1CPrivateDict { + double fontMatrix[6]; + GBool hasFontMatrix; int blueValues[type1CMaxBlueValues]; int nBlueValues; int otherBlues[type1CMaxOtherBlues]; @@ -221,6 +226,7 @@ private: 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 + GBool openPath; // true if there is an unclosed path }; #endif diff --git a/pdf2swf/xpdf/Function.cc b/pdf2swf/xpdf/Function.cc index 46b1912..f699641 100644 --- a/pdf2swf/xpdf/Function.cc +++ b/pdf2swf/xpdf/Function.cc @@ -185,7 +185,7 @@ void IdentityFunction::transform(double *in, double *out) { SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { Stream *str; - int nSamples, sampleBits; + int sampleBits; double sampleMul; Object obj1, obj2; Guint buf, bitMask; @@ -228,6 +228,10 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { obj2.free(); } obj1.free(); + idxMul[0] = n; + for (i = 1; i < m; ++i) { + idxMul[i] = idxMul[i-1] * sampleSize[i-1]; + } //----- BitsPerSample if (!dict->lookup("BitsPerSample", &obj1)->isInt()) { @@ -264,6 +268,10 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { } } obj1.free(); + for (i = 0; i < m; ++i) { + inputMul[i] = (encode[i][1] - encode[i][0]) / + (domain[i][1] - domain[i][0]); + } //----- Decode if (dict->lookup("Decode", &obj1)->isArray() && @@ -296,7 +304,7 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { nSamples = n; for (i = 0; i < m; ++i) nSamples *= sampleSize[i]; - samples = (double *)gmalloc(nSamples * sizeof(double)); + samples = (double *)gmallocn(nSamples, sizeof(double)); buf = 0; bits = 0; bitMask = (1 << sampleBits) - 1; @@ -342,37 +350,34 @@ SampledFunction::~SampledFunction() { } SampledFunction::SampledFunction(SampledFunction *func) { - int nSamples, i; - memcpy(this, func, sizeof(SampledFunction)); - - nSamples = n; - for (i = 0; i < m; ++i) { - nSamples *= sampleSize[i]; - } - samples = (double *)gmalloc(nSamples * sizeof(double)); + samples = (double *)gmallocn(nSamples, sizeof(double)); memcpy(samples, func->samples, nSamples * sizeof(double)); } void SampledFunction::transform(double *in, double *out) { double x; - int e[2][funcMaxInputs]; - double efrac[funcMaxInputs]; - double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs]; - int i, j, k, idx; + int e[funcMaxInputs][2]; + double efrac0[funcMaxInputs]; + double efrac1[funcMaxInputs]; + double s[1 << funcMaxInputs]; + int i, j, k, idx, t; // map input values into sample array for (i = 0; i < m; ++i) { - x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) * - (encode[i][1] - encode[i][0]) + encode[i][0]; + x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0]; if (x < 0) { x = 0; } else if (x > sampleSize[i] - 1) { x = sampleSize[i] - 1; } - e[0][i] = (int)floor(x); - e[1][i] = (int)ceil(x); - efrac[i] = x - e[0][i]; + e[i][0] = (int)x; + if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) { + // this happens if in[i] = domain[i][1] + e[i][1] = e[i][0]; + } + efrac1[i] = x - e[i][0]; + efrac0[i] = 1 - efrac1[i]; } // for each output, do m-linear interpolation @@ -380,24 +385,22 @@ void SampledFunction::transform(double *in, double *out) { // pull 2^m values out of the sample array for (j = 0; j < (1<= 0; --k) { - idx = idx * sampleSize[k] + e[(j >> k) & 1][k]; + idx = i; + for (k = 0, t = j; k < m; ++k, t >>= 1) { + idx += idxMul[k] * (e[k][t & 1]); } - idx = idx * n + i; - s0[j] = samples[idx]; + s[j] = samples[idx]; } // do m sets of interpolations - for (j = 0; j < m; ++j) { - for (k = 0; k < (1 << (m - j)); k += 2) { - s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1]; + for (j = 0, t = (1<>= 1) { + for (k = 0; k < t; k += 2) { + s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1]; } - memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double)); } // map output value to range - out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; + out[i] = s[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; if (out[i] < range[i][0]) { out[i] = range[i][0]; } else if (out[i] > range[i][1]) { @@ -553,9 +556,9 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) { goto err1; } k = obj1.arrayGetLength(); - funcs = (Function **)gmalloc(k * sizeof(Function *)); - bounds = (double *)gmalloc((k + 1) * sizeof(double)); - encode = (double *)gmalloc(2 * k * sizeof(double)); + funcs = (Function **)gmallocn(k, sizeof(Function *)); + bounds = (double *)gmallocn(k + 1, sizeof(double)); + encode = (double *)gmallocn(2 * k, sizeof(double)); for (i = 0; i < k; ++i) { funcs[i] = NULL; } @@ -619,13 +622,13 @@ StitchingFunction::StitchingFunction(StitchingFunction *func) { int i; k = func->k; - funcs = (Function **)gmalloc(k * sizeof(Function *)); + funcs = (Function **)gmallocn(k, sizeof(Function *)); for (i = 0; i < k; ++i) { funcs[i] = func->funcs[i]->copy(); } - bounds = (double *)gmalloc((k + 1) * sizeof(double)); + bounds = (double *)gmallocn(k + 1, sizeof(double)); memcpy(bounds, func->bounds, (k + 1) * sizeof(double)); - encode = (double *)gmalloc(2 * k * sizeof(double)); + encode = (double *)gmallocn(2 * k, sizeof(double)); memcpy(encode, func->encode, 2 * k * sizeof(double)); ok = gTrue; } @@ -916,10 +919,14 @@ double PSStack::popNum() { void PSStack::copy(int n) { int i; + if (sp + n > psStackSize) { + error(-1, "Stack underflow in PostScript function"); + return; + } if (!checkOverflow(n)) { return; } - for (i = sp + n - 1; i <= sp; ++i) { + for (i = sp + n - 1; i >= sp; --i) { stack[i - n] = stack[i]; } sp -= n; @@ -990,6 +997,7 @@ PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) { str = funcObj->getStream(); //----- parse the function + codeString = new GString(); str->reset(); if (!(tok = getToken(str)) || tok->cmp("{")) { error(-1, "Expected '{' at start of PostScript function"); @@ -1015,12 +1023,14 @@ PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) { PostScriptFunction::PostScriptFunction(PostScriptFunction *func) { memcpy(this, func, sizeof(PostScriptFunction)); - code = (PSObject *)gmalloc(codeSize * sizeof(PSObject)); + code = (PSObject *)gmallocn(codeSize, sizeof(PSObject)); memcpy(code, func->code, codeSize * sizeof(PSObject)); + codeString = func->codeString->copy(); } PostScriptFunction::~PostScriptFunction() { gfree(code); + delete codeString; } void PostScriptFunction::transform(double *in, double *out) { @@ -1174,6 +1184,9 @@ GString *PostScriptFunction::getToken(Stream *str) { s = new GString(); do { c = str->getChar(); + if (c != EOF) { + codeString->append(c); + } } while (c != EOF && isspace(c)); if (c == '{' || c == '}') { s->append((char)c); @@ -1185,6 +1198,7 @@ GString *PostScriptFunction::getToken(Stream *str) { break; } str->getChar(); + codeString->append(c); } } else { while (1) { @@ -1194,6 +1208,7 @@ GString *PostScriptFunction::getToken(Stream *str) { break; } str->getChar(); + codeString->append(c); } } return s; @@ -1202,7 +1217,7 @@ GString *PostScriptFunction::getToken(Stream *str) { void PostScriptFunction::resizeCode(int newSize) { if (newSize >= codeSize) { codeSize += 64; - code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject)); + code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject)); } } diff --git a/pdf2swf/xpdf/Function.h b/pdf2swf/xpdf/Function.h index 0ceb035..bfaf83e 100644 --- a/pdf2swf/xpdf/Function.h +++ b/pdf2swf/xpdf/Function.h @@ -45,10 +45,24 @@ public: virtual Function *copy() = 0; + // Return the function type: + // -1 : identity + // 0 : sampled + // 2 : exponential + // 3 : stitching + // 4 : PostScript + virtual int getType() = 0; + // Return size of input and output tuples. int getInputSize() { return m; } int getOutputSize() { return n; } + double getDomainMin(int i) { return domain[i][0]; } + double getDomainMax(int i) { return domain[i][1]; } + double getRangeMin(int i) { return range[i][0]; } + double getRangeMax(int i) { return range[i][1]; } + GBool getHasRange() { return hasRange; } + // Transform an input tuple into an output tuple. virtual void transform(double *in, double *out) = 0; @@ -74,6 +88,7 @@ public: IdentityFunction(); virtual ~IdentityFunction(); virtual Function *copy() { return new IdentityFunction(); } + virtual int getType() { return -1; } virtual void transform(double *in, double *out); virtual GBool isOk() { return gTrue; } @@ -90,9 +105,17 @@ public: SampledFunction(Object *funcObj, Dict *dict); virtual ~SampledFunction(); virtual Function *copy() { return new SampledFunction(this); } + virtual int getType() { return 0; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + int getSampleSize(int i) { return sampleSize[i]; } + double getEncodeMin(int i) { return encode[i][0]; } + double getEncodeMax(int i) { return encode[i][1]; } + double getDecodeMin(int i) { return decode[i][0]; } + double getDecodeMax(int i) { return decode[i][1]; } + double *getSamples() { return samples; } + private: SampledFunction(SampledFunction *func); @@ -103,7 +126,11 @@ private: encode[funcMaxInputs][2]; double // min and max values for range decoder decode[funcMaxOutputs][2]; + double // input multipliers + inputMul[funcMaxInputs]; + int idxMul[funcMaxInputs]; // sample array index multipliers double *samples; // the samples + int nSamples; // size of the samples array GBool ok; }; @@ -117,9 +144,14 @@ public: ExponentialFunction(Object *funcObj, Dict *dict); virtual ~ExponentialFunction(); virtual Function *copy() { return new ExponentialFunction(this); } + virtual int getType() { return 2; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + double *getC0() { return c0; } + double *getC1() { return c1; } + double getE() { return e; } + private: ExponentialFunction(ExponentialFunction *func); @@ -140,9 +172,15 @@ public: StitchingFunction(Object *funcObj, Dict *dict); virtual ~StitchingFunction(); virtual Function *copy() { return new StitchingFunction(this); } + virtual int getType() { return 3; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + int getNumFuncs() { return k; } + Function *getFunc(int i) { return funcs[i]; } + double *getBounds() { return bounds; } + double *getEncode() { return encode; } + private: StitchingFunction(StitchingFunction *func); @@ -164,9 +202,12 @@ public: PostScriptFunction(Object *funcObj, Dict *dict); virtual ~PostScriptFunction(); virtual Function *copy() { return new PostScriptFunction(this); } + virtual int getType() { return 4; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } + GString *getCodeString() { return codeString; } + private: PostScriptFunction(PostScriptFunction *func); @@ -175,6 +216,7 @@ private: void resizeCode(int newSize); void exec(PSStack *stack, int codePtr); + GString *codeString; PSObject *code; int codeSize; GBool ok; diff --git a/pdf2swf/xpdf/GHash.cc b/pdf2swf/xpdf/GHash.cc index 1dd0e26..b51a764 100644 --- a/pdf2swf/xpdf/GHash.cc +++ b/pdf2swf/xpdf/GHash.cc @@ -39,7 +39,7 @@ GHash::GHash(GBool deleteKeysA) { deleteKeys = deleteKeysA; size = 7; - tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *)); + tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); for (h = 0; h < size; ++h) { tab[h] = NULL; } @@ -101,6 +101,30 @@ void GHash::add(GString *key, int val) { ++len; } +void GHash::replace(GString *key, void *val) { + GHashBucket *p; + int h; + + if ((p = find(key, &h))) { + p->val.p = val; + delete key; + } else { + add(key, val); + } +} + +void GHash::replace(GString *key, int val) { + GHashBucket *p; + int h; + + if ((p = find(key, &h))) { + p->val.i = val; + delete key; + } else { + add(key, val); + } +} + void *GHash::lookup(GString *key) { GHashBucket *p; int h; @@ -292,7 +316,7 @@ void GHash::expand() { oldSize = size; oldTab = tab; size = 2*size + 1; - tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *)); + tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); for (h = 0; h < size; ++h) { tab[h] = NULL; } diff --git a/pdf2swf/xpdf/GHash.h b/pdf2swf/xpdf/GHash.h index 4a6e08d..31aba93 100644 --- a/pdf2swf/xpdf/GHash.h +++ b/pdf2swf/xpdf/GHash.h @@ -30,6 +30,8 @@ public: ~GHash(); void add(GString *key, void *val); void add(GString *key, int val); + void replace(GString *key, void *val); + void replace(GString *key, int val); void *lookup(GString *key); int lookupInt(GString *key); void *lookup(char *key); diff --git a/pdf2swf/xpdf/GList.cc b/pdf2swf/xpdf/GList.cc index 9534232..fb5fd62 100644 --- a/pdf2swf/xpdf/GList.cc +++ b/pdf2swf/xpdf/GList.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include #include "gmem.h" #include "GList.h" @@ -22,14 +23,14 @@ GList::GList() { size = 8; - data = (void **)gmalloc(size * sizeof(void*)); + data = (void **)gmallocn(size, sizeof(void*)); length = 0; inc = 0; } GList::GList(int sizeA) { size = sizeA; - data = (void **)gmalloc(size * sizeof(void*)); + data = (void **)gmallocn(size, sizeof(void*)); length = 0; inc = 0; } @@ -81,12 +82,16 @@ void *GList::del(int i) { return p; } +void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) { + qsort(data, length, sizeof(void *), cmp); +} + void GList::expand() { size += (inc > 0) ? inc : size; - data = (void **)grealloc(data, size * sizeof(void*)); + data = (void **)greallocn(data, size, sizeof(void*)); } void GList::shrink() { size -= (inc > 0) ? inc : size/2; - data = (void **)grealloc(data, size * sizeof(void*)); + data = (void **)greallocn(data, size, sizeof(void*)); } diff --git a/pdf2swf/xpdf/GList.h b/pdf2swf/xpdf/GList.h index 4c52489..e4d8ff8 100644 --- a/pdf2swf/xpdf/GList.h +++ b/pdf2swf/xpdf/GList.h @@ -58,6 +58,11 @@ public: // Assumes 0 <= i < length. void *del(int i); + // Sort the list accoring to the given comparison function. + // NB: this sorts an array of pointers, so the pointer args need to + // be double-dereferenced. + void sort(int (*cmp)(const void *ptr1, const void *ptr2)); + //----- control // Set allocation increment to . If inc > 0, that many diff --git a/pdf2swf/xpdf/GString.cc b/pdf2swf/xpdf/GString.cc index 7653fd0..049dcf3 100644 --- a/pdf2swf/xpdf/GString.cc +++ b/pdf2swf/xpdf/GString.cc @@ -35,7 +35,12 @@ inline void GString::resize(int length1) { s = new char[size(length1)]; } else if (size(length1) != size(length)) { s1 = new char[size(length1)]; - memcpy(s1, s, length + 1); + if (length1 < length) { + memcpy(s1, s, length1); + s1[length1] = '\0'; + } else { + memcpy(s1, s, length + 1); + } delete[] s; s = s1; } @@ -234,3 +239,81 @@ GString *GString::lowerCase() { } return this; } + +int GString::cmp(GString *str) { + int n1, n2, i, x; + char *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + return n1 - n2; +} + +int GString::cmpN(GString *str, int n) { + int n1, n2, i, x; + char *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; + i < n1 && i < n2 && i < n; + ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i == n) { + return 0; + } + return n1 - n2; +} + +int GString::cmp(const char *sA) { + int n1, i, x; + const char *p1, *p2; + + n1 = length; + for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i < n1) { + return 1; + } + if (*p2) { + return -1; + } + return 0; +} + +int GString::cmpN(const char *sA, int n) { + int n1, i, x; + const char *p1, *p2; + + n1 = length; + for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i == n) { + return 0; + } + if (i < n1) { + return 1; + } + if (*p2) { + return -1; + } + return 0; +} diff --git a/pdf2swf/xpdf/GString.h b/pdf2swf/xpdf/GString.h index 2083802..f4ff7c6 100644 --- a/pdf2swf/xpdf/GString.h +++ b/pdf2swf/xpdf/GString.h @@ -17,8 +17,6 @@ #pragma interface #endif -#include - class GString { public: @@ -83,11 +81,10 @@ public: GString *lowerCase(); // Compare two strings: -1:< 0:= +1:> - // These functions assume the strings do not contain null characters. - int cmp(GString *str) { return strcmp(s, str->getCString()); } - int cmpN(GString *str, int n) { return strncmp(s, str->getCString(), n); } - int cmp(const char *sA) { return strcmp(s, sA); } - int cmpN(const char *sA, int n) { return strncmp(s, sA, n); } + int cmp(GString *str); + int cmpN(GString *str, int n); + int cmp(const char *sA); + int cmpN(const char *sA, int n); private: diff --git a/pdf2swf/xpdf/Gfx.h b/pdf2swf/xpdf/Gfx.h index 2e40a57..168206d 100644 --- a/pdf2swf/xpdf/Gfx.h +++ b/pdf2swf/xpdf/Gfx.h @@ -33,6 +33,9 @@ class GfxShading; class GfxFunctionShading; class GfxAxialShading; class GfxRadialShading; +class GfxGouraudTriangleShading; +class GfxPatchMeshShading; +struct GfxPatch; class GfxState; struct GfxColor; class Gfx; @@ -101,14 +104,14 @@ public: // Constructor for regular output. Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, - double hDPI, double vDPI, PDFRectangle *box, GBool crop, + double hDPI, double vDPI, PDFRectangle *box, 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, PDFRectangle *cropBox, GBool (*abortCheckCbkA)(void *data) = NULL, void *abortCheckCbkDataA = NULL); @@ -128,6 +131,9 @@ public: // Restore graphics state. void restoreState(); + // Get the current graphics state object. + GfxState *getState() { return state; } + private: XRef *xref; // the xref table for this PDF file @@ -216,6 +222,13 @@ private: GfxColor *colors, int depth); void doAxialShFill(GfxAxialShading *shading); void doRadialShFill(GfxRadialShading *shading); + void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading); + void gouraudFillTriangle(double x0, double y0, GfxColor *color0, + double x1, double y1, GfxColor *color1, + double x2, double y2, GfxColor *color2, + int nComps, int depth); + void doPatchMeshShFill(GfxPatchMeshShading *shading); + void fillPatch(GfxPatch *patch, int nComps, int depth); void doEndPath(); // path clipping operators diff --git a/pdf2swf/xpdf/GfxFont.cc b/pdf2swf/xpdf/GfxFont.cc index ed9f076..a4581c0 100644 --- a/pdf2swf/xpdf/GfxFont.cc +++ b/pdf2swf/xpdf/GfxFont.cc @@ -55,8 +55,8 @@ static StdFontMapEntry stdFontMap[] = { { "Arial-ItalicMT", "Helvetica-Oblique" }, { "ArialMT", "Helvetica" }, { "Courier,Bold", "Courier-Bold" }, - { "Courier,Italic", "Courier-Oblique" }, { "Courier,BoldItalic", "Courier-BoldOblique" }, + { "Courier,Italic", "Courier-Oblique" }, { "CourierNew", "Courier" }, { "CourierNew,Bold", "Courier-Bold" }, { "CourierNew,BoldItalic", "Courier-BoldOblique" }, @@ -191,19 +191,19 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { // look for embedded font file if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) { - if (type == fontType1) { - embFontID = obj2.getRef(); - } else { + embFontID = obj2.getRef(); + if (type != fontType1) { error(-1, "Mismatch between font type and embedded font file"); + type = fontType1; } } obj2.free(); if (embFontID.num == -1 && obj1.dictLookupNF("FontFile2", &obj2)->isRef()) { - if (type == fontTrueType || type == fontCIDType2) { - embFontID = obj2.getRef(); - } else { + embFontID = obj2.getRef(); + if (type != fontTrueType && type != fontCIDType2) { error(-1, "Mismatch between font type and embedded font file"); + type = type == fontCIDType0 ? fontCIDType2 : fontTrueType; } } obj2.free(); @@ -212,33 +212,29 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { if (obj2.fetch(xref, &obj3)->isStream()) { obj3.streamGetDict()->lookup("Subtype", &obj4); if (obj4.isName("Type1")) { - if (type == fontType1) { - embFontID = obj2.getRef(); - } else { + embFontID = obj2.getRef(); + if (type != fontType1) { error(-1, "Mismatch between font type and embedded font file"); + type = fontType1; } } else if (obj4.isName("Type1C")) { - if (type == fontType1) { - type = fontType1C; - embFontID = obj2.getRef(); - } else if (type == fontType1C) { - embFontID = obj2.getRef(); - } else { + embFontID = obj2.getRef(); + if (type != fontType1 && type != fontType1C) { error(-1, "Mismatch between font type and embedded font file"); } + type = fontType1C; } else if (obj4.isName("TrueType")) { - if (type == fontTrueType) { - embFontID = obj2.getRef(); - } else { + embFontID = obj2.getRef(); + if (type != fontTrueType) { error(-1, "Mismatch between font type and embedded font file"); + type = fontTrueType; } } else if (obj4.isName("CIDFontType0C")) { - if (type == fontCIDType0) { - type = fontCIDType0C; - embFontID = obj2.getRef(); - } else { + embFontID = obj2.getRef(); + if (type != fontCIDType0) { error(-1, "Mismatch between font type and embedded font file"); } + type = fontCIDType0C; } else { error(-1, "Unknown embedded font type '%s'", obj4.isName() ? obj4.getName() : "???"); @@ -399,6 +395,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Dict *fontDict): GfxFont(tagA, idA, nameA) { + GString *name2; BuiltinFont *builtinFont; char **baseEnc; GBool baseEncFromFontFile; @@ -424,20 +421,30 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // do font name substitution for various aliases of the Base 14 font // names if (name) { + name2 = name->copy(); + i = 0; + while (i < name2->getLength()) { + if (name2->getChar(i) == ' ') { + name2->del(i); + } else { + ++i; + } + } a = 0; b = sizeof(stdFontMap) / sizeof(StdFontMapEntry); - // invariant: stdFontMap[a].altName <= name < stdFontMap[b].altName + // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName while (b - a > 1) { m = (a + b) / 2; - if (name->cmp(stdFontMap[m].altName) >= 0) { + if (name2->cmp(stdFontMap[m].altName) >= 0) { a = m; } else { b = m; } } - if (!name->cmp(stdFontMap[a].altName)) { + if (!name2->cmp(stdFontMap[a].altName)) { name = new GString(stdFontMap[a].properName); } + delete name2; } // is it a built-in font? @@ -468,6 +475,17 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // get info from font descriptor readFontDescriptor(xref, fontDict); + // for non-embedded fonts, don't trust the ascent/descent/bbox + // values from the font descriptor + if (builtinFont && embFontID.num < 0) { + ascent = 0.001 * builtinFont->ascent; + descent = 0.001 * builtinFont->descent; + fontBBox[0] = 0.001 * builtinFont->bbox[0]; + fontBBox[1] = 0.001 * builtinFont->bbox[1]; + fontBBox[2] = 0.001 * builtinFont->bbox[2]; + fontBBox[3] = 0.001 * builtinFont->bbox[3]; + } + // look for an external font file findExtFontFile(); @@ -513,7 +531,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // 2. embedded or external font file // 3. default: // - builtin --> builtin encoding - // - TrueType --> MacRomanEncoding + // - TrueType --> WinAnsiEncoding // - others --> StandardEncoding // and then add a list of differences (if any) from // FontDict.Encoding.Differences. @@ -536,9 +554,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } else if (obj2.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; - } else if (obj2.isName("StandardEncoding")) { - hasEncoding = gTrue; - baseEnc = standardEncoding; } obj2.free(); } else if (obj1.isName("MacRomanEncoding")) { @@ -551,9 +566,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } else if (obj1.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; - } else if (obj1.isName("StandardEncoding")) { - hasEncoding = gTrue; - baseEnc = standardEncoding; } // check embedded or external font file for base encoding @@ -607,7 +619,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // get default base encoding if (!baseEnc) { - if (builtinFont) { + if (builtinFont && embFontID.num < 0) { baseEnc = builtinFont->defaultBaseEnc; hasEncoding = gTrue; } else if (type == fontTrueType) { @@ -899,7 +911,7 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { Unicode u; int code, i, n; - map = (Gushort *)gmalloc(256 * sizeof(Gushort)); + map = (Gushort *)gmallocn(256, sizeof(Gushort)); for (i = 0; i < 256; ++i) { map[i] = 0; } @@ -919,7 +931,8 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { // 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: + // 2. If the PDF font does not have an encoding or the PDF font is + // symbolic: // 2a. If the TrueType font has a Macintosh Roman cmap, use it, // and use char codes directly (possibly with an offset of // 0xf000). @@ -953,6 +966,8 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { useUnicode = gTrue; } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { cmap = msSymbolCmap; + } else if ((flags & fontSymbolic) && macRomanCmap >= 0) { + cmap = macRomanCmap; } else if (macRomanCmap >= 0) { cmap = macRomanCmap; useMacRoman = gTrue; @@ -979,7 +994,9 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { // map Unicode through the cmap } else if (useUnicode) { for (i = 0; i < 256; ++i) { - if ((n = ctu->mapToUnicode((CharCode)i, &u, 1))) { + if (((charName = enc[i]) && + (u = globalParams->mapNameToUnicode(charName))) || + (n = ctu->mapToUnicode((CharCode)i, &u, 1))) { map[i] = ff->mapCodeToGID(cmap, u); } } @@ -1043,8 +1060,11 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GString *collection, *cMapName; Object desFontDictObj; Object obj1, obj2, obj3, obj4, obj5, obj6; + CharCodeToUnicode *utu; + CharCode c; + Unicode uBuf[8]; int c1, c2; - int excepsSize, i, j, k; + int excepsSize, i, j, k, n; ascent = 0.95; descent = -0.35; @@ -1126,9 +1146,27 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, if (!(ctu = globalParams->getCIDToUnicode(collection))) { error(-1, "Unknown character collection '%s'", collection->getCString()); - delete collection; - goto err2; + // fall-through, assuming the Identity mapping -- this appears + // to match Adobe's behavior + } + } + } + + // look for a Unicode-to-Unicode mapping + if (name && (utu = globalParams->getUnicodeToUnicode(name))) { + if (ctu) { + for (c = 0; c < ctu->getLength(); ++c) { + n = ctu->mapToUnicode(c, uBuf, 8); + if (n >= 1) { + n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (n >= 1) { + ctu->setMapping(c, uBuf, n); + } + } } + utu->decRefCnt(); + } else { + ctu = utu; } } @@ -1158,13 +1196,13 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, if (obj1.isStream()) { cidToGIDLen = 0; i = 64; - cidToGID = (Gushort *)gmalloc(i * sizeof(Gushort)); + cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort)); obj1.streamReset(); while ((c1 = obj1.streamGetChar()) != EOF && (c2 = obj1.streamGetChar()) != EOF) { if (cidToGIDLen == i) { i *= 2; - cidToGID = (Gushort *)grealloc(cidToGID, i * sizeof(Gushort)); + cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort)); } cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2); } @@ -1194,8 +1232,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, if (widths.nExceps == excepsSize) { excepsSize += 16; widths.exceps = (GfxFontCIDWidthExcep *) - grealloc(widths.exceps, - excepsSize * sizeof(GfxFontCIDWidthExcep)); + greallocn(widths.exceps, + excepsSize, sizeof(GfxFontCIDWidthExcep)); } widths.exceps[widths.nExceps].first = obj2.getInt(); widths.exceps[widths.nExceps].last = obj3.getInt(); @@ -1210,8 +1248,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, if (widths.nExceps + obj3.arrayGetLength() > excepsSize) { excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15; widths.exceps = (GfxFontCIDWidthExcep *) - grealloc(widths.exceps, - excepsSize * sizeof(GfxFontCIDWidthExcep)); + greallocn(widths.exceps, + excepsSize, sizeof(GfxFontCIDWidthExcep)); } j = obj2.getInt(); for (k = 0; k < obj3.arrayGetLength(); ++k) { @@ -1267,8 +1305,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, if (widths.nExcepsV == excepsSize) { excepsSize += 16; widths.excepsV = (GfxFontCIDWidthExcepV *) - grealloc(widths.excepsV, - excepsSize * sizeof(GfxFontCIDWidthExcepV)); + greallocn(widths.excepsV, + excepsSize, sizeof(GfxFontCIDWidthExcepV)); } widths.excepsV[widths.nExcepsV].first = obj2.getInt(); widths.excepsV[widths.nExcepsV].last = obj3.getInt(); @@ -1288,8 +1326,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, excepsSize = (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15; widths.excepsV = (GfxFontCIDWidthExcepV *) - grealloc(widths.excepsV, - excepsSize * sizeof(GfxFontCIDWidthExcepV)); + greallocn(widths.excepsV, + excepsSize, sizeof(GfxFontCIDWidthExcepV)); } j = obj2.getInt(); for (k = 0; k < obj3.arrayGetLength(); k += 3) { @@ -1452,7 +1490,7 @@ GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { Ref r; numFonts = fontDict->getLength(); - fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *)); + fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *)); for (i = 0; i < numFonts; ++i) { fontDict->getValNF(i, &obj1); obj1.fetch(xref, &obj2); diff --git a/pdf2swf/xpdf/GfxState.h b/pdf2swf/xpdf/GfxState.h index f747a83..e1d6801 100644 --- a/pdf2swf/xpdf/GfxState.h +++ b/pdf2swf/xpdf/GfxState.h @@ -25,21 +25,80 @@ class PDFRectangle; class GfxShading; //------------------------------------------------------------------------ +// GfxBlendMode +//------------------------------------------------------------------------ + +enum GfxBlendMode { + gfxBlendNormal, + gfxBlendMultiply, + gfxBlendScreen, + gfxBlendOverlay, + gfxBlendDarken, + gfxBlendLighten, + gfxBlendColorDodge, + gfxBlendColorBurn, + gfxBlendHardLight, + gfxBlendSoftLight, + gfxBlendDifference, + gfxBlendExclusion, + gfxBlendHue, + gfxBlendSaturation, + gfxBlendColor, + gfxBlendLuminosity +}; + +//------------------------------------------------------------------------ +// GfxColorComp +//------------------------------------------------------------------------ + +// 16.16 fixed point color component +typedef int GfxColorComp; + +#define gfxColorComp1 0x10000 + +static inline GfxColorComp dblToCol(double x) { + return (GfxColorComp)(x * gfxColorComp1); +} + +static inline double colToDbl(GfxColorComp x) { + return (double)x / (double)gfxColorComp1; +} + +static inline GfxColorComp byteToCol(Guchar x) { + // (x / 255) << 16 = (0.0000000100000001... * x) << 16 + // = ((x << 8) + (x) + (x >> 8) + ...) << 16 + // = (x << 8) + (x) + (x >> 7) + // [for rounding] + return (GfxColorComp)((x << 8) + x + (x >> 7)); +} + +static inline Guchar colToByte(GfxColorComp x) { + // 255 * x + 0.5 = 256 * x - x + 0x8000 + return (Guchar)(((x << 8) - x + 0x8000) >> 16); +} + +//------------------------------------------------------------------------ // GfxColor //------------------------------------------------------------------------ #define gfxColorMaxComps funcMaxOutputs struct GfxColor { - double c[gfxColorMaxComps]; + GfxColorComp c[gfxColorMaxComps]; }; //------------------------------------------------------------------------ +// GfxGray +//------------------------------------------------------------------------ + +typedef GfxColorComp GfxGray; + +//------------------------------------------------------------------------ // GfxRGB //------------------------------------------------------------------------ struct GfxRGB { - double r, g, b; + GfxColorComp r, g, b; }; //------------------------------------------------------------------------ @@ -47,7 +106,7 @@ struct GfxRGB { //------------------------------------------------------------------------ struct GfxCMYK { - double c, m, y, k; + GfxColorComp c, m, y, k; }; //------------------------------------------------------------------------ @@ -82,7 +141,7 @@ public: static GfxColorSpace *parse(Object *csObj); // Convert to gray, RGB, or CMYK. - virtual void getGray(GfxColor *color, double *gray) = 0; + virtual void getGray(GfxColor *color, GfxGray *gray) = 0; virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0; virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0; @@ -115,7 +174,7 @@ public: virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceGray; } - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -139,7 +198,7 @@ public: // Construct a CalGray color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -173,7 +232,7 @@ public: virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceRGB; } - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -197,7 +256,7 @@ public: // Construct a CalRGB color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -220,7 +279,7 @@ private: double whiteX, whiteY, whiteZ; // white point double blackX, blackY, blackZ; // black point double gammaR, gammaG, gammaB; // gamma values - double mat[9]; // ABC -> XYZ transform matrix + double mat[9]; // ABC -> XYZ transform matrix }; //------------------------------------------------------------------------ @@ -235,7 +294,7 @@ public: virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; } - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -259,7 +318,7 @@ public: // Construct a Lab color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -304,7 +363,7 @@ public: // Construct an ICCBased color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -340,7 +399,7 @@ public: // Construct a Lab color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -378,7 +437,7 @@ public: // Construct a Separation color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -411,7 +470,7 @@ public: // Construct a DeviceN color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -446,7 +505,7 @@ public: // Construct a Pattern color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr); - virtual void getGray(GfxColor *color, double *gray); + virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); @@ -599,6 +658,8 @@ public: void getDomain(double *x0A, double *y0A, double *x1A, double *y1A) { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } double *getMatrix() { return matrix; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } void getColor(double x, double y, GfxColor *color); private: @@ -632,9 +693,11 @@ public: { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } double getDomain0() { return t0; } double getDomain1() { return t1; } - void getColor(double t, GfxColor *color); GBool getExtend0() { return extend0; } GBool getExtend1() { return extend1; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double t, GfxColor *color); private: @@ -669,9 +732,11 @@ public: { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; } double getDomain0() { return t0; } double getDomain1() { return t1; } - void getColor(double t, GfxColor *color); GBool getExtend0() { return extend0; } GBool getExtend1() { return extend1; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double t, GfxColor *color); private: @@ -683,6 +748,77 @@ private: }; //------------------------------------------------------------------------ +// GfxGouraudTriangleShading +//------------------------------------------------------------------------ + +struct GfxGouraudVertex { + double x, y; + GfxColor color; +}; + +class GfxGouraudTriangleShading: public GfxShading { +public: + + GfxGouraudTriangleShading(int typeA, + GfxGouraudVertex *verticesA, int nVerticesA, + int (*trianglesA)[3], int nTrianglesA, + Function **funcsA, int nFuncsA); + GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading); + virtual ~GfxGouraudTriangleShading(); + + static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str); + + virtual GfxShading *copy(); + + int getNTriangles() { return nTriangles; } + void getTriangle(int i, double *x0, double *y0, GfxColor *color0, + double *x1, double *y1, GfxColor *color1, + double *x2, double *y2, GfxColor *color2); + +private: + + GfxGouraudVertex *vertices; + int nVertices; + int (*triangles)[3]; + int nTriangles; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ +// GfxPatchMeshShading +//------------------------------------------------------------------------ + +struct GfxPatch { + double x[4][4]; + double y[4][4]; + GfxColor color[2][2]; +}; + +class GfxPatchMeshShading: public GfxShading { +public: + + GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA, + Function **funcsA, int nFuncsA); + GfxPatchMeshShading(GfxPatchMeshShading *shading); + virtual ~GfxPatchMeshShading(); + + static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str); + + virtual GfxShading *copy(); + + int getNPatches() { return nPatches; } + GfxPatch *getPatch(int i) { return &patches[i]; } + +private: + + GfxPatch *patches; + int nPatches; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ // GfxImageColorMap //------------------------------------------------------------------------ @@ -713,7 +849,7 @@ public: double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; } // Convert an image pixel to a color. - void getGray(Guchar *x, double *gray); + void getGray(Guchar *x, GfxGray *gray); void getRGB(Guchar *x, GfxRGB *rgb); void getCMYK(Guchar *x, GfxCMYK *cmyk); void getColor(Guchar *x, GfxColor *color); @@ -727,7 +863,8 @@ private: int nComps; // number of components in a pixel GfxColorSpace *colorSpace2; // secondary color space int nComps2; // number of components in colorSpace2 - double *lookup; // lookup table + GfxColorComp * // lookup table + lookup[gfxColorMaxComps]; double // minimum values for each component decodeLow[gfxColorMaxComps]; double // max - min value for each component @@ -853,10 +990,10 @@ class GfxState { public: // Construct a default GfxState, for a device with resolution - // x , page box , page rotation , and + // x , page box , page rotation , and // coordinate system specified by . GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, - int rotate, GBool upsideDown); + int rotateA, GBool upsideDown); // Destructor. ~GfxState(); @@ -872,11 +1009,12 @@ public: double getY2() { return py2; } double getPageWidth() { return pageWidth; } double getPageHeight() { return pageHeight; } + int getRotate() { return rotate; } GfxColor *getFillColor() { return &fillColor; } GfxColor *getStrokeColor() { return &strokeColor; } - void getFillGray(double *gray) + void getFillGray(GfxGray *gray) { fillColorSpace->getGray(&fillColor, gray); } - void getStrokeGray(double *gray) + void getStrokeGray(GfxGray *gray) { strokeColorSpace->getGray(&strokeColor, gray); } void getFillRGB(GfxRGB *rgb) { fillColorSpace->getRGB(&fillColor, rgb); } @@ -890,8 +1028,11 @@ public: GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; } GfxPattern *getFillPattern() { return fillPattern; } GfxPattern *getStrokePattern() { return strokePattern; } + GfxBlendMode getBlendMode() { return blendMode; } double getFillOpacity() { return fillOpacity; } double getStrokeOpacity() { return strokeOpacity; } + GBool getFillOverprint() { return fillOverprint; } + GBool getStrokeOverprint() { return strokeOverprint; } double getLineWidth() { return lineWidth; } void getLineDash(double **dash, int *length, double *start) { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; } @@ -952,8 +1093,11 @@ public: void setStrokeColor(GfxColor *color) { strokeColor = *color; } void setFillPattern(GfxPattern *pattern); void setStrokePattern(GfxPattern *pattern); + void setBlendMode(GfxBlendMode mode) { blendMode = mode; } void setFillOpacity(double opac) { fillOpacity = opac; } void setStrokeOpacity(double opac) { strokeOpacity = opac; } + void setFillOverprint(GBool op) { fillOverprint = op; } + void setStrokeOverprint(GBool op) { strokeOverprint = op; } void setLineWidth(double width) { lineWidth = width; } void setLineDash(double *dash, int length, double start); void setFlatness(int flatness1) { flatness = flatness1; } @@ -1006,11 +1150,15 @@ public: GfxState *restore(); GBool hasSaves() { return saved != NULL; } + // Misc + GBool parseBlendMode(Object *obj, GfxBlendMode *mode); + private: double ctm[6]; // coord transform matrix double px1, py1, px2, py2; // page corners (user coords) double pageWidth, pageHeight; // page size (pixels) + int rotate; // page rotation angle GfxColorSpace *fillColorSpace; // fill color space GfxColorSpace *strokeColorSpace; // stroke color space @@ -1018,8 +1166,11 @@ private: GfxColor strokeColor; // stroke color GfxPattern *fillPattern; // fill pattern GfxPattern *strokePattern; // stroke pattern + GfxBlendMode blendMode; // transparency blend mode double fillOpacity; // fill opacity double strokeOpacity; // stroke opacity + GBool fillOverprint; // fill overprint + GBool strokeOverprint; // stroke overprint double lineWidth; // line width double *lineDash; // line dash diff --git a/pdf2swf/xpdf/JArithmeticDecoder.cc b/pdf2swf/xpdf/JArithmeticDecoder.cc index fd29744..195b73e 100644 --- a/pdf2swf/xpdf/JArithmeticDecoder.cc +++ b/pdf2swf/xpdf/JArithmeticDecoder.cc @@ -22,7 +22,7 @@ JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) { contextSize = contextSizeA; - cxTab = (Guchar *)gmalloc(contextSize * sizeof(Guchar)); + cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar)); reset(); } @@ -89,24 +89,24 @@ int JArithmeticDecoder::switchTab[47] = { JArithmeticDecoder::JArithmeticDecoder() { str = NULL; -} - -JArithmeticDecoder::~JArithmeticDecoder() { - while (dataLen > 0) { - readByte(); - } + dataLen = 0; + limitStream = gFalse; } inline Guint JArithmeticDecoder::readByte() { - if (dataLen == 0) { - return 0xff; - } - if (dataLen > 0) { + if (limitStream) { --dataLen; + if (dataLen < 0) { + return 0xff; + } } return (Guint)str->getChar() & 0xff; } +JArithmeticDecoder::~JArithmeticDecoder() { + cleanup(); +} + void JArithmeticDecoder::start() { buf0 = readByte(); buf1 = readByte(); @@ -119,6 +119,28 @@ void JArithmeticDecoder::start() { a = 0x80000000; } +void JArithmeticDecoder::restart(int dataLenA) { + int oldDataLen; + + oldDataLen = dataLen; + dataLen = dataLenA; + if (oldDataLen == -1) { + buf1 = readByte(); + } else if (oldDataLen <= -2) { + buf0 = readByte(); + buf1 = readByte(); + } +} + +void JArithmeticDecoder::cleanup() { + if (limitStream) { + while (dataLen > 0) { + buf0 = buf1; + buf1 = readByte(); + } + } +} + int JArithmeticDecoder::decodeBit(Guint context, JArithmeticDecoderStats *stats) { int bit; diff --git a/pdf2swf/xpdf/JArithmeticDecoder.h b/pdf2swf/xpdf/JArithmeticDecoder.h index a348017..a40823d 100644 --- a/pdf2swf/xpdf/JArithmeticDecoder.h +++ b/pdf2swf/xpdf/JArithmeticDecoder.h @@ -53,12 +53,29 @@ public: JArithmeticDecoder(); ~JArithmeticDecoder(); + void setStream(Stream *strA) - { str = strA; dataLen = -1; } + { str = strA; dataLen = 0; limitStream = gFalse; } void setStream(Stream *strA, int dataLenA) - { str = strA; dataLen = dataLenA; } + { str = strA; dataLen = dataLenA; limitStream = gTrue; } + + // Start decoding on a new stream. This fills the byte buffers and + // runs INITDEC. void start(); + + // Restart decoding on an interrupted stream. This refills the + // buffers if needed, but does not run INITDEC. (This is used in + // JPEG 2000 streams when codeblock data is split across multiple + // packets/layers.) + void restart(int dataLenA); + + // Read any leftover data in the stream. + void cleanup(); + + // Decode one bit. int decodeBit(Guint context, JArithmeticDecoderStats *stats); + + // Decode eight bits. int decodeByte(Guint context, JArithmeticDecoderStats *stats); // Returns false for OOB, otherwise sets * and returns true. @@ -86,6 +103,7 @@ private: Stream *str; int dataLen; + GBool limitStream; }; #endif diff --git a/pdf2swf/xpdf/JBIG2Stream.cc b/pdf2swf/xpdf/JBIG2Stream.cc index c1bf4f7..a90db80 100644 --- a/pdf2swf/xpdf/JBIG2Stream.cc +++ b/pdf2swf/xpdf/JBIG2Stream.cc @@ -681,7 +681,9 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): w = wA; h = hA; line = (wA + 7) >> 3; - data = (Guchar *)gmalloc(h * line); + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); + data[h * line] = 0; } JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): @@ -690,8 +692,10 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): w = bitmap->w; h = bitmap->h; line = bitmap->line; - data = (Guchar *)gmalloc(h * line); + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); memcpy(data, bitmap->data, h * line); + data[h * line] = 0; } JBIG2Bitmap::~JBIG2Bitmap() { @@ -719,13 +723,15 @@ void JBIG2Bitmap::expand(int newH, Guint pixel) { if (newH <= h) { return; } - data = (Guchar *)grealloc(data, newH * line); + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)grealloc(data, newH * line + 1); if (pixel) { memset(data + h * line, 0xff, (newH - h) * line); } else { memset(data + h * line, 0x00, (newH - h) * line); } h = newH; + data[h * line] = 0; } void JBIG2Bitmap::clearToZero() { @@ -933,6 +939,10 @@ void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y, } // right-most byte + // note: this last byte (src1) may not actually be used, depending + // on the values of s1, m1, and m2 - and in fact, it may be off + // the edge of the source bitmap, which means we need to allocate + // one extra guard byte at the end of each bitmap dest = *destPtr; src0 = src1; src1 = *srcPtr++; @@ -993,7 +1003,7 @@ JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA): JBIG2Segment(segNumA) { size = sizeA; - bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *)); + bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); genericRegionStats = NULL; refinementRegionStats = NULL; } @@ -1037,7 +1047,7 @@ JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): JBIG2Segment(segNumA) { size = sizeA; - bitmaps = (JBIG2Bitmap **)gmalloc(size * sizeof(JBIG2Bitmap *)); + bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); } JBIG2PatternDict::~JBIG2PatternDict() { @@ -1233,7 +1243,7 @@ void JBIG2Stream::readSegments() { } // referred-to segment numbers - refSegs = (Guint *)gmalloc(nRefSegs * sizeof(Guint)); + refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint)); if (segNum <= 256) { for (i = 0; i < nRefSegs; ++i) { if (!readUByte(&refSegs[i])) { @@ -1273,7 +1283,9 @@ void JBIG2Stream::readSegments() { // read the segment data switch (segType) { case 0: - readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs); + if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) { + goto syntaxError; + } break; case 4: readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); @@ -1350,14 +1362,18 @@ void JBIG2Stream::readSegments() { return; + syntaxError: + 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) { +GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, + Guint *refSegs, Guint nRefSegs) { JBIG2SymbolDict *symbolDict; JBIG2HuffmanTable *huffDHTable, *huffDWTable; JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable; @@ -1451,8 +1467,11 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, } // get the input symbol bitmaps - bitmaps = (JBIG2Bitmap **)gmalloc((numInputSyms + numNewSyms) * - sizeof(JBIG2Bitmap *)); + bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms, + sizeof(JBIG2Bitmap *)); + for (i = 0; i < numInputSyms + numNewSyms; ++i) { + bitmaps[i] = NULL; + } k = 0; inputSymbolDict = NULL; for (i = 0; i < nRefSegs; ++i) { @@ -1527,7 +1546,7 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, // allocate symbol widths storage symWidths = NULL; if (huff && !refAgg) { - symWidths = (Guint *)gmalloc(numNewSyms * sizeof(Guint)); + symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint)); } symHeight = 0; @@ -1540,6 +1559,10 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, } else { arithDecoder->decodeInt(&dh, iadhStats); } + if (dh < 0 && (Guint)-dh >= symHeight) { + error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); + goto syntaxError; + } symHeight += dh; symWidth = 0; totalWidth = 0; @@ -1558,6 +1581,10 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, break; } } + if (dw < 0 && (Guint)-dw >= symWidth) { + error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); + goto syntaxError; + } symWidth += dw; // using a collective bitmap, so don't read a bitmap here @@ -1690,10 +1717,23 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, // store the new symbol dict segments->append(symbolDict); - return; + return gTrue; + + syntaxError: + for (i = 0; i < numNewSyms; ++i) { + if (bitmaps[numInputSyms + i]) { + delete bitmaps[numInputSyms + i]; + } + } + gfree(bitmaps); + if (symWidths) { + gfree(symWidths); + } + return gFalse; eofError: error(getPos(), "Unexpected EOF in JBIG2 stream"); + return gFalse; } void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, @@ -1773,11 +1813,14 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, 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); + if ((seg = findSegment(refSegs[i]))) { + if (seg->getType() == jbig2SegSymbolDict) { + numSyms += ((JBIG2SymbolDict *)seg)->getSize(); + } else if (seg->getType() == jbig2SegCodeTable) { + codeTables->append(seg); + } + } else { + error(getPos(), "Invalid segment reference in JBIG2 text region"); } } symCodeLen = 0; @@ -1788,14 +1831,15 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, } // get the symbol bitmaps - syms = (JBIG2Bitmap **)gmalloc(numSyms * sizeof(JBIG2Bitmap *)); + syms = (JBIG2Bitmap **)gmallocn(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); + if ((seg = findSegment(refSegs[i]))) { + if (seg->getType() == jbig2SegSymbolDict) { + symbolDict = (JBIG2SymbolDict *)seg; + for (k = 0; k < symbolDict->getSize(); ++k) { + syms[kk++] = symbolDict->getBitmap(k); + } } } } @@ -1888,8 +1932,8 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, runLengthTab[35].prefixLen = 0; runLengthTab[35].rangeLen = jbig2HuffmanEOT; huffDecoder->buildTable(runLengthTab, 35); - symCodeTab = (JBIG2HuffmanTable *)gmalloc((numSyms + 1) * - sizeof(JBIG2HuffmanTable)); + symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1, + sizeof(JBIG2HuffmanTable)); for (i = 0; i < numSyms; ++i) { symCodeTab[i].val = i; symCodeTab[i].rangeLen = 0; @@ -2052,85 +2096,90 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); } - // get the symbol bitmap - symbolBitmap = NULL; - if (refine) { - if (huff) { - ri = (int)huffDecoder->readBit(); + if (symID >= (Guint)numSyms) { + error(getPos(), "Invalid symbol number in JBIG2 text region"); + } else { + + // get the symbol bitmap + symbolBitmap = NULL; + if (refine) { + if (huff) { + ri = (int)huffDecoder->readBit(); + } else { + arithDecoder->decodeInt(&ri, iariStats); + } } else { - arithDecoder->decodeInt(&ri, iariStats); + ri = 0; } - } 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(); + 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 { - arithDecoder->decodeInt(&rdw, iardwStats); - arithDecoder->decodeInt(&rdh, iardhStats); - arithDecoder->decodeInt(&rdx, iardxStats); - arithDecoder->decodeInt(&rdy, iardyStats); + symbolBitmap = syms[symID]; } - refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx; - refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy; - - symbolBitmap = - readGenericRefinementRegion(rdw + syms[symID]->getWidth(), - rdh + syms[symID]->getHeight(), - templ, gFalse, syms[symID], - refDX, refDY, atx, aty); - //~ do we need to use the bmSize value here (in Huffman mode)? - } else { - symbolBitmap = syms[symID]; - } - // 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; + // 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; } - 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; + if (ri) { + delete symbolBitmap; } - s += bw; - } - if (ri) { - delete symbolBitmap; } // next instance @@ -2298,7 +2347,7 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, } // read the gray-scale image - grayImg = (Guint *)gmalloc(gridW * gridH * sizeof(Guint)); + grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint)); memset(grayImg, 0, gridW * gridH * sizeof(Guint)); atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1; atx[1] = -3; aty[1] = -1; @@ -2451,8 +2500,8 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, if (mmr) { mmrDecoder->reset(); - refLine = (int *)gmalloc((w + 2) * sizeof(int)); - codingLine = (int *)gmalloc((w + 2) * sizeof(int)); + refLine = (int *)gmallocn(w + 2, sizeof(int)); + codingLine = (int *)gmallocn(w + 2, sizeof(int)); codingLine[0] = codingLine[1] = w; for (y = 0; y < h; ++y) { @@ -3111,14 +3160,14 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) { huffDecoder->reset(); huffTabSize = 8; huffTab = (JBIG2HuffmanTable *) - gmalloc(huffTabSize * sizeof(JBIG2HuffmanTable)); + gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable)); i = 0; val = lowVal; while (val < highVal) { if (i == huffTabSize) { huffTabSize *= 2; huffTab = (JBIG2HuffmanTable *) - grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable)); + greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); } huffTab[i].val = val; huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); @@ -3129,7 +3178,7 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) { if (i + oob + 3 > huffTabSize) { huffTabSize = i + oob + 3; huffTab = (JBIG2HuffmanTable *) - grealloc(huffTab, huffTabSize * sizeof(JBIG2HuffmanTable)); + greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); } huffTab[i].val = lowVal - 1; huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); diff --git a/pdf2swf/xpdf/JBIG2Stream.h b/pdf2swf/xpdf/JBIG2Stream.h index ed26d4e..44e09db 100644 --- a/pdf2swf/xpdf/JBIG2Stream.h +++ b/pdf2swf/xpdf/JBIG2Stream.h @@ -45,8 +45,8 @@ public: private: void readSegments(); - void readSymbolDictSeg(Guint segNum, Guint length, - Guint *refSegs, Guint nRefSegs); + GBool readSymbolDictSeg(Guint segNum, Guint length, + Guint *refSegs, Guint nRefSegs); void readTextRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length, Guint *refSegs, Guint nRefSegs); diff --git a/pdf2swf/xpdf/JPXStream.cc b/pdf2swf/xpdf/JPXStream.cc index defa7d2..336b7ba 100644 --- a/pdf2swf/xpdf/JPXStream.cc +++ b/pdf2swf/xpdf/JPXStream.cc @@ -243,6 +243,9 @@ JPXStream::~JPXStream() { for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) { cb = &subband->cbs[k]; gfree(cb->coeffs); + if (cb->arithDecoder) { + delete cb->arithDecoder; + } if (cb->stats) { delete cb->stats; } @@ -374,6 +377,122 @@ GBool JPXStream::isBinary(GBool last) { return str->isBinary(gTrue); } +void JPXStream::getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode) { + Guint boxType, boxLen, dataLen, csEnum; + Guint bpc1, dummy, i; + int csMeth, csPrec, csPrec1, dummy2; + StreamColorSpaceMode csMode1; + GBool haveBPC, haveCSMode; + + csPrec = 0; // make gcc happy + haveBPC = haveCSMode = gFalse; + str->reset(); + if (str->lookChar() == 0xff) { + getImageParams2(bitsPerComponent, csMode); + } else { + while (readBoxHdr(&boxType, &boxLen, &dataLen)) { + if (boxType == 0x6a703268) { // JP2 header + // skip the superbox + } else if (boxType == 0x69686472) { // image header + if (readULong(&dummy) && + readULong(&dummy) && + readUWord(&dummy) && + readUByte(&bpc1) && + readUByte(&dummy) && + readUByte(&dummy) && + readUByte(&dummy)) { + *bitsPerComponent = bpc1 + 1; + haveBPC = gTrue; + } + } else if (boxType == 0x636F6C72) { // color specification + if (readByte(&csMeth) && + readByte(&csPrec1) && + readByte(&dummy2)) { + if (csMeth == 1) { + if (readULong(&csEnum)) { + csMode1 = streamCSNone; + if (csEnum == jpxCSBiLevel || + csEnum == jpxCSGrayscale) { + csMode1 = streamCSDeviceGray; + } else if (csEnum == jpxCSCMYK) { + csMode1 = streamCSDeviceCMYK; + } else if (csEnum == jpxCSsRGB || + csEnum == jpxCSCISesRGB || + csEnum == jpxCSROMMRGB) { + csMode1 = streamCSDeviceRGB; + } + if (csMode1 != streamCSNone && + (!haveCSMode || csPrec1 > csPrec)) { + *csMode = csMode1; + csPrec = csPrec1; + haveCSMode = gTrue; + } + for (i = 0; i < dataLen - 7; ++i) { + str->getChar(); + } + } + } else { + for (i = 0; i < dataLen - 3; ++i) { + str->getChar(); + } + } + } + } else if (boxType == 0x6A703263) { // codestream + if (!(haveBPC && haveCSMode)) { + getImageParams2(bitsPerComponent, csMode); + } + break; + } else { + for (i = 0; i < dataLen; ++i) { + str->getChar(); + } + } + } + } + str->close(); +} + +// Get image parameters from the codestream. +void JPXStream::getImageParams2(int *bitsPerComponent, + StreamColorSpaceMode *csMode) { + int segType; + Guint segLen, nComps1, bpc1, dummy, i; + + while (readMarkerHdr(&segType, &segLen)) { + if (segType == 0x51) { // SIZ - image and tile size + if (readUWord(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readUWord(&nComps1) && + readUByte(&bpc1)) { + *bitsPerComponent = (bpc1 & 0x7f) + 1; + // if there's no color space info, take a guess + if (nComps1 == 1) { + *csMode = streamCSDeviceGray; + } else if (nComps1 == 3) { + *csMode = streamCSDeviceRGB; + } else if (nComps1 == 4) { + *csMode = streamCSDeviceCMYK; + } + } + break; + } else { + if (segLen > 2) { + for (i = 0; i < segLen - 2; ++i) { + str->getChar(); + } + } + } + } +} + GBool JPXStream::readBoxes() { Guint boxType, boxLen, dataLen; Guint bpc1, compression, unknownColorspace, ipr; @@ -388,7 +507,7 @@ GBool JPXStream::readBoxes() { error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper"); readCodestream(0); nComps = img.nComps; - bpc = (Guint *)gmalloc(nComps * sizeof(Guint)); + bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); for (i = 0; i < nComps; ++i) { bpc[i] = img.tiles[0].tileComps[i].prec; } @@ -421,7 +540,7 @@ GBool JPXStream::readBoxes() { error(getPos(), "Unknown compression type in JPX stream"); return gFalse; } - bpc = (Guint *)gmalloc(nComps * sizeof(Guint)); + bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); for (i = 0; i < nComps; ++i) { bpc[i] = bpc1; } @@ -454,9 +573,9 @@ GBool JPXStream::readBoxes() { error(getPos(), "Unexpected EOF in JPX stream"); return gFalse; } - palette.bpc = (Guint *)gmalloc(palette.nComps * sizeof(Guint)); + palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint)); palette.c = - (int *)gmalloc(palette.nEntries * palette.nComps * sizeof(int)); + (int *)gmallocn(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"); @@ -478,9 +597,9 @@ GBool JPXStream::readBoxes() { 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)); + compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); for (i = 0; i < compMap.nChannels; ++i) { if (!readUWord(&compMap.comp[i]) || !readUByte(&compMap.type[i]) || @@ -497,11 +616,11 @@ GBool JPXStream::readBoxes() { return gFalse; } channelDefn.idx = - (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); channelDefn.type = - (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); channelDefn.assoc = - (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint)); + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); for (i = 0; i < channelDefn.nChannels; ++i) { if (!readUWord(&channelDefn.idx[i]) || !readUWord(&channelDefn.type[i]) || @@ -515,11 +634,9 @@ GBool JPXStream::readBoxes() { 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; @@ -582,7 +699,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) { ok = gTrue; break; case jpxCSCIELab: - if (dataLen == 3 + 7*4) { + if (dataLen == 7 + 7*4) { if (!readULong(&newCS.enumerated.cieLab.rl) || !readULong(&newCS.enumerated.cieLab.ol) || !readULong(&newCS.enumerated.cieLab.ra) || @@ -592,7 +709,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) { !readULong(&newCS.enumerated.cieLab.il)) { goto err; } - } else if (dataLen == 3) { + } else if (dataLen == 7) { //~ this assumes the 8-bit case newCS.enumerated.cieLab.rl = 100; newCS.enumerated.cieLab.ol = 0; @@ -666,7 +783,7 @@ GBool JPXStream::readCodestream(Guint len) { int segType; GBool haveSIZ, haveCOD, haveQCD, haveSOT; Guint precinctSize, style; - Guint segLen, capabilities, comp, i, j, r; + Guint segLen, capabilities, nTiles, comp, i, j, r; //----- main header haveSIZ = haveCOD = haveQCD = haveSOT = gFalse; @@ -701,11 +818,16 @@ GBool JPXStream::readCodestream(Guint len) { / img.xTileSize; img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) / img.yTileSize; - img.tiles = (JPXTile *)gmalloc(img.nXTiles * img.nYTiles * - sizeof(JPXTile)); + nTiles = img.nXTiles * img.nYTiles; + // check for overflow before allocating memory + if (nTiles == 0 || nTiles / img.nXTiles != img.nYTiles) { + error(getPos(), "Bad tile count in JPX SIZ marker segment"); + return gFalse; + } + img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile)); for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { - img.tiles[i].tileComps = (JPXTileComp *)gmalloc(img.nComps * - sizeof(JPXTileComp)); + img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps, + sizeof(JPXTileComp)); for (comp = 0; comp < img.nComps; ++comp) { img.tiles[i].tileComps[comp].quantSteps = NULL; img.tiles[i].tileComps[comp].data = NULL; @@ -767,8 +889,8 @@ GBool JPXStream::readCodestream(Guint len) { img.tiles[0].tileComps[0].transform; } img.tiles[i].tileComps[comp].resLevels = - (JPXResLevel *)gmalloc( - (img.tiles[i].tileComps[comp].nDecompLevels + 1) * + (JPXResLevel *)gmallocn( + (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; @@ -841,10 +963,10 @@ GBool JPXStream::readCodestream(Guint len) { img.tiles[0].tileComps[comp].transform; } img.tiles[i].tileComps[comp].resLevels = - (JPXResLevel *)grealloc( + (JPXResLevel *)greallocn( img.tiles[i].tileComps[comp].resLevels, - (img.tiles[i].tileComps[comp].nDecompLevels + 1) * - sizeof(JPXResLevel)); + (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; } @@ -881,9 +1003,9 @@ GBool JPXStream::readCodestream(Guint len) { 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)); + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) { error(getPos(), "Error in JPX QCD marker segment"); @@ -893,9 +1015,9 @@ GBool JPXStream::readCodestream(Guint len) { } 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)); + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) { error(getPos(), "Error in JPX QCD marker segment"); return gFalse; @@ -903,9 +1025,9 @@ GBool JPXStream::readCodestream(Guint len) { } 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)); + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) { error(getPos(), "Error in JPX QCD marker segment"); @@ -924,9 +1046,9 @@ GBool JPXStream::readCodestream(Guint len) { 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)); + (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) { img.tiles[i].tileComps[comp].quantSteps[j] = img.tiles[0].tileComps[0].quantSteps[j]; @@ -952,9 +1074,9 @@ GBool JPXStream::readCodestream(Guint len) { 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)); + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) { error(getPos(), "Error in JPX QCC marker segment"); @@ -964,9 +1086,9 @@ GBool JPXStream::readCodestream(Guint len) { } 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)); + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) { error(getPos(), "Error in JPX QCC marker segment"); return gFalse; @@ -975,9 +1097,9 @@ GBool JPXStream::readCodestream(Guint len) { 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)); + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) { error(getPos(), "Error in JPX QCD marker segment"); @@ -994,9 +1116,9 @@ GBool JPXStream::readCodestream(Guint len) { 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)); + (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) { img.tiles[i].tileComps[comp].quantSteps[j] = img.tiles[0].tileComps[comp].quantSteps[j]; @@ -1034,7 +1156,7 @@ GBool JPXStream::readCodestream(Guint len) { } #else nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); - progs = (JPXProgOrder *)gmalloc(nProgs * sizeof(JPXProgOrder)); + progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder)); for (i = 0; i < nProgs; ++i) { if (!readUByte(&progs[i].startRes) || !(img.nComps > 256 && readUWord(&progs[i].startComp)) || @@ -1231,10 +1353,10 @@ GBool JPXStream::readTilePart() { img.tiles[tileIdx].tileComps[0].transform; } img.tiles[tileIdx].tileComps[comp].resLevels = - (JPXResLevel *)grealloc( + (JPXResLevel *)greallocn( img.tiles[tileIdx].tileComps[comp].resLevels, - (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) * - sizeof(JPXResLevel)); + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { @@ -1285,10 +1407,10 @@ GBool JPXStream::readTilePart() { img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; img.tiles[tileIdx].tileComps[comp].codeBlockH += 2; img.tiles[tileIdx].tileComps[comp].resLevels = - (JPXResLevel *)grealloc( + (JPXResLevel *)greallocn( img.tiles[tileIdx].tileComps[comp].resLevels, - (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) * - sizeof(JPXResLevel)); + (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; } @@ -1317,9 +1439,9 @@ GBool JPXStream::readTilePart() { 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)); + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { error(getPos(), "Error in JPX QCD marker segment"); @@ -1329,9 +1451,9 @@ GBool JPXStream::readTilePart() { } 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)); + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) { error(getPos(), "Error in JPX QCD marker segment"); return gFalse; @@ -1339,9 +1461,9 @@ GBool JPXStream::readTilePart() { } 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)); + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { error(getPos(), "Error in JPX QCD marker segment"); @@ -1358,9 +1480,9 @@ GBool JPXStream::readTilePart() { 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)); + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) { img.tiles[tileIdx].tileComps[comp].quantSteps[j] = img.tiles[tileIdx].tileComps[0].quantSteps[j]; @@ -1379,9 +1501,9 @@ GBool JPXStream::readTilePart() { 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)); + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { error(getPos(), "Error in JPX QCC marker segment"); @@ -1392,9 +1514,9 @@ GBool JPXStream::readTilePart() { == 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)); + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) { error(getPos(), "Error in JPX QCC marker segment"); return gFalse; @@ -1404,9 +1526,9 @@ GBool JPXStream::readTilePart() { 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)); + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { error(getPos(), "Error in JPX QCD marker segment"); @@ -1449,7 +1571,7 @@ GBool JPXStream::readTilePart() { } #else nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); - tileProgs = (JPXProgOrder *)gmalloc(nTileProgs * sizeof(JPXProgOrder)); + tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder)); for (i = 0; i < nTileProgs; ++i) { if (!readUByte(&tileProgs[i].startRes) || !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) || @@ -1541,15 +1663,15 @@ GBool JPXStream::readTilePart() { 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)); + tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) * + (tileComp->y1 - tileComp->y0), + sizeof(int)); if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { n = tileComp->x1 - tileComp->x0; } else { n = tileComp->y1 - tileComp->y0; } - tileComp->buf = (int *)gmalloc((n + 8) * sizeof(int)); + tileComp->buf = (int *)gmallocn(n + 8, sizeof(int)); for (r = 0; r <= tileComp->nDecompLevels; ++r) { resLevel = &tileComp->resLevels[r]; k = r == 0 ? tileComp->nDecompLevels @@ -1577,7 +1699,7 @@ GBool JPXStream::readTilePart() { 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)); + resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct)); for (pre = 0; pre < 1; ++pre) { precinct = &resLevel->precincts[pre]; precinct->x0 = resLevel->x0; @@ -1586,7 +1708,7 @@ GBool JPXStream::readTilePart() { precinct->y1 = resLevel->y1; nSBs = r == 0 ? 1 : 3; precinct->subbands = - (JPXSubband *)gmalloc(nSBs * sizeof(JPXSubband)); + (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband)); for (sb = 0; sb < nSBs; ++sb) { subband = &precinct->subbands[sb]; subband->x0 = resLevel->bx0[sb]; @@ -1613,18 +1735,18 @@ GBool JPXStream::readTilePart() { n += nx * ny; } subband->inclusion = - (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode)); + (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); subband->zeroBitPlane = - (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode)); + (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); for (k = 0; k < n; ++k) { subband->inclusion[k].finished = gFalse; subband->inclusion[k].val = 0; subband->zeroBitPlane[k].finished = gFalse; subband->zeroBitPlane[k].val = 0; } - subband->cbs = (JPXCodeBlock *)gmalloc(subband->nXCBs * - subband->nYCBs * - sizeof(JPXCodeBlock)); + subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs * + subband->nYCBs, + sizeof(JPXCodeBlock)); sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW); sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH); cb = subband->cbs; @@ -1651,9 +1773,9 @@ GBool JPXStream::readTilePart() { cb->nextPass = jpxPassCleanup; cb->nZeroBitPlanes = 0; cb->coeffs = - (JPXCoeff *)gmalloc((1 << (tileComp->codeBlockW - + tileComp->codeBlockH)) - * sizeof(JPXCoeff)); + (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW + + tileComp->codeBlockH)), + sizeof(JPXCoeff)); for (cbi = 0; cbi < (Guint)(1 << (tileComp->codeBlockW + tileComp->codeBlockH)); @@ -1662,10 +1784,8 @@ GBool JPXStream::readTilePart() { 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->arithDecoder = NULL; + cb->stats = NULL; ++cb; } } @@ -1963,14 +2083,21 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, 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(); + if (cb->arithDecoder) { + cb->arithDecoder->restart(cb->dataLen); + } else { + cb->arithDecoder = new JArithmeticDecoder(); + cb->arithDecoder->setStream(str, cb->dataLen); + cb->arithDecoder->start(); + cb->stats = new JArithmeticDecoderStats(jpxNContexts); + cb->stats->setEntry(jpxContextSigProp, 4, 0); + cb->stats->setEntry(jpxContextRunLength, 3, 0); + cb->stats->setEntry(jpxContextUniform, 46, 0); + } for (i = 0; i < cb->nCodingPasses; ++i) { switch (cb->nextPass) { @@ -1995,7 +2122,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; } if (y0+y1 > cb->y0) { - diag += (coeff[-tileComp->cbW - 1].flags + diag += (coeff[-(int)tileComp->cbW - 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2009,7 +2136,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; } if (y0+y1 > cb->y0) { - diag += (coeff[-tileComp->cbW + 1].flags + diag += (coeff[-(int)tileComp->cbW + 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2018,9 +2145,9 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } if (y0+y1 > cb->y0) { - if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) { + if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { ++vert; - vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign) + vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) ? -1 : 1; } } @@ -2033,12 +2160,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; if (cx != 0) { - if (arithDecoder->decodeBit(cx, cb->stats)) { + if (cb->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) { + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { coeff->flags |= jpxCoeffSign; } } @@ -2070,7 +2197,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, if (x > cb->x0) { all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1; if (y0+y1 > cb->y0) { - all += (coeff[-tileComp->cbW - 1].flags + all += (coeff[-(int)tileComp->cbW - 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2081,7 +2208,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, if (x < cb->x1 - 1) { all += (coeff[1].flags >> jpxCoeffSignificantB) & 1; if (y0+y1 > cb->y0) { - all += (coeff[-tileComp->cbW + 1].flags + all += (coeff[-(int)tileComp->cbW + 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2090,7 +2217,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } if (y0+y1 > cb->y0) { - all += (coeff[-tileComp->cbW].flags + all += (coeff[-(int)tileComp->cbW].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2102,7 +2229,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, cx = 16; } coeff->mag = (coeff->mag << 1) | - arithDecoder->decodeBit(cx, cb->stats); + cb->arithDecoder->decodeBit(cx, cb->stats); ++coeff->len; coeff->flags |= jpxCoeffTouched; coeff->flags &= ~jpxCoeffFirstMagRef; @@ -2128,12 +2255,14 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) && !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) && (x == cb->x0 || y0 == cb->y0 || - !(coeff1[-tileComp->cbW - 1].flags + !(coeff1[-(int)tileComp->cbW - 1].flags & jpxCoeffSignificant)) && (y0 == cb->y0 || - !(coeff1[-tileComp->cbW].flags & jpxCoeffSignificant)) && + !(coeff1[-(int)tileComp->cbW].flags + & jpxCoeffSignificant)) && (x == cb->x1 - 1 || y0 == cb->y0 || - !(coeff1[-tileComp->cbW + 1].flags & jpxCoeffSignificant)) && + !(coeff1[-(int)tileComp->cbW + 1].flags + & jpxCoeffSignificant)) && (x == cb->x0 || (!(coeff1[-1].flags & jpxCoeffSignificant) && !(coeff1[tileComp->cbW - 1].flags @@ -2157,10 +2286,10 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, (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); + if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) { + y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); y1 = (y1 << 1) | - arithDecoder->decodeBit(jpxContextUniform, cb->stats); + cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); for (y2 = 0, coeff = coeff1; y2 < y1; ++y2, coeff += tileComp->cbW) { @@ -2171,7 +2300,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, ++coeff->len; cx = signContext[2][2][0]; xorBit = signContext[2][2][1]; - if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { coeff->flags |= jpxCoeffSign; } ++y1; @@ -2196,7 +2325,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; } if (y0+y1 > cb->y0) { - diag += (coeff[-tileComp->cbW - 1].flags + diag += (coeff[-(int)tileComp->cbW - 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2210,7 +2339,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; } if (y0+y1 > cb->y0) { - diag += (coeff[-tileComp->cbW + 1].flags + diag += (coeff[-(int)tileComp->cbW + 1].flags >> jpxCoeffSignificantB) & 1; } if (y0+y1 < cb->y1 - 1) { @@ -2219,9 +2348,9 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } if (y0+y1 > cb->y0) { - if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) { + if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { ++vert; - vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign) + vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) ? -1 : 1; } } @@ -2233,12 +2362,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; - if (arithDecoder->decodeBit(cx, cb->stats)) { + if (cb->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) { + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { coeff->flags |= jpxCoeffSign; } } @@ -2254,7 +2383,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, } } - delete arithDecoder; + cb->arithDecoder->cleanup(); return gTrue; } @@ -2266,7 +2395,8 @@ void JPXStream::inverseTransform(JPXTileComp *tileComp) { JPXSubband *subband; JPXCodeBlock *cb; JPXCoeff *coeff0, *coeff; - Guint qStyle, guard, eps, shift, shift2; + Guint qStyle, guard, eps, shift; + int shift2; double mu; int val; int *dataPtr; @@ -2368,7 +2498,8 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, JPXSubband *subband; JPXCodeBlock *cb; JPXCoeff *coeff0, *coeff; - Guint qStyle, guard, eps, shift, shift2, t; + Guint qStyle, guard, eps, shift, t; + int shift2; double mu; int val; int *dataPtr; @@ -2578,7 +2709,7 @@ void JPXStream::inverseTransform1D(JPXTileComp *tileComp, // converts fixed point samples back to integers. GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { JPXTileComp *tileComp; - int coeff, d0, d1, d2, minVal, maxVal, zeroVal; + int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal; int *dataPtr; Guint j, comp, x, y; @@ -2617,9 +2748,9 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { 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; + tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2); + tile->tileComps[0].data[j] = d2 + t; + tile->tileComps[2].data[j] = d1 + t; ++j; } } diff --git a/pdf2swf/xpdf/JPXStream.h b/pdf2swf/xpdf/JPXStream.h index eb84fe6..e64731d 100644 --- a/pdf2swf/xpdf/JPXStream.h +++ b/pdf2swf/xpdf/JPXStream.h @@ -44,18 +44,22 @@ enum JPXColorSpaceType { jpxCSYPbPr1250 = 24 }; +struct JPXColorSpecCIELab { + Guint rl, ol, ra, oa, rb, ob, il; +}; + +struct JPXColorSpecEnumerated { + JPXColorSpaceType type; // color space type + union { + JPXColorSpecCIELab cieLab; + }; +}; + struct JPXColorSpec { Guint meth; // method int prec; // precedence union { - struct { - JPXColorSpaceType type; // color space type - union { - struct { - Guint rl, ol, ra, oa, rb, ob, il; - } cieLab; - }; - } enumerated; + JPXColorSpecEnumerated enumerated; }; }; @@ -135,6 +139,8 @@ struct JPXCodeBlock { //----- coefficient data JPXCoeff *coeffs; // the coefficients + JArithmeticDecoder // arithmetic decoder + *arithDecoder; JArithmeticDecoderStats // arithmetic decoder stats *stats; }; @@ -275,10 +281,13 @@ public: virtual int lookChar(); virtual GString *getPSFilter(int psLevel, char *indent); virtual GBool isBinary(GBool last = gTrue); + virtual void getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode); private: void fillReadBuf(); + void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode); GBool readBoxes(); GBool readColorSpecBox(Guint dataLen); GBool readCodestream(Guint len); diff --git a/pdf2swf/xpdf/Lexer.cc b/pdf2swf/xpdf/Lexer.cc index 1fa166f..9f0c3ca 100644 --- a/pdf2swf/xpdf/Lexer.cc +++ b/pdf2swf/xpdf/Lexer.cc @@ -171,6 +171,13 @@ Object *Lexer::getObj(Object *obj) { scale = 0.1; while (1) { c = lookChar(); + if (c == '-') { + // ignore minus signs in the middle of numbers to match + // Adobe's behavior + error(getPos(), "Badly formatted number"); + getChar(); + continue; + } if (!isdigit(c)) { break; } @@ -472,3 +479,7 @@ void Lexer::skipToNextLine() { } } } + +GBool Lexer::isSpace(int c) { + return c >= 0 && c <= 0xff && specialChars[c] == 1; +} diff --git a/pdf2swf/xpdf/Lexer.h b/pdf2swf/xpdf/Lexer.h index 398d27c..f6ad9ce 100644 --- a/pdf2swf/xpdf/Lexer.h +++ b/pdf2swf/xpdf/Lexer.h @@ -62,6 +62,9 @@ public: void setPos(Guint pos, int dir = 0) { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); } + // Returns true if is a whitespace character. + static GBool isSpace(int c); + private: int getChar(); diff --git a/pdf2swf/xpdf/Link.cc b/pdf2swf/xpdf/Link.cc index 2d146b5..898ca20 100644 --- a/pdf2swf/xpdf/Link.cc +++ b/pdf2swf/xpdf/Link.cc @@ -117,14 +117,19 @@ GString *LinkAction::getFileSpecName(Object *fileSpecObj) { // dictionary } else if (fileSpecObj->isDict()) { +#ifdef WIN32 + if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) { +#else if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { +#endif obj1.free(); fileSpecObj->dictLookup("F", &obj1); } - if (obj1.isString()) + if (obj1.isString()) { name = obj1.getString()->copy(); - else + } else { error(-1, "Illegal file spec in link"); + } obj1.free(); // error @@ -132,6 +137,55 @@ GString *LinkAction::getFileSpecName(Object *fileSpecObj) { error(-1, "Illegal file spec in link"); } + // system-dependent path manipulation + if (name) { +#ifdef WIN32 + int i, j; + + // "//...." --> "\...." + // "/x/...." --> "x:\...." + // "/server/share/...." --> "\\server\share\...." + // convert escaped slashes to slashes and unescaped slashes to backslashes + i = 0; + if (name->getChar(0) == '/') { + if (name->getLength() >= 2 && name->getChar(1) == '/') { + name->del(0); + i = 0; + } else if (name->getLength() >= 2 && + ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') || + (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) && + (name->getLength() == 2 || name->getChar(2) == '/')) { + name->setChar(0, name->getChar(1)); + name->setChar(1, ':'); + i = 2; + } else { + for (j = 2; j < name->getLength(); ++j) { + if (name->getChar(j-1) != '\\' && + name->getChar(j) == '/') { + break; + } + } + if (j < name->getLength()) { + name->setChar(0, '\\'); + name->insert(0, '\\'); + i = 2; + } + } + } + for (; i < name->getLength(); ++i) { + if (name->getChar(i) == '/') { + name->setChar(i, '\\'); + } else if (name->getChar(i) == '\\' && + i+1 < name->getLength() && + name->getChar(i+1) == '/') { + name->del(i); + } + } +#else + // no manipulation needed for Unix +#endif + } + return name; } @@ -497,7 +551,7 @@ LinkURI::LinkURI(Object *uriObj, GString *baseURI) { uri = NULL; if (uriObj->isString()) { uri2 = uriObj->getString()->copy(); - if (baseURI) { + if (baseURI && baseURI->getLength() > 0) { n = strcspn(uri2->getCString(), "/:"); if (n == uri2->getLength() || uri2->getChar(n) == '/') { uri = baseURI->copy(); @@ -690,7 +744,7 @@ Link::Link(Dict *dict, GString *baseURI) { obj2.free(); if (obj1.dictLookup("D", &obj2)->isArray()) { borderDashLength = obj2.arrayGetLength(); - borderDash = (double *)gmalloc(borderDashLength * sizeof(double)); + borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); for (i = 0; i < borderDashLength; ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { borderDash[i] = obj3.getNum(); @@ -713,7 +767,7 @@ Link::Link(Dict *dict, GString *baseURI) { if (obj1.arrayGet(3, &obj2)->isArray()) { borderType = linkBorderDashed; borderDashLength = obj2.arrayGetLength(); - borderDash = (double *)gmalloc(borderDashLength * sizeof(double)); + borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); for (i = 0; i < borderDashLength; ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { borderDash[i] = obj3.getNum(); @@ -722,6 +776,10 @@ Link::Link(Dict *dict, GString *baseURI) { } obj3.free(); } + } else { + // Adobe draws no border at all if the last element is of + // the wrong type. + borderWidth = 0; } obj2.free(); } @@ -805,7 +863,7 @@ Links::Links(Object *annots, GString *baseURI) { if (link->isOk()) { if (numLinks >= size) { size += 16; - links = (Link **)grealloc(links, size * sizeof(Link *)); + links = (Link **)greallocn(links, size, sizeof(Link *)); } links[numLinks++] = link; } else { diff --git a/pdf2swf/xpdf/NameToCharCode.cc b/pdf2swf/xpdf/NameToCharCode.cc index 8f22a90..7ebf4e1 100644 --- a/pdf2swf/xpdf/NameToCharCode.cc +++ b/pdf2swf/xpdf/NameToCharCode.cc @@ -30,7 +30,7 @@ NameToCharCode::NameToCharCode() { size = 31; len = 0; - tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry)); + tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); for (i = 0; i < size; ++i) { tab[i].name = NULL; } @@ -56,7 +56,7 @@ void NameToCharCode::add(char *name, CharCode c) { oldSize = size; oldTab = tab; size = 2*size + 1; - tab = (NameToCharCodeEntry *)gmalloc(size * sizeof(NameToCharCodeEntry)); + tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); for (h = 0; h < size; ++h) { tab[h].name = NULL; } diff --git a/pdf2swf/xpdf/NameToUnicodeTable.h b/pdf2swf/xpdf/NameToUnicodeTable.h index 4f28fff..c5ecba4 100644 --- a/pdf2swf/xpdf/NameToUnicodeTable.h +++ b/pdf2swf/xpdf/NameToUnicodeTable.h @@ -2,7 +2,7 @@ // // NameToUnicodeTable.h // -// Copyright 2001-2003 Glyph & Cog, LLC +// Copyright 2001-2004 Glyph & Cog, LLC // //======================================================================== @@ -44,45 +44,45 @@ static struct { {0x0041, "A"}, {0x00c6, "AE"}, {0x01fc, "AEacute"}, - {0x00c6, "AEsmall"}, + {0xf7e6, "AEsmall"}, {0x00c1, "Aacute"}, - {0x00c1, "Aacutesmall"}, + {0xf7e1, "Aacutesmall"}, {0x0102, "Abreve"}, {0x00c2, "Acircumflex"}, - {0x00c2, "Acircumflexsmall"}, + {0xf7e2, "Acircumflexsmall"}, {0xf6c9, "Acute"}, - {0xf6c9, "Acutesmall"}, + {0xf7b4, "Acutesmall"}, {0x00c4, "Adieresis"}, - {0x00c4, "Adieresissmall"}, + {0xf7e4, "Adieresissmall"}, {0x00c0, "Agrave"}, - {0x00c0, "Agravesmall"}, + {0xf7e0, "Agravesmall"}, {0x0391, "Alpha"}, {0x0386, "Alphatonos"}, {0x0100, "Amacron"}, {0x0104, "Aogonek"}, {0x00c5, "Aring"}, {0x01fa, "Aringacute"}, - {0x00c5, "Aringsmall"}, - {0x0041, "Asmall"}, + {0xf7e5, "Aringsmall"}, + {0xf761, "Asmall"}, {0x00c3, "Atilde"}, - {0x00c3, "Atildesmall"}, + {0xf7e3, "Atildesmall"}, {0x0042, "B"}, {0x0392, "Beta"}, {0xf6f4, "Brevesmall"}, - {0x0042, "Bsmall"}, + {0xf762, "Bsmall"}, {0x0043, "C"}, {0x0106, "Cacute"}, {0xf6ca, "Caron"}, - {0xf6ca, "Caronsmall"}, + {0xf6f5, "Caronsmall"}, {0x010c, "Ccaron"}, {0x00c7, "Ccedilla"}, - {0x00c7, "Ccedillasmall"}, + {0xf7e7, "Ccedillasmall"}, {0x0108, "Ccircumflex"}, {0x010a, "Cdotaccent"}, {0xf7b8, "Cedillasmall"}, {0x03a7, "Chi"}, {0xf6f6, "Circumflexsmall"}, - {0x0043, "Csmall"}, + {0xf763, "Csmall"}, {0x0044, "D"}, {0x010e, "Dcaron"}, {0x0110, "Dcroat"}, @@ -90,34 +90,34 @@ static struct { {0xf6cb, "Dieresis"}, {0xf6cc, "DieresisAcute"}, {0xf6cd, "DieresisGrave"}, - {0xf6cb, "Dieresissmall"}, + {0xf7a8, "Dieresissmall"}, {0xf6f7, "Dotaccentsmall"}, - {0x0044, "Dsmall"}, + {0xf764, "Dsmall"}, {0x0045, "E"}, {0x00c9, "Eacute"}, - {0x00c9, "Eacutesmall"}, + {0xf7e9, "Eacutesmall"}, {0x0114, "Ebreve"}, {0x011a, "Ecaron"}, {0x00ca, "Ecircumflex"}, - {0x00ca, "Ecircumflexsmall"}, + {0xf7ea, "Ecircumflexsmall"}, {0x00cb, "Edieresis"}, - {0x00cb, "Edieresissmall"}, + {0xf7eb, "Edieresissmall"}, {0x0116, "Edotaccent"}, {0x00c8, "Egrave"}, - {0x00c8, "Egravesmall"}, + {0xf7e8, "Egravesmall"}, {0x0112, "Emacron"}, {0x014a, "Eng"}, {0x0118, "Eogonek"}, {0x0395, "Epsilon"}, {0x0388, "Epsilontonos"}, - {0x0045, "Esmall"}, + {0xf765, "Esmall"}, {0x0397, "Eta"}, {0x0389, "Etatonos"}, {0x00d0, "Eth"}, - {0x00d0, "Ethsmall"}, + {0xf7f0, "Ethsmall"}, {0x20ac, "Euro"}, {0x0046, "F"}, - {0x0046, "Fsmall"}, + {0xf766, "Fsmall"}, {0x0047, "G"}, {0x0393, "Gamma"}, {0x011e, "Gbreve"}, @@ -126,8 +126,8 @@ static struct { {0x0122, "Gcommaaccent"}, {0x0120, "Gdotaccent"}, {0xf6ce, "Grave"}, - {0xf6ce, "Gravesmall"}, - {0x0047, "Gsmall"}, + {0xf760, "Gravesmall"}, + {0xf767, "Gsmall"}, {0x0048, "H"}, {0x25cf, "H18533"}, {0x25aa, "H18543"}, @@ -135,36 +135,36 @@ static struct { {0x25a1, "H22073"}, {0x0126, "Hbar"}, {0x0124, "Hcircumflex"}, - {0x0048, "Hsmall"}, + {0xf768, "Hsmall"}, {0xf6cf, "Hungarumlaut"}, - {0xf6cf, "Hungarumlautsmall"}, + {0xf6f8, "Hungarumlautsmall"}, {0x0049, "I"}, {0x0132, "IJ"}, {0x00cd, "Iacute"}, - {0x00cd, "Iacutesmall"}, + {0xf7ed, "Iacutesmall"}, {0x012c, "Ibreve"}, {0x00ce, "Icircumflex"}, - {0x00ce, "Icircumflexsmall"}, + {0xf7ee, "Icircumflexsmall"}, {0x00cf, "Idieresis"}, - {0x00cf, "Idieresissmall"}, + {0xf7ef, "Idieresissmall"}, {0x0130, "Idotaccent"}, {0x2111, "Ifraktur"}, {0x00cc, "Igrave"}, - {0x00cc, "Igravesmall"}, + {0xf7ec, "Igravesmall"}, {0x012a, "Imacron"}, {0x012e, "Iogonek"}, {0x0399, "Iota"}, {0x03aa, "Iotadieresis"}, {0x038a, "Iotatonos"}, - {0x0049, "Ismall"}, + {0xf769, "Ismall"}, {0x0128, "Itilde"}, {0x004a, "J"}, {0x0134, "Jcircumflex"}, - {0x004a, "Jsmall"}, + {0xf76a, "Jsmall"}, {0x004b, "K"}, {0x039a, "Kappa"}, {0x0136, "Kcommaaccent"}, - {0x004b, "Ksmall"}, + {0xf76b, "Ksmall"}, {0x004c, "L"}, {0xf6bf, "LL"}, {0x0139, "Lacute"}, @@ -173,34 +173,34 @@ static struct { {0x013b, "Lcommaaccent"}, {0x013f, "Ldot"}, {0x0141, "Lslash"}, - {0x0141, "Lslashsmall"}, - {0x004c, "Lsmall"}, + {0xf6f9, "Lslashsmall"}, + {0xf76c, "Lsmall"}, {0x004d, "M"}, {0xf6d0, "Macron"}, - {0xf6d0, "Macronsmall"}, - {0x004d, "Msmall"}, + {0xf7af, "Macronsmall"}, + {0xf76d, "Msmall"}, {0x039c, "Mu"}, {0x004e, "N"}, {0x0143, "Nacute"}, {0x0147, "Ncaron"}, {0x0145, "Ncommaaccent"}, - {0x004e, "Nsmall"}, + {0xf76e, "Nsmall"}, {0x00d1, "Ntilde"}, - {0x00d1, "Ntildesmall"}, + {0xf7f1, "Ntildesmall"}, {0x039d, "Nu"}, {0x004f, "O"}, {0x0152, "OE"}, - {0x0152, "OEsmall"}, + {0xf6fa, "OEsmall"}, {0x00d3, "Oacute"}, - {0x00d3, "Oacutesmall"}, + {0xf7f3, "Oacutesmall"}, {0x014e, "Obreve"}, {0x00d4, "Ocircumflex"}, - {0x00d4, "Ocircumflexsmall"}, + {0xf7f4, "Ocircumflexsmall"}, {0x00d6, "Odieresis"}, - {0x00d6, "Odieresissmall"}, + {0xf7f6, "Odieresissmall"}, {0xf6fb, "Ogoneksmall"}, {0x00d2, "Ograve"}, - {0x00d2, "Ogravesmall"}, + {0xf7f2, "Ogravesmall"}, {0x01a0, "Ohorn"}, {0x0150, "Ohungarumlaut"}, {0x014c, "Omacron"}, @@ -210,17 +210,17 @@ static struct { {0x038c, "Omicrontonos"}, {0x00d8, "Oslash"}, {0x01fe, "Oslashacute"}, - {0x00d8, "Oslashsmall"}, - {0x004f, "Osmall"}, + {0xf7f8, "Oslashsmall"}, + {0xf76f, "Osmall"}, {0x00d5, "Otilde"}, - {0x00d5, "Otildesmall"}, + {0xf7f5, "Otildesmall"}, {0x0050, "P"}, {0x03a6, "Phi"}, {0x03a0, "Pi"}, {0x03a8, "Psi"}, - {0x0050, "Psmall"}, + {0xf770, "Psmall"}, {0x0051, "Q"}, - {0x0051, "Qsmall"}, + {0xf771, "Qsmall"}, {0x0052, "R"}, {0x0154, "Racute"}, {0x0158, "Rcaron"}, @@ -228,7 +228,7 @@ static struct { {0x211c, "Rfraktur"}, {0x03a1, "Rho"}, {0xf6fc, "Ringsmall"}, - {0x0052, "Rsmall"}, + {0xf772, "Rsmall"}, {0x0053, "S"}, {0x250c, "SF010000"}, {0x2514, "SF020000"}, @@ -272,12 +272,12 @@ static struct { {0x256a, "SF540000"}, {0x015a, "Sacute"}, {0x0160, "Scaron"}, - {0x0160, "Scaronsmall"}, + {0xf6fd, "Scaronsmall"}, {0x015e, "Scedilla"}, {0x015c, "Scircumflex"}, {0x0218, "Scommaaccent"}, {0x03a3, "Sigma"}, - {0x0053, "Ssmall"}, + {0xf773, "Ssmall"}, {0x0054, "T"}, {0x03a4, "Tau"}, {0x0166, "Tbar"}, @@ -285,19 +285,19 @@ static struct { {0x0162, "Tcommaaccent"}, {0x0398, "Theta"}, {0x00de, "Thorn"}, - {0x00de, "Thornsmall"}, + {0xf7fe, "Thornsmall"}, {0xf6fe, "Tildesmall"}, - {0x0054, "Tsmall"}, + {0xf774, "Tsmall"}, {0x0055, "U"}, {0x00da, "Uacute"}, - {0x00da, "Uacutesmall"}, + {0xf7fa, "Uacutesmall"}, {0x016c, "Ubreve"}, {0x00db, "Ucircumflex"}, - {0x00db, "Ucircumflexsmall"}, + {0xf7fb, "Ucircumflexsmall"}, {0x00dc, "Udieresis"}, - {0x00dc, "Udieresissmall"}, + {0xf7fc, "Udieresissmall"}, {0x00d9, "Ugrave"}, - {0x00d9, "Ugravesmall"}, + {0xf7f9, "Ugravesmall"}, {0x01af, "Uhorn"}, {0x0170, "Uhungarumlaut"}, {0x016a, "Umacron"}, @@ -307,34 +307,34 @@ static struct { {0x03ab, "Upsilondieresis"}, {0x038e, "Upsilontonos"}, {0x016e, "Uring"}, - {0x0055, "Usmall"}, + {0xf775, "Usmall"}, {0x0168, "Utilde"}, {0x0056, "V"}, - {0x0056, "Vsmall"}, + {0xf776, "Vsmall"}, {0x0057, "W"}, {0x1e82, "Wacute"}, {0x0174, "Wcircumflex"}, {0x1e84, "Wdieresis"}, {0x1e80, "Wgrave"}, - {0x0057, "Wsmall"}, + {0xf777, "Wsmall"}, {0x0058, "X"}, {0x039e, "Xi"}, - {0x0058, "Xsmall"}, + {0xf778, "Xsmall"}, {0x0059, "Y"}, {0x00dd, "Yacute"}, - {0x00dd, "Yacutesmall"}, + {0xf7fd, "Yacutesmall"}, {0x0176, "Ycircumflex"}, {0x0178, "Ydieresis"}, - {0x0178, "Ydieresissmall"}, + {0xf7ff, "Ydieresissmall"}, {0x1ef2, "Ygrave"}, - {0x0059, "Ysmall"}, + {0xf779, "Ysmall"}, {0x005a, "Z"}, {0x0179, "Zacute"}, {0x017d, "Zcaron"}, - {0x017d, "Zcaronsmall"}, + {0xf6ff, "Zcaronsmall"}, {0x017b, "Zdotaccent"}, {0x0396, "Zeta"}, - {0x005a, "Zsmall"}, + {0xf77a, "Zsmall"}, {0x0022, "\""}, {0x005c, "\\"}, {0x005d, "]"}, @@ -601,7 +601,7 @@ static struct { {0x03ac, "alphatonos"}, {0x0101, "amacron"}, {0x0026, "ampersand"}, - {0x0026, "ampersandsmall"}, + {0xf726, "ampersandsmall"}, {0x2220, "angle"}, {0x2329, "angleleft"}, {0x232a, "angleright"}, @@ -668,7 +668,7 @@ static struct { {0x00b8, "cedilla"}, {0x00a2, "cent"}, {0xf6df, "centinferior"}, - {0x00a2, "centoldstyle"}, + {0xf7a2, "centoldstyle"}, {0xf6e0, "centsuperior"}, {0x03c7, "chi"}, {0x25cb, "circle"}, @@ -710,7 +710,7 @@ static struct { {0x2584, "dnblock"}, {0x0024, "dollar"}, {0xf6e3, "dollarinferior"}, - {0x0024, "dollaroldstyle"}, + {0xf724, "dollaroldstyle"}, {0xf6e4, "dollarsuperior"}, {0x20ab, "dong"}, {0x02d9, "dotaccent"}, @@ -729,7 +729,7 @@ static struct { {0x00e8, "egrave"}, {0x0038, "eight"}, {0x2088, "eightinferior"}, - {0x0038, "eightoldstyle"}, + {0xf738, "eightoldstyle"}, {0x2078, "eightsuperior"}, {0x2208, "element"}, {0x2026, "ellipsis"}, @@ -751,9 +751,9 @@ static struct { {0x0021, "exclam"}, {0x203c, "exclamdbl"}, {0x00a1, "exclamdown"}, - {0x00a1, "exclamdownsmall"}, + {0xf7a1, "exclamdownsmall"}, {0x0021, "exclamleft"}, - {0x0021, "exclamsmall"}, + {0xf721, "exclamsmall"}, {0x2203, "existential"}, {0x0066, "f"}, {0x2640, "female"}, @@ -767,13 +767,13 @@ static struct { {0x0035, "five"}, {0x215d, "fiveeighths"}, {0x2085, "fiveinferior"}, - {0x0035, "fiveoldstyle"}, + {0xf735, "fiveoldstyle"}, {0x2075, "fivesuperior"}, {0xfb02, "fl"}, {0x0192, "florin"}, {0x0034, "four"}, {0x2084, "fourinferior"}, - {0x0034, "fouroldstyle"}, + {0xf734, "fouroldstyle"}, {0x2074, "foursuperior"}, {0x2044, "fraction"}, {0x20a3, "franc"}, @@ -871,7 +871,7 @@ static struct { {0x0146, "ncommaaccent"}, {0x0039, "nine"}, {0x2089, "nineinferior"}, - {0x0039, "nineoldstyle"}, + {0xf739, "nineoldstyle"}, {0x2079, "ninesuperior"}, {0x00a0, "nonbreakingspace"}, {0x2209, "notelement"}, @@ -903,7 +903,7 @@ static struct { {0xf6dc, "onefitted"}, {0x00bd, "onehalf"}, {0x2081, "oneinferior"}, - {0x0031, "oneoldstyle"}, + {0xf731, "oneoldstyle"}, {0x00bc, "onequarter"}, {0x00b9, "onesuperior"}, {0x2153, "onethird"}, @@ -952,8 +952,8 @@ static struct { {0x0071, "q"}, {0x003f, "question"}, {0x00bf, "questiondown"}, - {0x00bf, "questiondownsmall"}, - {0x003f, "questionsmall"}, + {0xf7bf, "questiondownsmall"}, + {0xf73f, "questionsmall"}, {0x0022, "quotedbl"}, {0x201e, "quotedblbase"}, {0x201c, "quotedblleft"}, @@ -992,7 +992,7 @@ static struct { {0x0037, "seven"}, {0x215e, "seveneighths"}, {0x2087, "seveninferior"}, - {0x0037, "sevenoldstyle"}, + {0xf737, "sevenoldstyle"}, {0x2077, "sevensuperior"}, {0x2592, "shade"}, {0x03c3, "sigma"}, @@ -1000,7 +1000,7 @@ static struct { {0x223c, "similar"}, {0x0036, "six"}, {0x2086, "sixinferior"}, - {0x0036, "sixoldstyle"}, + {0xf736, "sixoldstyle"}, {0x2076, "sixsuperior"}, {0x002f, "slash"}, {0x263a, "smileface"}, @@ -1023,7 +1023,7 @@ static struct { {0x0033, "three"}, {0x215c, "threeeighths"}, {0x2083, "threeinferior"}, - {0x0033, "threeoldstyle"}, + {0xf733, "threeoldstyle"}, {0x00be, "threequarters"}, {0xf6de, "threequartersemdash"}, {0x00b3, "threesuperior"}, @@ -1041,7 +1041,7 @@ static struct { {0x0032, "two"}, {0x2025, "twodotenleader"}, {0x2082, "twoinferior"}, - {0x0032, "twooldstyle"}, + {0xf732, "twooldstyle"}, {0x00b2, "twosuperior"}, {0x2154, "twothirds"}, {0x0075, "u"}, @@ -1086,7 +1086,7 @@ static struct { {0x017c, "zdotaccent"}, {0x0030, "zero"}, {0x2080, "zeroinferior"}, - {0x0030, "zerooldstyle"}, + {0xf730, "zerooldstyle"}, {0x2070, "zerosuperior"}, {0x03b6, "zeta"}, {0x007b, "{"}, diff --git a/pdf2swf/xpdf/Object.cc b/pdf2swf/xpdf/Object.cc index ddd6da6..71c632a 100644 --- a/pdf2swf/xpdf/Object.cc +++ b/pdf2swf/xpdf/Object.cc @@ -161,7 +161,7 @@ void Object::print(FILE *f) { break; case objString: fprintf(f, "("); - fwrite(string->getCString(), 1, string->getLength(), stdout); + fwrite(string->getCString(), 1, string->getLength(), f); fprintf(f, ")"); break; case objName: diff --git a/pdf2swf/xpdf/Outline.cc b/pdf2swf/xpdf/Outline.cc index 04891f3..39e89a3 100644 --- a/pdf2swf/xpdf/Outline.cc +++ b/pdf2swf/xpdf/Outline.cc @@ -58,14 +58,14 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { if ((s->getChar(0) & 0xff) == 0xfe && (s->getChar(1) & 0xff) == 0xff) { titleLen = (s->getLength() - 2) / 2; - title = (Unicode *)gmalloc(titleLen * sizeof(Unicode)); + title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); for (i = 0; i < titleLen; ++i) { title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | (s->getChar(3 + 2*i) & 0xff); } } else { titleLen = s->getLength(); - title = (Unicode *)gmalloc(titleLen * sizeof(Unicode)); + title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); for (i = 0; i < titleLen; ++i) { title[i] = pdfDocEncoding[s->getChar(i) & 0xff]; } @@ -79,7 +79,7 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { action = LinkAction::parseDest(&obj1); } else { obj1.free(); - if (dict->lookup("A", &obj1)) { + if (!dict->lookup("A", &obj1)->isNull()) { action = LinkAction::parseAction(&obj1); } } diff --git a/pdf2swf/xpdf/OutputDev.cc b/pdf2swf/xpdf/OutputDev.cc index e83882d..cfa4161 100644 --- a/pdf2swf/xpdf/OutputDev.cc +++ b/pdf2swf/xpdf/OutputDev.cc @@ -55,8 +55,15 @@ void OutputDev::updateAll(GfxState *state) { updateLineCap(state); updateMiterLimit(state); updateLineWidth(state); + updateFillColorSpace(state); updateFillColor(state); + updateStrokeColorSpace(state); updateStrokeColor(state); + updateBlendMode(state); + updateFillOpacity(state); + updateStrokeOpacity(state); + updateFillOverprint(state); + updateStrokeOverprint(state); updateFont(state); } @@ -95,6 +102,24 @@ void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str, } } +void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GBool maskInvert) { + drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); +} + +void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap) { + drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); +} + #if OPI_SUPPORT void OutputDev::opiBegin(GfxState *state, Dict *opiDict) { } diff --git a/pdf2swf/xpdf/PDFDoc.cc b/pdf2swf/xpdf/PDFDoc.cc index b5981d9..92863e4 100644 --- a/pdf2swf/xpdf/PDFDoc.cc +++ b/pdf2swf/xpdf/PDFDoc.cc @@ -16,6 +16,9 @@ #include #include #include +#ifdef WIN32 +# include +#endif #include "GString.h" #include "config.h" #include "GlobalParams.h" @@ -29,6 +32,7 @@ #include "ErrorCodes.h" #include "Lexer.h" #include "Parser.h" +#include "SecurityHandler.h" #ifndef DISABLE_OUTLINE #include "Outline.h" #endif @@ -44,13 +48,15 @@ //------------------------------------------------------------------------ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, - GString *userPassword) { + GString *userPassword, void *guiDataA) { Object obj; GString *fileName1, *fileName2; ok = gFalse; errCode = errNone; + guiData = guiDataA; + file = NULL; str = NULL; xref = NULL; @@ -96,10 +102,68 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, ok = setup(ownerPassword, userPassword); } +#ifdef WIN32 +PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, + GString *userPassword, void *guiDataA) { + OSVERSIONINFO version; + wchar_t fileName2[_MAX_PATH + 1]; + Object obj; + int i; + + ok = gFalse; + errCode = errNone; + + guiData = guiDataA; + + file = NULL; + str = NULL; + xref = NULL; + catalog = NULL; + links = NULL; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif + + //~ file name should be stored in Unicode (?) + fileName = new GString(); + for (i = 0; i < fileNameLen; ++i) { + fileName->append((char)fileNameA[i]); + } + + // zero-terminate the file name string + for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) { + fileName2[i] = fileNameA[i]; + } + fileName2[i] = 0; + + // try to open file + // NB: _wfopen is only available in NT + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx(&version); + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { + file = _wfopen(fileName2, L"rb"); + } else { + file = fopen(fileName->getCString(), "rb"); + } + if (!file) { + error(-1, "Couldn't open file '%s'", fileName->getCString()); + errCode = errOpenFile; + return; + } + + // create stream + obj.initNull(); + str = new FileStream(file, 0, gFalse, 0, &obj); + + ok = setup(ownerPassword, userPassword); +} +#endif + PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, - GString *userPassword) { + GString *userPassword, void *guiDataA) { ok = gFalse; errCode = errNone; + guiData = guiDataA; fileName = NULL; file = NULL; str = strA; @@ -119,13 +183,19 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { checkHeader(); // read xref table - xref = new XRef(str, ownerPassword, userPassword); + xref = new XRef(str); if (!xref->isOk()) { error(-1, "Couldn't read xref table"); errCode = xref->getErrorCode(); return gFalse; } + // check for encryption + if (!checkEncryption(ownerPassword, userPassword)) { + errCode = errEncrypted; + return gFalse; + } + // read catalog catalog = new Catalog(xref); if (!catalog->isOk()) { @@ -191,7 +261,10 @@ void PDFDoc::checkHeader() { return; } str->moveStart(i); - p = strtok(&hdrBuf[i+5], " \t\n\r"); + if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) { + error(-1, "May not be a PDF file (continuing anyway)"); + return; + } pdfVersion = atof(p); if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') || pdfVersion > supportedPDFVersionNum + 0.0001) { @@ -200,8 +273,43 @@ void PDFDoc::checkHeader() { } } +GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { + Object encrypt; + GBool encrypted; + SecurityHandler *secHdlr; + GBool ret; + + xref->getTrailerDict()->dictLookup("Encrypt", &encrypt); + if ((encrypted = encrypt.isDict())) { + if ((secHdlr = SecurityHandler::make(this, &encrypt))) { + if (secHdlr->checkEncryption(ownerPassword, userPassword)) { + // authorization succeeded + xref->setEncryption(secHdlr->getPermissionFlags(), + secHdlr->getOwnerPasswordOk(), + secHdlr->getFileKey(), + secHdlr->getFileKeyLength(), + secHdlr->getEncVersion()); + ret = gTrue; + } else { + // authorization failed + ret = gFalse; + } + delete secHdlr; + } else { + // couldn't find the matching security handler + ret = gFalse; + } + } else { + // document is not encrypted + ret = gTrue; + } + encrypt.free(); + return ret; +} + void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool crop, GBool doLinks, + int rotate, GBool useMediaBox, GBool crop, + GBool doLinks, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { Page *p; @@ -215,39 +323,57 @@ void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, delete links; } getLinks(p); - p->display(out, hDPI, vDPI, rotate, crop, links, catalog, + p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog, abortCheckCbk, abortCheckCbkData); } else { - p->display(out, hDPI, vDPI, rotate, crop, NULL, catalog, + p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog, abortCheckCbk, abortCheckCbkData); } } void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, double hDPI, double vDPI, int rotate, - GBool crop, GBool doLinks, + GBool useMediaBox, GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { int page; for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, hDPI, vDPI, rotate, crop, doLinks, + displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks, abortCheckCbk, abortCheckCbkData); } } void PDFDoc::displayPageSlice(OutputDev *out, int page, - double hDPI, double vDPI, - int rotate, GBool crop, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool doLinks, 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); + if (doLinks) { + if (links) { + delete links; + } + getLinks(p); + p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + links, catalog, abortCheckCbk, abortCheckCbkData); + } else { + p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + NULL, catalog, abortCheckCbk, abortCheckCbkData); + } +} + +Links *PDFDoc::takeLinks() { + Links *ret; + + ret = links; + links = NULL; + return ret; } GBool PDFDoc::isLinearized() { diff --git a/pdf2swf/xpdf/PDFDoc.h b/pdf2swf/xpdf/PDFDoc.h index bdcbd65..a1f42c0 100644 --- a/pdf2swf/xpdf/PDFDoc.h +++ b/pdf2swf/xpdf/PDFDoc.h @@ -17,7 +17,6 @@ #include #include "XRef.h" -#include "Link.h" #include "Catalog.h" #include "Page.h" @@ -37,9 +36,13 @@ class PDFDoc { public: PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, - GString *userPassword = NULL); + GString *userPassword = NULL, void *guiDataA = NULL); +#ifdef WIN32 + PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL, + GString *userPassword = NULL, void *guiDataA = NULL); +#endif PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, - GString *userPassword = NULL); + GString *userPassword = NULL, void *guiDataA = NULL); ~PDFDoc(); // Was PDF document successfully opened? @@ -61,10 +64,14 @@ public: BaseStream *getBaseStream() { return str; } // Get page parameters. - double getPageWidth(int page) - { return catalog->getPage(page)->getWidth(); } - double getPageHeight(int page) - { return catalog->getPage(page)->getHeight(); } + double getPageMediaWidth(int page) + { return catalog->getPage(page)->getMediaWidth(); } + double getPageMediaHeight(int page) + { return catalog->getPage(page)->getMediaHeight(); } + double getPageCropWidth(int page) + { return catalog->getPage(page)->getCropWidth(); } + double getPageCropHeight(int page) + { return catalog->getPage(page)->getCropHeight(); } int getPageRotate(int page) { return catalog->getPage(page)->getRotate(); } @@ -80,21 +87,22 @@ public: // Display a page. void displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool crop, GBool doLinks, + int rotate, GBool useMediaBox, 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, double hDPI, double vDPI, int rotate, - GBool crop, GBool doLinks, + GBool useMediaBox, 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, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool doLinks, int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); @@ -103,13 +111,9 @@ public: // not found. int findPage(int num, int gen) { return catalog->findPage(num, gen); } - // If point , is in a link, return the associated action; - // else return NULL. - 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); } + // Returns the links for the current page, transferring ownership to + // the caller. + Links *takeLinks(); // Find a named destination. Returns the link destination, or // NULL if is not a destination. @@ -147,16 +151,21 @@ public: // Save this file with another name. GBool saveAs(GString *name); + // Return a pointer to the GUI (XPDFCore or WinPDFCore object). + void *getGUIData() { return guiData; } + private: GBool setup(GString *ownerPassword, GString *userPassword); void checkHeader(); + GBool checkEncryption(GString *ownerPassword, GString *userPassword); void getLinks(Page *page); GString *fileName; FILE *file; BaseStream *str; + void *guiData; double pdfVersion; XRef *xref; Catalog *catalog; diff --git a/pdf2swf/xpdf/Page.h b/pdf2swf/xpdf/Page.h index 2376cb4..36f96e1 100644 --- a/pdf2swf/xpdf/Page.h +++ b/pdf2swf/xpdf/Page.h @@ -51,7 +51,6 @@ public: ~PageAttrs(); // Accessors. - PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; } PDFRectangle *getMediaBox() { return &mediaBox; } PDFRectangle *getCropBox() { return &cropBox; } GBool isCropped() { return haveCropBox; } @@ -83,7 +82,6 @@ private: PDFRectangle mediaBox; PDFRectangle cropBox; GBool haveCropBox; - GBool limitToCropBox; PDFRectangle bleedBox; PDFRectangle trimBox; PDFRectangle artBox; @@ -114,12 +112,17 @@ public: GBool isOk() { return ok; } // Get page parameters. - PDFRectangle *getBox() { return attrs->getBox(); } PDFRectangle *getMediaBox() { return attrs->getMediaBox(); } PDFRectangle *getCropBox() { return attrs->getCropBox(); } GBool isCropped() { return attrs->isCropped(); } - double getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; } - double getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; } + double getMediaWidth() + { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; } + double getMediaHeight() + { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; } + double getCropWidth() + { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; } + double getCropHeight() + { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; } PDFRectangle *getBleedBox() { return attrs->getBleedBox(); } PDFRectangle *getTrimBox() { return attrs->getTrimBox(); } PDFRectangle *getArtBox() { return attrs->getArtBox(); } @@ -142,19 +145,23 @@ public: // Display a page. void display(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, + int rotate, GBool useMediaBox, 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 rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); + // Get the page's default CTM. + void getDefaultCTM(double *ctm, double hDPI, double vDPI, + int rotate, GBool upsideDown); + private: XRef *xref; // the xref table for this PDF file diff --git a/pdf2swf/xpdf/Parser.cc b/pdf2swf/xpdf/Parser.cc index 0aa66d3..af7c933 100644 --- a/pdf2swf/xpdf/Parser.cc +++ b/pdf2swf/xpdf/Parser.cc @@ -19,9 +19,7 @@ #include "Parser.h" #include "XRef.h" #include "Error.h" -#ifndef NO_DECRYPTION #include "Decrypt.h" -#endif Parser::Parser(XRef *xrefA, Lexer *lexerA) { xref = xrefA; @@ -37,23 +35,17 @@ Parser::~Parser() { delete lexer; } -#ifndef NO_DECRYPTION Object *Parser::getObj(Object *obj, Guchar *fileKey, int keyLength, int objNum, int objGen) { -#else -Object *Parser::getObj(Object *obj) { -#endif char *key; Stream *str; Object obj2; int num; -#ifndef NO_DECRYPTION Decrypt *decrypt; GString *s; char *p; int i; -#endif // refill buffer after inline image data if (inlineImg == 2) { @@ -69,11 +61,7 @@ Object *Parser::getObj(Object *obj) { shift(); obj->initArray(xref); while (!buf1.isCmd("]") && !buf1.isEOF()) -#ifndef NO_DECRYPTION obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen)); -#else - obj->arrayAdd(getObj(&obj2)); -#endif if (buf1.isEOF()) error(getPos(), "End of file inside array"); shift(); @@ -93,11 +81,7 @@ Object *Parser::getObj(Object *obj) { gfree(key); break; } -#ifndef NO_DECRYPTION obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); -#else - obj->dictAdd(key, getObj(&obj2)); -#endif } } if (buf1.isEOF()) @@ -105,12 +89,10 @@ Object *Parser::getObj(Object *obj) { if (buf2.isCmd("stream")) { if ((str = makeStream(obj))) { obj->initStream(str); -#ifndef NO_DECRYPTION if (fileKey) { str->getBaseStream()->doDecryption(fileKey, keyLength, objNum, objGen); } -#endif } else { obj->free(); obj->initError(); @@ -131,7 +113,6 @@ Object *Parser::getObj(Object *obj) { obj->initInt(num); } -#ifndef NO_DECRYPTION // string } else if (buf1.isString() && fileKey) { buf1.copy(obj); @@ -144,7 +125,6 @@ Object *Parser::getObj(Object *obj) { } delete decrypt; shift(); -#endif // simple object } else { @@ -157,6 +137,7 @@ Object *Parser::getObj(Object *obj) { Stream *Parser::makeStream(Object *dict) { Object obj; + BaseStream *baseStr; Stream *str; Guint pos, endPos, length; @@ -185,13 +166,7 @@ Stream *Parser::makeStream(Object *dict) { if (!lexer->getStream()) { return NULL; } - - // make base stream - str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue, - length, dict); - - // get filters - str = str->addFilters(dict); + baseStr = lexer->getStream()->getBaseStream(); // skip over stream data lexer->setPos(pos + length); @@ -203,9 +178,17 @@ Stream *Parser::makeStream(Object *dict) { shift(); } else { error(getPos(), "Missing 'endstream'"); - str->ignoreLength(); + // kludge for broken PDF files: just add 5k to the length, and + // hope its enough + length += 5000; } + // make base stream + str = baseStr->makeSubStream(pos, gTrue, length, dict); + + // get filters + str = str->addFilters(dict); + return str; } diff --git a/pdf2swf/xpdf/Parser.h b/pdf2swf/xpdf/Parser.h index 3bc3ab2..b583baf 100644 --- a/pdf2swf/xpdf/Parser.h +++ b/pdf2swf/xpdf/Parser.h @@ -31,13 +31,9 @@ public: ~Parser(); // Get the next object from the input stream. -#ifndef NO_DECRYPTION Object *getObj(Object *obj, Guchar *fileKey = NULL, int keyLength = 0, int objNum = 0, int objGen = 0); -#else - Object *getObj(Object *obj); -#endif // Get stream. Stream *getStream() { return lexer->getStream(); } diff --git a/pdf2swf/xpdf/SecurityHandler.cc b/pdf2swf/xpdf/SecurityHandler.cc new file mode 100644 index 0000000..8825ce8 --- /dev/null +++ b/pdf2swf/xpdf/SecurityHandler.cc @@ -0,0 +1,376 @@ +//======================================================================== +// +// SecurityHandler.cc +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "GString.h" +#include "PDFDoc.h" +#include "Decrypt.h" +#include "Error.h" +#include "GlobalParams.h" +#if HAVE_XPDFCORE +# include "XPDFCore.h" +#elif HAVE_WINPDFCORE +# include "WinPDFCore.h" +#endif +#ifdef ENABLE_PLUGINS +# include "XpdfPluginAPI.h" +#endif +#include "SecurityHandler.h" + +//------------------------------------------------------------------------ +// SecurityHandler +//------------------------------------------------------------------------ + +SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) { + Object filterObj; + SecurityHandler *secHdlr; + XpdfSecurityHandler *xsh; + + encryptDictA->dictLookup("Filter", &filterObj); + if (filterObj.isName("Standard")) { + secHdlr = new StandardSecurityHandler(docA, encryptDictA); + } else if (filterObj.isName()) { +#ifdef ENABLE_PLUGINS + if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) { + secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh); + } else { +#endif + error(-1, "Couldn't find the '%s' security handler", + filterObj.getName()); + secHdlr = NULL; +#ifdef ENABLE_PLUGINS + } +#endif + } else { + error(-1, "Missing or invalid 'Filter' entry in encryption dictionary"); + secHdlr = NULL; + } + filterObj.free(); + return secHdlr; +} + +SecurityHandler::SecurityHandler(PDFDoc *docA) { + doc = docA; +} + +SecurityHandler::~SecurityHandler() { +} + +GBool SecurityHandler::checkEncryption(GString *ownerPassword, + GString *userPassword) { + void *authData; + GBool ok; + int i; + + if (ownerPassword || userPassword) { + authData = makeAuthData(ownerPassword, userPassword); + } else { + authData = NULL; + } + ok = authorize(authData); + if (authData) { + freeAuthData(authData); + } + for (i = 0; !ok && i < 3; ++i) { + if (!(authData = getAuthData())) { + break; + } + ok = authorize(authData); + if (authData) { + freeAuthData(authData); + } + } + if (!ok) { + error(-1, "Incorrect password"); + } + return ok; +} + +//------------------------------------------------------------------------ +// StandardSecurityHandler +//------------------------------------------------------------------------ + +class StandardAuthData { +public: + + StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) { + ownerPassword = ownerPasswordA; + userPassword = userPasswordA; + } + + ~StandardAuthData() { + if (ownerPassword) { + delete ownerPassword; + } + if (userPassword) { + delete userPassword; + } + } + + GString *ownerPassword; + GString *userPassword; +}; + +StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, + Object *encryptDictA): + SecurityHandler(docA) +{ + Object versionObj, revisionObj, lengthObj; + Object ownerKeyObj, userKeyObj, permObj, fileIDObj; + Object fileIDObj1; + Object cryptFiltersObj, streamFilterObj, stringFilterObj; + Object cryptFilterObj, cfmObj, cfLengthObj; + Object encryptMetadataObj; + + ok = gFalse; + fileID = NULL; + ownerKey = NULL; + userKey = NULL; + + encryptDictA->dictLookup("V", &versionObj); + encryptDictA->dictLookup("R", &revisionObj); + encryptDictA->dictLookup("Length", &lengthObj); + encryptDictA->dictLookup("O", &ownerKeyObj); + encryptDictA->dictLookup("U", &userKeyObj); + encryptDictA->dictLookup("P", &permObj); + doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj); + if (versionObj.isInt() && + revisionObj.isInt() && + ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 && + userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 && + permObj.isInt()) { + encVersion = versionObj.getInt(); + encRevision = revisionObj.getInt(); + // revision 2 forces a 40-bit key - some buggy PDF generators + // set the Length value incorrectly + if (encRevision == 2 || !lengthObj.isInt()) { + fileKeyLength = 5; + } else { + fileKeyLength = lengthObj.getInt() / 8; + } + encryptMetadata = gTrue; + //~ this currently only handles a subset of crypt filter functionality + if (encVersion == 4 && encRevision == 4) { + encryptDictA->dictLookup("CF", &cryptFiltersObj); + encryptDictA->dictLookup("StmF", &streamFilterObj); + encryptDictA->dictLookup("StrF", &stringFilterObj); + if (cryptFiltersObj.isDict() && + streamFilterObj.isName() && + stringFilterObj.isName() && + !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { + if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), + &cryptFilterObj)->isDict()) { + if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) { + encVersion = 2; + encRevision = 3; + if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { + //~ according to the spec, this should be cfLengthObj / 8 + fileKeyLength = cfLengthObj.getInt(); + } + cfLengthObj.free(); + } + cfmObj.free(); + } + cryptFilterObj.free(); + } + stringFilterObj.free(); + streamFilterObj.free(); + cryptFiltersObj.free(); + if (encryptDictA->dictLookup("EncryptMetadata", + &encryptMetadataObj)->isBool()) { + encryptMetadata = encryptMetadataObj.getBool(); + } + encryptMetadataObj.free(); + } + permFlags = permObj.getInt(); + ownerKey = ownerKeyObj.getString()->copy(); + userKey = userKeyObj.getString()->copy(); + if (encVersion >= 1 && encVersion <= 2 && + encRevision >= 2 && encRevision <= 3) { + if (fileIDObj.isArray()) { + if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) { + fileID = fileIDObj1.getString()->copy(); + } else { + fileID = new GString(); + } + fileIDObj1.free(); + } else { + fileID = new GString(); + } + ok = gTrue; + } else { + error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", + encVersion, encRevision); + } + } else { + error(-1, "Weird encryption info"); + } + if (fileKeyLength > 16) { + fileKeyLength = 16; + } + fileIDObj.free(); + permObj.free(); + userKeyObj.free(); + ownerKeyObj.free(); + lengthObj.free(); + revisionObj.free(); + versionObj.free(); +} + +StandardSecurityHandler::~StandardSecurityHandler() { + if (fileID) { + delete fileID; + } + if (ownerKey) { + delete ownerKey; + } + if (userKey) { + delete userKey; + } +} + +void *StandardSecurityHandler::makeAuthData(GString *ownerPassword, + GString *userPassword) { + return new StandardAuthData(ownerPassword ? ownerPassword->copy() + : (GString *)NULL, + userPassword ? userPassword->copy() + : (GString *)NULL); +} + +void *StandardSecurityHandler::getAuthData() { +#if HAVE_XPDFCORE + XPDFCore *core; + GString *password; + + if (!(core = (XPDFCore *)doc->getGUIData()) || + !(password = core->getPassword())) { + return NULL; + } + return new StandardAuthData(password, password->copy()); +#elif HAVE_WINPDFCORE + WinPDFCore *core; + GString *password; + + if (!(core = (WinPDFCore *)doc->getGUIData()) || + !(password = core->getPassword())) { + return NULL; + } + return new StandardAuthData(password, password->copy()); +#else + return NULL; +#endif +} + +void StandardSecurityHandler::freeAuthData(void *authData) { + delete (StandardAuthData *)authData; +} + +GBool StandardSecurityHandler::authorize(void *authData) { + GString *ownerPassword, *userPassword; + + if (!ok) { + return gFalse; + } + if (authData) { + ownerPassword = ((StandardAuthData *)authData)->ownerPassword; + userPassword = ((StandardAuthData *)authData)->userPassword; + } else { + ownerPassword = NULL; + userPassword = NULL; + } + if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength, + ownerKey, userKey, permFlags, fileID, + ownerPassword, userPassword, fileKey, + encryptMetadata, &ownerPasswordOk)) { + return gFalse; + } + return gTrue; +} + +#ifdef ENABLE_PLUGINS + +//------------------------------------------------------------------------ +// ExternalSecurityHandler +//------------------------------------------------------------------------ + +ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA, + Object *encryptDictA, + XpdfSecurityHandler *xshA): + SecurityHandler(docA) +{ + encryptDictA->copy(&encryptDict); + xsh = xshA; + ok = gFalse; + + if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA, + (XpdfObject)encryptDictA, &docData)) { + return; + } + + ok = gTrue; +} + +ExternalSecurityHandler::~ExternalSecurityHandler() { + (*xsh->freeDoc)(xsh->handlerData, docData); + encryptDict.free(); +} + +void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword, + GString *userPassword) { + char *opw, *upw; + void *authData; + + opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL; + upw = userPassword ? userPassword->getCString() : (char *)NULL; + if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) { + return NULL; + } + return authData; +} + +void *ExternalSecurityHandler::getAuthData() { + void *authData; + + if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) { + return NULL; + } + return authData; +} + +void ExternalSecurityHandler::freeAuthData(void *authData) { + (*xsh->freeAuthData)(xsh->handlerData, docData, authData); +} + +GBool ExternalSecurityHandler::authorize(void *authData) { + char *key; + int length; + + if (!ok) { + return gFalse; + } + permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData); + if (!(permFlags & xpdfPermissionOpen)) { + return gFalse; + } + if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) { + return gFalse; + } + if ((fileKeyLength = length) > 16) { + fileKeyLength = 16; + } + memcpy(fileKey, key, fileKeyLength); + (*xsh->freeKey)(xsh->handlerData, docData, key, length); + return gTrue; +} + +#endif // ENABLE_PLUGINS diff --git a/pdf2swf/xpdf/SecurityHandler.h b/pdf2swf/xpdf/SecurityHandler.h new file mode 100644 index 0000000..127acb7 --- /dev/null +++ b/pdf2swf/xpdf/SecurityHandler.h @@ -0,0 +1,155 @@ +//======================================================================== +// +// SecurityHandler.h +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SECURITYHANDLER_H +#define SECURITYHANDLER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" + +class GString; +class PDFDoc; +struct XpdfSecurityHandler; + +//------------------------------------------------------------------------ +// SecurityHandler +//------------------------------------------------------------------------ + +class SecurityHandler { +public: + + static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA); + + SecurityHandler(PDFDoc *docA); + virtual ~SecurityHandler(); + + // Check the document's encryption. If the document is encrypted, + // this will first try and (in + // "batch" mode), and if those fail, it will attempt to request a + // password from the user. This is the high-level function that + // calls the lower level functions for the specific security handler + // (requesting a password three times, etc.). Returns true if the + // document can be opened (if it's unencrypted, or if a correct + // password is obtained); false otherwise (encrypted and no correct + // password). + GBool checkEncryption(GString *ownerPassword, + GString *userPassword); + + // Create authorization data for the specified owner and user + // passwords. If the security handler doesn't support "batch" mode, + // this function should return NULL. + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword) = 0; + + // Construct authorization data, typically by prompting the user for + // a password. Returns an authorization data object, or NULL to + // cancel. + virtual void *getAuthData() = 0; + + // Free the authorization data returned by makeAuthData or + // getAuthData. + virtual void freeAuthData(void *authData) = 0; + + // Attempt to authorize the document, using the supplied + // authorization data (which may be NULL). Returns true if + // successful (i.e., if at least the right to open the document was + // granted). + virtual GBool authorize(void *authData) = 0; + + // Return the various authorization parameters. These are only + // valid after authorize has returned true. + virtual int getPermissionFlags() = 0; + virtual GBool getOwnerPasswordOk() = 0; + virtual Guchar *getFileKey() = 0; + virtual int getFileKeyLength() = 0; + virtual int getEncVersion() = 0; + +protected: + + PDFDoc *doc; +}; + +//------------------------------------------------------------------------ +// StandardSecurityHandler +//------------------------------------------------------------------------ + +class StandardSecurityHandler: public SecurityHandler { +public: + + StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA); + virtual ~StandardSecurityHandler(); + + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword); + virtual void *getAuthData(); + virtual void freeAuthData(void *authData); + virtual GBool authorize(void *authData); + virtual int getPermissionFlags() { return permFlags; } + virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; } + virtual Guchar *getFileKey() { return fileKey; } + virtual int getFileKeyLength() { return fileKeyLength; } + virtual int getEncVersion() { return encVersion; } + +private: + + int permFlags; + GBool ownerPasswordOk; + Guchar fileKey[16]; + int fileKeyLength; + int encVersion; + int encRevision; + GBool encryptMetadata; + + GString *ownerKey, *userKey; + GString *fileID; + GBool ok; +}; + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// ExternalSecurityHandler +//------------------------------------------------------------------------ + +class ExternalSecurityHandler: public SecurityHandler { +public: + + ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA, + XpdfSecurityHandler *xshA); + virtual ~ExternalSecurityHandler(); + + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword); + virtual void *getAuthData(); + virtual void freeAuthData(void *authData); + virtual GBool authorize(void *authData); + virtual int getPermissionFlags() { return permFlags; } + virtual GBool getOwnerPasswordOk() { return gFalse; } + virtual Guchar *getFileKey() { return fileKey; } + virtual int getFileKeyLength() { return fileKeyLength; } + virtual int getEncVersion() { return encVersion; } + +private: + + Object encryptDict; + XpdfSecurityHandler *xsh; + void *docData; + int permFlags; + Guchar fileKey[16]; + int fileKeyLength; + int encVersion; + GBool ok; +}; +#endif // ENABLE_PLUGINS + +#endif diff --git a/pdf2swf/xpdf/Stream.h b/pdf2swf/xpdf/Stream.h index 0b70afa..e1e7bae 100644 --- a/pdf2swf/xpdf/Stream.h +++ b/pdf2swf/xpdf/Stream.h @@ -19,9 +19,7 @@ #include "gtypes.h" #include "Object.h" -#ifndef NO_DECRYPTION class Decrypt; -#endif class BaseStream; //------------------------------------------------------------------------ @@ -40,6 +38,13 @@ enum StreamKind { strWeird // internal-use stream types }; +enum StreamColorSpaceMode { + streamCSNone, + streamCSDeviceGray, + streamCSDeviceRGB, + streamCSDeviceCMYK +}; + //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ @@ -102,15 +107,14 @@ public: // Is this an encoding filter? virtual GBool isEncoder() { return gFalse; } + // Get image parameters which are defined by the stream contents. + virtual void getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode) {} + // Add filters to this stream according to the parameters in . // 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); @@ -140,17 +144,13 @@ public: virtual Guint getStart() = 0; virtual void moveStart(int delta) = 0; -#ifndef NO_DECRYPTION // Set decryption for this stream. virtual void doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen); -#endif -#ifndef NO_DECRYPTION protected: Decrypt *decrypt; -#endif private: @@ -173,7 +173,6 @@ 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: @@ -233,6 +232,8 @@ public: ~StreamPredictor(); + GBool isOk() { return ok; } + int lookChar(); int getChar(); @@ -250,6 +251,7 @@ private: int rowBytes; // bytes per line Guchar *predLine; // line buffer int predIdx; // current index in predLine + GBool ok; }; //------------------------------------------------------------------------ @@ -275,7 +277,6 @@ public: { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual int getPos() { return bufPos + (bufPtr - buf); } virtual void setPos(Guint pos, int dir = 0); - virtual void ignoreLength() { limited = gFalse; } virtual Guint getStart() { return start; } virtual void moveStart(int delta); @@ -317,10 +318,8 @@ public: virtual void setPos(Guint pos, int dir = 0); virtual Guint getStart() { return start; } virtual void moveStart(int delta); -#ifndef NO_DECRYPTION virtual void doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen); -#endif private: @@ -591,7 +590,7 @@ private: 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 + Gushort quantTables[4][64]; // quantization tables int numQuantTables; // number of quantization tables DCTHuffTable dcHuffTables[4]; // DC Huffman tables DCTHuffTable acHuffTables[4]; // AC Huffman tables @@ -616,7 +615,7 @@ private: DCTHuffTable *acHuffTable, int *prevDC, int data[64]); void decodeImage(); - void transformDataUnit(Guchar *quantTable, + void transformDataUnit(Gushort *quantTable, int dataIn[64], Guchar dataOut[64]); int readHuffSym(DCTHuffTable *table); int readAmp(int size); @@ -700,6 +699,10 @@ private: lengthDecode[flateMaxLitCodes-257]; static FlateDecode // distance decoding info distDecode[flateMaxDistCodes]; + static FlateHuffmanTab // fixed literal code table + fixedLitCodeTab; + static FlateHuffmanTab // fixed distance code table + fixedDistCodeTab; void readSome(); GBool startBlock(); diff --git a/pdf2swf/xpdf/UnicodeMap.cc b/pdf2swf/xpdf/UnicodeMap.cc index 300d802..2b8cb1f 100644 --- a/pdf2swf/xpdf/UnicodeMap.cc +++ b/pdf2swf/xpdf/UnicodeMap.cc @@ -53,7 +53,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { map = new UnicodeMap(encodingNameA->copy()); size = 8; - map->ranges = (UnicodeMapRange *)gmalloc(size * sizeof(UnicodeMapRange)); + map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange)); eMapsSize = 0; line = 1; @@ -69,7 +69,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { if (map->len == size) { size *= 2; map->ranges = (UnicodeMapRange *) - grealloc(map->ranges, size * sizeof(UnicodeMapRange)); + greallocn(map->ranges, size, sizeof(UnicodeMapRange)); } range = &map->ranges[map->len]; sscanf(tok1, "%x", &range->start); @@ -81,7 +81,7 @@ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { if (map->eMapsLen == eMapsSize) { eMapsSize += 16; map->eMaps = (UnicodeMapExt *) - grealloc(map->eMaps, eMapsSize * sizeof(UnicodeMapExt)); + greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt)); } eMap = &map->eMaps[map->eMapsLen]; sscanf(tok1, "%x", &eMap->u); diff --git a/pdf2swf/xpdf/UnicodeMap.h b/pdf2swf/xpdf/UnicodeMap.h index 6fd4ed2..0f86101 100644 --- a/pdf2swf/xpdf/UnicodeMap.h +++ b/pdf2swf/xpdf/UnicodeMap.h @@ -95,7 +95,7 @@ private: UnicodeMapExt *eMaps; // (user) int eMapsLen; // (user) int refCnt; -#ifdef MULTITHREADED +#if MULTITHREADED GMutex mutex; #endif }; diff --git a/pdf2swf/xpdf/XRef.cc b/pdf2swf/xpdf/XRef.cc index e0d82d2..b371541 100644 --- a/pdf2swf/xpdf/XRef.cc +++ b/pdf2swf/xpdf/XRef.cc @@ -22,9 +22,6 @@ #include "Lexer.h" #include "Parser.h" #include "Dict.h" -#ifndef NO_DECRYPTION -#include "Decrypt.h" -#endif #include "Error.h" #include "ErrorCodes.h" #include "XRef.h" @@ -34,7 +31,6 @@ #define xrefSearchSize 1024 // read this many bytes at end of file // to look for 'startxref' -#ifndef NO_DECRYPTION //------------------------------------------------------------------------ // Permission bits //------------------------------------------------------------------------ @@ -44,7 +40,6 @@ #define permCopy (1<<4) #define permNotes (1<<5) #define defPermFlags 0xfffc -#endif //------------------------------------------------------------------------ // ObjectStream @@ -96,7 +91,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { } nObjects = obj1.getInt(); obj1.free(); - if (nObjects == 0) { + if (nObjects <= 0) { goto err1; } @@ -106,10 +101,13 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { } first = obj1.getInt(); obj1.free(); + if (first < 0) { + goto err1; + } objs = new Object[nObjects]; - objNums = (int *)gmalloc(nObjects * sizeof(int)); - offsets = (int *)gmalloc(nObjects * sizeof(int)); + objNums = (int *)gmallocn(nObjects, sizeof(int)); + offsets = (int *)gmallocn(nObjects, sizeof(int)); // parse the header: object numbers and offsets objStr.streamReset(); @@ -130,6 +128,12 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { offsets[i] = obj2.getInt(); obj1.free(); obj2.free(); + if (objNums[i] < 0 || offsets[i] < 0 || + (i > 0 && offsets[i] < offsets[i-1])) { + delete parser; + gfree(offsets); + goto err1; + } } while (str->getChar() != EOF) ; delete parser; @@ -186,7 +190,7 @@ Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { // XRef //------------------------------------------------------------------------ -XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { +XRef::XRef(BaseStream *strA) { Guint pos; Object obj; @@ -198,6 +202,10 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { streamEndsLen = 0; objStr = NULL; + encrypted = gFalse; + permFlags = defPermFlags; + ownerPasswordOk = gFalse; + // read the trailer str = strA; start = str->getStart(); @@ -242,16 +250,6 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { // now set the trailer dictionary's xref pointer so we can fetch // indirect objects from it trailerDict.getDict()->setXRef(this); - - // check for encryption -#ifndef NO_DECRYPTION - encrypted = gFalse; -#endif - if (checkEncrypted(ownerPassword, userPassword)) { - ok = gFalse; - errCode = errEncrypted; - return; - } } XRef::~XRef() { @@ -369,11 +367,17 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos) { } n = obj.getInt(); obj.free(); + if (first < 0 || n < 0 || first + n < 0) { + goto err1; + } if (first + n > size) { for (newSize = size ? 2 * size : 1024; - first + n > newSize; + first + n > newSize && newSize > 0; newSize <<= 1) ; - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + if (newSize < 0) { + goto err1; + } + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; @@ -443,9 +447,10 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos) { // check for an 'XRefStm' key if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { - pos2 = obj2.getInt(); + pos2 = (Guint)obj2.getInt(); readXRef(&pos2); if (!ok) { + obj2.free(); goto err1; } } @@ -474,8 +479,11 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { } newSize = obj.getInt(); obj.free(); + if (newSize < 0) { + goto err1; + } if (newSize > size) { - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; @@ -494,6 +502,9 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { } w[i] = obj2.getInt(); obj2.free(); + if (w[i] < 0 || w[i] > 4) { + goto err1; + } } obj.free(); @@ -513,13 +524,14 @@ GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { } n = obj.getInt(); obj.free(); - if (!readXRefStreamSection(xrefStr, w, first, n)) { + if (first < 0 || n < 0 || + !readXRefStreamSection(xrefStr, w, first, n)) { idx.free(); goto err0; } } } else { - if (!readXRefStreamSection(xrefStr, w, 0, size)) { + if (!readXRefStreamSection(xrefStr, w, 0, newSize)) { idx.free(); goto err0; } @@ -551,11 +563,17 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { Guint offset; int type, gen, c, newSize, i, j; + if (first + n < 0) { + return gFalse; + } if (first + n > size) { for (newSize = size ? 2 * size : 1024; - first + n > newSize; + first + n > newSize && newSize > 0; newSize <<= 1) ; - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + if (newSize < 0) { + return gFalse; + } + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; @@ -585,24 +603,26 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { } 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; + if (entries[i].offset == 0xffffffff) { + 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; + } } } @@ -643,7 +663,7 @@ GBool XRef::constructXRef() { obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, - str->makeSubStream(start + pos + 7, gFalse, 0, &obj))); + str->makeSubStream(pos + 7, gFalse, 0, &obj))); parser->getObj(&newTrailerDict); if (newTrailerDict.isDict()) { newTrailerDict.dictLookupNF("Root", &obj); @@ -664,38 +684,44 @@ GBool XRef::constructXRef() { // look for object } else if (isdigit(*p)) { num = atoi(p); - do { - ++p; - } while (*p && isdigit(*p)); - if (isspace(*p)) { + if (num > 0) { do { ++p; - } while (*p && isspace(*p)); - if (isdigit(*p)) { - gen = atoi(p); + } while (*p && isdigit(*p)); + if (isspace(*p)) { do { ++p; - } while (*p && isdigit(*p)); - if (isspace(*p)) { + } while (*p && isspace(*p)); + if (isdigit(*p)) { + gen = atoi(p); do { ++p; - } while (*p && isspace(*p)); - if (!strncmp(p, "obj", 3)) { - if (num >= size) { - newSize = (num + 1 + 255) & ~255; - entries = (XRefEntry *) - grealloc(entries, newSize * sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; + } while (*p && isdigit(*p)); + if (isspace(*p)) { + do { + ++p; + } while (*p && isspace(*p)); + if (!strncmp(p, "obj", 3)) { + if (num >= size) { + newSize = (num + 1 + 255) & ~255; + if (newSize < 0) { + error(-1, "Bad object number"); + return gFalse; + } + entries = (XRefEntry *) + greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + if (entries[num].type == xrefEntryFree || + gen >= entries[num].gen) { + entries[num].offset = pos - start; + entries[num].gen = gen; + entries[num].type = xrefEntryUncompressed; } - size = newSize; - } - if (entries[num].type == xrefEntryFree || - gen >= entries[num].gen) { - entries[num].offset = pos - start; - entries[num].gen = gen; - entries[num].type = xrefEntryUncompressed; } } } @@ -705,8 +731,8 @@ GBool XRef::constructXRef() { } else if (!strncmp(p, "endstream", 9)) { if (streamEndsLen == streamEndsSize) { streamEndsSize += 64; - streamEnds = (Guint *)grealloc(streamEnds, - streamEndsSize * sizeof(int)); + streamEnds = (Guint *)greallocn(streamEnds, + streamEndsSize, sizeof(int)); } streamEnds[streamEndsLen++] = pos; } @@ -719,137 +745,38 @@ GBool XRef::constructXRef() { return gFalse; } -#ifndef NO_DECRYPTION -GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { - Object encrypt, filterObj, versionObj, revisionObj, lengthObj; - Object ownerKey, userKey, permissions, fileID, fileID1; - GBool encrypted1; - GBool ret; - - keyLength = 0; - encVersion = encRevision = 0; - ret = gFalse; +void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA, + Guchar *fileKeyA, int keyLengthA, int encVersionA) { + int i; - permFlags = defPermFlags; - ownerPasswordOk = gFalse; - trailerDict.dictLookup("Encrypt", &encrypt); - if ((encrypted1 = encrypt.isDict())) { - ret = gTrue; - encrypt.dictLookup("Filter", &filterObj); - if (filterObj.isName("Standard")) { - encrypt.dictLookup("V", &versionObj); - encrypt.dictLookup("R", &revisionObj); - encrypt.dictLookup("Length", &lengthObj); - encrypt.dictLookup("O", &ownerKey); - encrypt.dictLookup("U", &userKey); - encrypt.dictLookup("P", &permissions); - trailerDict.dictLookup("ID", &fileID); - if (versionObj.isInt() && - revisionObj.isInt() && - ownerKey.isString() && ownerKey.getString()->getLength() == 32 && - userKey.isString() && userKey.getString()->getLength() == 32 && - permissions.isInt() && - fileID.isArray()) { - encVersion = versionObj.getInt(); - encRevision = revisionObj.getInt(); - if (lengthObj.isInt()) { - keyLength = lengthObj.getInt() / 8; - } else { - keyLength = 5; - } - permFlags = permissions.getInt(); - if (encVersion >= 1 && encVersion <= 2 && - encRevision >= 2 && encRevision <= 3) { - fileID.arrayGet(0, &fileID1); - if (fileID1.isString()) { - if (Decrypt::makeFileKey(encVersion, encRevision, keyLength, - ownerKey.getString(), userKey.getString(), - permFlags, fileID1.getString(), - ownerPassword, userPassword, fileKey, - &ownerPasswordOk)) { - if (ownerPassword && !ownerPasswordOk) { - error(-1, "Incorrect owner password"); - } - ret = gFalse; - } else { - error(-1, "Incorrect password"); - } - } else { - error(-1, "Weird encryption info"); - } - fileID1.free(); - } else { - error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", - encVersion, encRevision); - } - } else { - error(-1, "Weird encryption info"); - } - fileID.free(); - permissions.free(); - userKey.free(); - ownerKey.free(); - lengthObj.free(); - revisionObj.free(); - versionObj.free(); - } else { - error(-1, "Unknown security handler '%s'", - filterObj.isName() ? filterObj.getName() : "???"); - } - filterObj.free(); + encrypted = gTrue; + permFlags = permFlagsA; + ownerPasswordOk = ownerPasswordOkA; + if (keyLengthA <= 16) { + keyLength = keyLengthA; + } else { + keyLength = 16; } - encrypt.free(); - - // this flag has to be set *after* we read the O/U/P strings - encrypted = encrypted1; - - return ret; -} -#else -GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { - Object obj; - GBool encrypted; - - trailerDict.dictLookup("Encrypt", &obj); - if ((encrypted = !obj.isNull())) { - error(-1, "PDF file is encrypted and this version of the Xpdf tools"); - error(-1, "was built without decryption support."); + for (i = 0; i < keyLength; ++i) { + fileKey[i] = fileKeyA[i]; } - obj.free(); - return encrypted; + encVersion = encVersionA; } -#endif GBool XRef::okToPrint(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); -#else - return gTrue; -#endif } GBool XRef::okToChange(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange); -#else - return gTrue; -#endif } GBool XRef::okToCopy(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy); -#else - return gTrue; -#endif } GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes); -#else - return gTrue; -#endif } Object *XRef::fetch(int num, int gen, Object *obj) { @@ -879,14 +806,14 @@ Object *XRef::fetch(int num, int gen, Object *obj) { if (!obj1.isInt() || obj1.getInt() != num || !obj2.isInt() || obj2.getInt() != gen || !obj3.isCmd("obj")) { + obj1.free(); + obj2.free(); + obj3.free(); + delete parser; goto err; } -#ifndef NO_DECRYPTION parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, num, gen); -#else - parser->getObj(obj); -#endif obj1.free(); obj2.free(); obj3.free(); diff --git a/pdf2swf/xpdf/XRef.h b/pdf2swf/xpdf/XRef.h index bec487a..f9dede3 100644 --- a/pdf2swf/xpdf/XRef.h +++ b/pdf2swf/xpdf/XRef.h @@ -43,7 +43,7 @@ class XRef { public: // Constructor. Read xref table from stream. - XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword); + XRef(BaseStream *strA); // Destructor. ~XRef(); @@ -54,12 +54,12 @@ public: // Get the error code (if isOk() returns false). int getErrorCode() { return errCode; } + // Set the encryption parameters. + void setEncryption(int permFlagsA, GBool ownerPasswordOkA, + Guchar *fileKeyA, int keyLengthA, int encVersionA); + // Is the file encrypted? -#ifndef NO_DECRYPTION GBool isEncrypted() { return encrypted; } -#else - GBool isEncrypted() { return gFalse; } -#endif // Check various permissions. GBool okToPrint(GBool ignoreOwnerPW = gFalse); @@ -112,15 +112,12 @@ private: // 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 - int encRevision; // security handler revision - int keyLength; // length of key, in bytes int permFlags; // permission bits - Guchar fileKey[16]; // file decryption key GBool ownerPasswordOk; // true if owner password is correct -#endif + Guchar fileKey[16]; // file decryption key + int keyLength; // length of key, in bytes + int encVersion; // encryption algorithm Guint getStartXref(); GBool readXRef(Guint *pos); @@ -128,7 +125,6 @@ private: 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/gmem.c b/pdf2swf/xpdf/gmem.c index 07bbf81..a0f2cf5 100644 --- a/pdf2swf/xpdf/gmem.c +++ b/pdf2swf/xpdf/gmem.c @@ -50,6 +50,7 @@ static GMemHdr *gMemList[gMemNLists] = { static int gMemIndex = 0; static int gMemAlloc = 0; +static int gMemInUse = 0; #endif /* DEBUG_MEM */ @@ -78,6 +79,7 @@ void *gmalloc(int size) { hdr->next = gMemList[lst]; gMemList[lst] = hdr; ++gMemAlloc; + gMemInUse += size; for (p = (unsigned long *)data; p <= trl; ++p) *p = gMemDeadVal; return data; @@ -135,6 +137,28 @@ void *grealloc(void *p, int size) { #endif } +void *gmallocn(int nObjs, int objSize) { + int n; + + n = nObjs * objSize; + if (objSize == 0 || n / objSize != nObjs) { + fprintf(stderr, "Bogus memory allocation size\n"); + exit(1); + } + return gmalloc(n); +} + +void *greallocn(void *p, int nObjs, int objSize) { + int n; + + n = nObjs * objSize; + if (objSize == 0 || n / objSize != nObjs) { + fprintf(stderr, "Bogus memory allocation size\n"); + exit(1); + } + return grealloc(p, n); +} + void gfree(void *p) { #ifdef DEBUG_MEM int size; @@ -156,6 +180,7 @@ void gfree(void *p) { else gMemList[lst] = hdr->next; --gMemAlloc; + gMemInUse -= hdr->size; size = gMemDataSize(hdr->size); trl = (unsigned long *)((char *)hdr + gMemHdrSize + size); if (*trl != gMemDeadVal) { diff --git a/pdf2swf/xpdf/gmem.h b/pdf2swf/xpdf/gmem.h index 587e7fa..e74d182 100644 --- a/pdf2swf/xpdf/gmem.h +++ b/pdf2swf/xpdf/gmem.h @@ -28,6 +28,15 @@ extern void *gmalloc(int size); extern void *grealloc(void *p, int size); /* + * These are similar to gmalloc and grealloc, but take an object count + * and size. The result is similar to allocating nObjs * objSize + * bytes, but there is an additional error check that the total size + * doesn't overflow an int. + */ +extern void *gmallocn(int nObjs, int objSize); +extern void *greallocn(void *p, int nObjs, int objSize); + +/* * Same as free, but checks for and ignores NULL pointers. */ extern void gfree(void *p);