From 7c5ab64d4db75e4bb6dadedb578e10178554d0db Mon Sep 17 00:00:00 2001 From: Martin Kretzschmar Date: Tue, 01 Apr 2003 19:47:11 +0000 Subject: Merge with Xpdf 2.02 and make it build --- (limited to 'pdf/xpdf') diff --git a/pdf/xpdf/Annot.cc b/pdf/xpdf/Annot.cc index 8ebf6a0..68373f9 100644 --- a/pdf/xpdf/Annot.cc +++ b/pdf/xpdf/Annot.cc @@ -2,7 +2,7 @@ // // Annot.cc // -// Copyright 2000-2002 Glyph & Cog, LLC +// Copyright 2000-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Annot.h b/pdf/xpdf/Annot.h index 731fa8a..89dde0f 100644 --- a/pdf/xpdf/Annot.h +++ b/pdf/xpdf/Annot.h @@ -2,7 +2,7 @@ // // Annot.h // -// Copyright 2000-2002 Glyph & Cog, LLC +// Copyright 2000-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Array.cc b/pdf/xpdf/Array.cc index 9c6cb34..27ecbe9 100644 --- a/pdf/xpdf/Array.cc +++ b/pdf/xpdf/Array.cc @@ -2,7 +2,7 @@ // // Array.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include #include "gmem.h" #include "Object.h" @@ -46,9 +47,23 @@ void Array::add(Object *elem) { } Object *Array::get(int i, Object *obj) { + if (i < 0 || i >= length) { +#ifdef DEBUG_MEM + abort(); +#else + return obj->initNull(); +#endif + } return elems[i].fetch(xref, obj); } Object *Array::getNF(int i, Object *obj) { + if (i < 0 || i >= length) { +#ifdef DEBUG_MEM + abort(); +#else + return obj->initNull(); +#endif + } return elems[i].copy(obj); } diff --git a/pdf/xpdf/Array.h b/pdf/xpdf/Array.h index 09dbe2b..20ae05f 100644 --- a/pdf/xpdf/Array.h +++ b/pdf/xpdf/Array.h @@ -2,7 +2,7 @@ // // Array.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/BuiltinFont.cc b/pdf/xpdf/BuiltinFont.cc index a504b4c..a687e73 100644 --- a/pdf/xpdf/BuiltinFont.cc +++ b/pdf/xpdf/BuiltinFont.cc @@ -2,7 +2,7 @@ // // BuiltinFont.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/BuiltinFont.h b/pdf/xpdf/BuiltinFont.h index 69d2e75..903ed19 100644 --- a/pdf/xpdf/BuiltinFont.h +++ b/pdf/xpdf/BuiltinFont.h @@ -2,7 +2,7 @@ // // BuiltinFont.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/BuiltinFontTables.cc b/pdf/xpdf/BuiltinFontTables.cc index e2acfef..296e564 100644 --- a/pdf/xpdf/BuiltinFontTables.cc +++ b/pdf/xpdf/BuiltinFontTables.cc @@ -2,7 +2,7 @@ // // BuiltinFontTables.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/CMap.cc b/pdf/xpdf/CMap.cc index b000218..c60ce3c 100644 --- a/pdf/xpdf/CMap.cc +++ b/pdf/xpdf/CMap.cc @@ -2,7 +2,7 @@ // // CMap.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/CMap.h b/pdf/xpdf/CMap.h index ce926ba..b44f07a 100644 --- a/pdf/xpdf/CMap.h +++ b/pdf/xpdf/CMap.h @@ -2,7 +2,7 @@ // // CMap.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Catalog.cc b/pdf/xpdf/Catalog.cc index efea828..ad0821b 100644 --- a/pdf/xpdf/Catalog.cc +++ b/pdf/xpdf/Catalog.cc @@ -2,7 +2,7 @@ // // Catalog.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Catalog.h b/pdf/xpdf/Catalog.h index 7f89a61..8ab7c61 100644 --- a/pdf/xpdf/Catalog.h +++ b/pdf/xpdf/Catalog.h @@ -2,7 +2,7 @@ // // Catalog.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/CharCodeToUnicode.cc b/pdf/xpdf/CharCodeToUnicode.cc index e2fecbc..a374b1b 100644 --- a/pdf/xpdf/CharCodeToUnicode.cc +++ b/pdf/xpdf/CharCodeToUnicode.cc @@ -2,7 +2,7 @@ // // CharCodeToUnicode.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/CharCodeToUnicode.h b/pdf/xpdf/CharCodeToUnicode.h index 9cbd2a9..b20f323 100644 --- a/pdf/xpdf/CharCodeToUnicode.h +++ b/pdf/xpdf/CharCodeToUnicode.h @@ -4,7 +4,7 @@ // // Mapping from character codes to Unicode. // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Decrypt.cc b/pdf/xpdf/Decrypt.cc index b58a6c5..dca3762 100644 --- a/pdf/xpdf/Decrypt.cc +++ b/pdf/xpdf/Decrypt.cc @@ -2,7 +2,7 @@ // // Decrypt.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Decrypt.h b/pdf/xpdf/Decrypt.h index 903ee12..71f9457 100644 --- a/pdf/xpdf/Decrypt.h +++ b/pdf/xpdf/Decrypt.h @@ -2,7 +2,7 @@ // // Decrypt.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Dict.cc b/pdf/xpdf/Dict.cc index ad4ec3e..9575e4c 100644 --- a/pdf/xpdf/Dict.cc +++ b/pdf/xpdf/Dict.cc @@ -2,7 +2,7 @@ // // Dict.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Dict.h b/pdf/xpdf/Dict.h index e87ed90..08f55ec 100644 --- a/pdf/xpdf/Dict.h +++ b/pdf/xpdf/Dict.h @@ -2,7 +2,7 @@ // // Dict.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Error.cc b/pdf/xpdf/Error.cc index 4b2d120..c03f75f 100644 --- a/pdf/xpdf/Error.cc +++ b/pdf/xpdf/Error.cc @@ -2,7 +2,7 @@ // // Error.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Error.h b/pdf/xpdf/Error.h index c924065..0ce55e9 100644 --- a/pdf/xpdf/Error.h +++ b/pdf/xpdf/Error.h @@ -2,7 +2,7 @@ // // Error.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/FTFont.cc b/pdf/xpdf/FTFont.cc index ab101ac..c360eb7 100644 --- a/pdf/xpdf/FTFont.cc +++ b/pdf/xpdf/FTFont.cc @@ -2,7 +2,7 @@ // // FTFont.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -48,7 +48,8 @@ FTFontEngine::~FTFontEngine() { //------------------------------------------------------------------------ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, - char **fontEnc, GBool pdfFontHasEncoding) { + char **fontEnc, GBool pdfFontHasEncoding, + GBool pdfFontIsSymbolic) { char *name; int unicodeCmap, macRomanCmap, msSymbolCmap; int i, j; @@ -82,7 +83,9 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, // 1. If the PDF font has an encoding: // 1a. If the TrueType font has a Microsoft Unicode cmap, use it, // and use the Unicode indexes, not the char codes. - // 1b. If the TrueType font has a Macintosh Roman cmap, use it, + // 1b. If the PDF font is symbolic and the TrueType font has a + // Microsoft Symbol cmap, use it, and use (0xf000 + char code). + // 1c. If the TrueType font has a Macintosh Roman cmap, use it, // and reverse map the char names through MacRomanEncoding to // get char codes. // 2. If the PDF font does not have an encoding: @@ -94,8 +97,9 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, // the best (this shouldn't happen). unicodeCmap = macRomanCmap = msSymbolCmap = 0xffff; for (i = 0; i < face->num_charmaps; ++i) { - if (face->charmaps[i]->platform_id == 3 && - face->charmaps[i]->encoding_id == 1) { + if ((face->charmaps[i]->platform_id == 3 && + face->charmaps[i]->encoding_id == 1) || + face->charmaps[i]->platform_id == 0) { unicodeCmap = i; } else if (face->charmaps[i]->platform_id == 1 && face->charmaps[i]->encoding_id == 0) { @@ -112,6 +116,10 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, if (unicodeCmap != 0xffff) { i = unicodeCmap; mode = ftFontModeUnicode; + } else if (pdfFontIsSymbolic && msSymbolCmap != 0xffff) { + i = msSymbolCmap; + mode = ftFontModeCharCodeOffset; + charMapOffset = 0xf000; } else if (macRomanCmap != 0xffff) { i = macRomanCmap; mode = ftFontModeCodeMap; @@ -143,7 +151,9 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, } FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, - Gushort *cidToGIDA, int cidToGIDLenA) { + Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded) { + int i; + ok = gFalse; engine = engineA; codeMap = NULL; @@ -156,11 +166,33 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, cidToGIDLen = cidToGIDLenA; cidToGID = (Gushort *)gmalloc(cidToGIDLen * sizeof(Gushort)); memcpy(cidToGID, cidToGIDA, cidToGIDLen * sizeof(Gushort)); - mode = ftFontModeCIDToGIDMap; + if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) { + mode = ftFontModeCID; + } else if (!strcmp(face->driver->root.clazz->module_name, "cff")) { + mode = ftFontModeCFFCharset; + } else if (embedded) { + mode = ftFontModeCIDToGIDMap; + } else { + mode = ftFontModeUnicode; + for (i = 0; i < face->num_charmaps; ++i) { + if ((face->charmaps[i]->platform_id == 3 && + face->charmaps[i]->encoding_id == 1) || + face->charmaps[i]->platform_id == 0) { + break; + } + } + if (i == face->num_charmaps) { + i = 0; + } + FT_Set_Charmap(face, face->charmaps[i]); + } ok = gTrue; } -FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName) { +FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, + GBool embedded) { + int i; + ok = gFalse; engine = engineA; codeMap = NULL; @@ -172,8 +204,21 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName) { } if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) { mode = ftFontModeCID; - } else { + } else if (embedded) { mode = ftFontModeCFFCharset; + } else { + mode = ftFontModeUnicode; + for (i = 0; i < face->num_charmaps; ++i) { + if ((face->charmaps[i]->platform_id == 3 && + face->charmaps[i]->encoding_id == 1) || + face->charmaps[i]->platform_id == 0) { + break; + } + } + if (i == face->num_charmaps) { + i = 0; + } + FT_Set_Charmap(face, face->charmaps[i]); } ok = gTrue; } @@ -336,7 +381,9 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, XColor xcolor; int bgR, bgG, bgB; Gulong colors[5]; - Guchar *p; + Guchar *bitmap, *p; + GBool tempBitmap; + XImage *img; int pix; int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0; int xx, yy, xx1; @@ -349,7 +396,8 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, } // generate the glyph pixmap - if (!(p = getGlyphPixmap(c, u, &xOffset, &yOffset, &gw, &gh))) { + if (!(bitmap = getGlyphPixmap(c, u, &xOffset, &yOffset, &gw, &gh, + &tempBitmap))) { return gFalse; } @@ -371,7 +419,7 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, w0 = w - x0; } if (w0 < 0) { - return gTrue; + goto done; } if (y0 < 0) { y1 = -y0; @@ -382,17 +430,29 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, h0 = h - y0; } if (h0 < 0) { - return gTrue; + goto done; + } + + // getGlyphPixmap may have returned a larger-than-cache-entry + // bitmap, in which case we need to allocate a temporary XImage here + if (tempBitmap) { + if (!(img = XCreateImage(engine->display, engine->visual, engine->depth, + ZPixmap, 0, NULL, gw, gh, 8, 0))) { + goto done; + } + img->data = (char *)gmalloc(gh * img->bytes_per_line); + } else { + img = image; } // read the X image XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1, - ZPixmap, image, x1, y1); + ZPixmap, img, x1, y1); if (engine->aa) { // compute the colors - xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2); + xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2); XQueryColor(engine->display, engine->colormap, &xcolor); bgR = xcolor.red; bgG = xcolor.green; @@ -409,6 +469,7 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, colors[4] = engine->findColor(r, g, b); // stuff the glyph pixmap into the X image + p = bitmap; for (yy = 0; yy < gh; ++yy) { for (xx = 0; xx < gw; ++xx) { pix = *p++ & 0xff; @@ -420,7 +481,7 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, pix = 4; } if (pix > 0) { - XPutPixel(image, xx, yy, colors[pix]); + XPutPixel(img, xx, yy, colors[pix]); } } } @@ -431,12 +492,13 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, colors[1] = engine->findColor(r, g, b); // stuff the glyph bitmap into the X image + p = bitmap; for (yy = 0; yy < gh; ++yy) { for (xx = 0; xx < gw; xx += 8) { pix = *p++; for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) { if (pix & 0x80) { - XPutPixel(image, xx1, yy, colors[1]); + XPutPixel(img, xx1, yy, colors[1]); } pix <<= 1; } @@ -446,13 +508,23 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, } // draw the X image - XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0); + XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0); + if (tempBitmap) { + gfree(img->data); + img->data = NULL; + XDestroyImage(img); + } + done: + if (tempBitmap) { + gfree(bitmap); + } return gTrue; } Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u, - int *x, int *y, int *w, int *h) { + int *x, int *y, int *w, int *h, + GBool *tempBitmap) { FT_GlyphSlot slot; FT_UInt idx; int rowSize; @@ -474,6 +546,7 @@ Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u, } } cacheTags[i+j].mru = 0x8000; + *tempBitmap = gFalse; return cache + (i+j) * glyphSize; } } @@ -504,42 +577,45 @@ Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u, ft_render_mode_mono)) { return gFalse; } + + // copy the glyph into the cache or a temporary bitmap *x = -slot->bitmap_left; *y = slot->bitmap_top; *w = slot->bitmap.width; *h = slot->bitmap.rows; - if (*w > glyphW || *h > glyphH) { -#if 1 //~ debug - fprintf(stderr, "Weird FreeType glyph size: %d > %d or %d > %d\n", - *w, glyphW, *h, glyphH); -#endif - return NULL; + if (fontFile->engine->aa) { + rowSize = *w; + } else { + rowSize = (*w + 7) >> 3; } - - // store glyph pixmap in cache - ret = NULL; - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { - cacheTags[i+j].mru = 0x8000; - cacheTags[i+j].code = c; - cacheTags[i+j].x = *x; - cacheTags[i+j].y = *y; - cacheTags[i+j].w = *w; - cacheTags[i+j].h = *h; - if (fontFile->engine->aa) { - rowSize = *w; + if (*w > glyphW || *h > glyphH) { + // the glyph doesn't fit in the bounding box -- return a + // temporary, uncached bitmap (this shouldn't happen but some + // fonts have incorrect bboxes) + ret = (Guchar *)gmalloc(*h * rowSize); + *tempBitmap = gTrue; + } else { + // store glyph pixmap in cache + ret = NULL; // make gcc happy + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { + cacheTags[i+j].mru = 0x8000; + cacheTags[i+j].code = c; + cacheTags[i+j].x = *x; + cacheTags[i+j].y = *y; + cacheTags[i+j].w = *w; + cacheTags[i+j].h = *h; + ret = cache + (i+j) * glyphSize; } else { - rowSize = (*w + 7) >> 3; - } - ret = cache + (i+j) * glyphSize; - for (k = 0, p = ret, q = slot->bitmap.buffer; - k < slot->bitmap.rows; - ++k, p += rowSize, q += slot->bitmap.pitch) { - memcpy(p, q, rowSize); + ++cacheTags[i+j].mru; } - } else { - ++cacheTags[i+j].mru; } + *tempBitmap = gFalse; + } + for (k = 0, p = ret, q = slot->bitmap.buffer; + k < slot->bitmap.rows; + ++k, p += rowSize, q += slot->bitmap.pitch) { + memcpy(p, q, rowSize); } return ret; } @@ -649,8 +725,10 @@ FT_UInt FTFont::getGlyphIndex(CharCode c, Unicode u) { idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)c); break; case ftFontModeCharCodeOffset: - idx = FT_Get_Char_Index(fontFile->face, - (FT_ULong)(c + fontFile->charMapOffset)); + if ((idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)c)) == 0) { + idx = FT_Get_Char_Index(fontFile->face, + (FT_ULong)(c + fontFile->charMapOffset)); + } break; case ftFontModeCodeMap: if (c <= 0xff) { diff --git a/pdf/xpdf/FTFont.h b/pdf/xpdf/FTFont.h index 32675c6..52bc149 100644 --- a/pdf/xpdf/FTFont.h +++ b/pdf/xpdf/FTFont.h @@ -4,7 +4,7 @@ // // An X wrapper for the FreeType font rasterizer. // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -62,14 +62,16 @@ public: // 8-bit font, TrueType or Type 1/1C FTFontFile(FTFontEngine *engineA, char *fontFileName, - char **fontEnc, GBool pdfFontHasEncoding); + char **fontEnc, GBool pdfFontHasEncoding, + GBool pdfFontIsSymbolic); // CID font, TrueType FTFontFile(FTFontEngine *engineA, char *fontFileName, - Gushort *cidToGIDA, int cidToGIDLenA); + Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded); // CID font, Type 0C (CFF) - FTFontFile(FTFontEngine *engineA, char *fontFileName); + FTFontFile(FTFontEngine *engineA, char *fontFileName, + GBool embedded); GBool isOk() { return ok; } virtual ~FTFontFile(); @@ -110,7 +112,8 @@ public: private: Guchar *getGlyphPixmap(CharCode c, Unicode u, - int *x, int *y, int *w, int *h); + int *x, int *y, int *w, int *h, + GBool *tempBitmap); static int charPathMoveTo(FT_Vector *pt, void *state); static int charPathLineTo(FT_Vector *pt, void *state); static int charPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *state); diff --git a/pdf/xpdf/FontEncodingTables.cc b/pdf/xpdf/FontEncodingTables.cc index 6deff95..f3b9280 100644 --- a/pdf/xpdf/FontEncodingTables.cc +++ b/pdf/xpdf/FontEncodingTables.cc @@ -2,7 +2,7 @@ // // FontEncodingTables.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/FontFile.cc b/pdf/xpdf/FontFile.cc index 6860e4a..fde0ae6 100644 --- a/pdf/xpdf/FontFile.cc +++ b/pdf/xpdf/FontFile.cc @@ -2,7 +2,7 @@ // // FontFile.cc // -// Copyright 1999-2002 Glyph & Cog, LLC +// Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== @@ -190,31 +190,38 @@ struct Type1CPrivateDict { }; Type1CFontFile::Type1CFontFile(char *fileA, int lenA) { - Guchar *nameIdxPtr, *idxPtr0, *idxPtr1; + int nameIdxPos, namePos, nameLen; - file = fileA; + file = (Guchar *)fileA; len = lenA; name = NULL; encoding = NULL; + ok = gFalse; // some tools embed Type 1C fonts with an extra whitespace char at // the beginning - if (file[0] != '\x01') { + if (len > 0 && file[0] != '\x01') { ++file; + --len; } - // read header - topOffSize = file[3] & 0xff; + // make sure the header exists + if (len < 4) { + return; + } // read name index (first font only) - nameIdxPtr = (Guchar *)file + (file[2] & 0xff); - idxPtr0 = getIndexValPtr(nameIdxPtr, 0); - idxPtr1 = getIndexValPtr(nameIdxPtr, 1); - name = new GString((char *)idxPtr0, idxPtr1 - idxPtr0); - - topDictIdxPtr = getIndexEnd(nameIdxPtr); - stringIdxPtr = getIndexEnd(topDictIdxPtr); - gsubrIdxPtr = getIndexEnd(stringIdxPtr); + nameIdxPos = file[2] & 0xff; + if ((namePos = getIndexValPos(nameIdxPos, 0, &nameLen)) < 0) { + return; + } + name = new GString((char *)&file[namePos], nameLen); + + topDictIdxPos = getIndexEnd(nameIdxPos); + stringIdxPos = getIndexEnd(topDictIdxPos); + gsubrIdxPos = getIndexEnd(stringIdxPos); + + ok = gTrue; } Type1CFontFile::~Type1CFontFile() { @@ -235,14 +242,14 @@ char *Type1CFontFile::getName() { char **Type1CFontFile::getEncoding() { if (!encoding) { - readNameAndEncoding(); + readEncoding(); } return encoding; } -void Type1CFontFile::readNameAndEncoding() { +void Type1CFontFile::readEncoding() { char buf[256]; - Guchar *idxPtr0, *idxPtr1, *ptr; + int idxPos, idxLen, pos; int nGlyphs; int nCodes, nRanges, nLeft, nSups; Gushort *glyphNames; @@ -260,16 +267,20 @@ void Type1CFontFile::readNameAndEncoding() { } // read top dict (first font only) - idxPtr0 = getIndexValPtr(topDictIdxPtr, 0); - idxPtr1 = getIndexValPtr(topDictIdxPtr, 1); + if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) { + return; + } charset = enc = charstrings = 0; i = 0; - ptr = idxPtr0; - while (ptr < idxPtr1) { - if (*ptr <= 27 || *ptr == 31) { - key = *ptr++; + pos = idxPos; + while (pos < idxPos + idxLen) { + if (file[pos] <= 27 || file[pos] == 31) { + key = file[pos++]; if (key == 0x0c) { - key = (key << 8) | *ptr++; + if (pos >= idxPos + idxLen) { + return; + } + key = (key << 8) | file[pos++]; } if (key == 0x0f) { // charset charset = (int)op[0]; @@ -280,7 +291,7 @@ void Type1CFontFile::readNameAndEncoding() { } i = 0; } else { - x = getNum(&ptr, &isFP); + x = getNum(&pos, &isFP); if (i < 48) { op[i++] = x; } @@ -288,7 +299,7 @@ void Type1CFontFile::readNameAndEncoding() { } // get number of glyphs from charstrings index - nGlyphs = getIndexLen((Guchar *)file + charstrings); + nGlyphs = getIndexLen(charstrings); // read charset (GID -> name mapping) glyphNames = readCharset(charset, nGlyphs); @@ -307,24 +318,45 @@ void Type1CFontFile::readNameAndEncoding() { } } } else { - ptr = (Guchar *)file + enc; - encFormat = *ptr++; + pos = enc; + if (pos < 0 || pos >= len) { + goto err0; + } + encFormat = file[pos++]; if ((encFormat & 0x7f) == 0) { - nCodes = 1 + *ptr++; + if (pos >= len) { + goto err0; + } + nCodes = 1 + file[pos++]; if (nCodes > nGlyphs) { nCodes = nGlyphs; } + if (pos + nCodes - 1 > len) { + goto err0; + } for (i = 1; i < nCodes; ++i) { - c = *ptr++; + c = file[pos++]; + if (encoding[c]) { + gfree(encoding[c]); + } encoding[c] = copyString(getString(glyphNames[i], buf)); } } else if ((encFormat & 0x7f) == 1) { - nRanges = *ptr++; + if (pos >= len) { + goto err0; + } + nRanges = file[pos++]; + if (pos + 2 * nRanges > len) { + goto err0; + } nCodes = 1; for (i = 0; i < nRanges; ++i) { - c = *ptr++; - nLeft = *ptr++; + c = file[pos++]; + nLeft = file[pos++]; for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { + if (encoding[c]) { + gfree(encoding[c]); + } encoding[c] = copyString(getString(glyphNames[nCodes], buf)); ++nCodes; ++c; @@ -332,17 +364,27 @@ void Type1CFontFile::readNameAndEncoding() { } } if (encFormat & 0x80) { - nSups = *ptr++; + if (pos >= len) { + goto err0; + } + nSups = file[pos++]; + if (pos + nSups * 3 > len) { + goto err0; + } for (i = 0; i < nSups; ++i) { - c = *ptr++; - sid = getWord(ptr, 2); - ptr += 2; + c = file[pos++]; + sid = getWord(pos, 2); + pos += 2; + if (encoding[c]) { + gfree(encoding[c]); + } encoding[c] = copyString(getString(sid, buf)); } } } - if (charset > 2) { + err0: + if (charset < 0 || charset > 2) { gfree(glyphNames); } } @@ -352,12 +394,12 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, Type1CTopDict dict; Type1CPrivateDict privateDict; char buf[512], eBuf[256]; - Guchar *idxPtr0, *idxPtr1, *subrsIdxPtr, *charStringsIdxPtr, *ptr; + int idxPos, idxLen, pos; int nGlyphs, nCodes, nRanges, nLeft, nSups; Gushort *glyphNames; - int encFormat, nSubrs, nCharStrings; + int encFormat, nCharStrings; int c, sid; - int i, j, n; + int i, j; outputFunc = outputFuncA; outputStream = outputStreamA; @@ -365,9 +407,6 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, // read top dict (first font only) readTopDict(&dict); - // get global subrs - //~ ... global subrs are unimplemented - // write header and font dictionary, up to encoding (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); (*outputFunc)(outputStream, name->getCString(), name->getLength()); @@ -447,7 +486,7 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, } // get number of glyphs from charstrings index - nGlyphs = getIndexLen((Guchar *)file + dict.charStrings); + nGlyphs = getIndexLen(dict.charStrings); // read charset glyphNames = readCharset(dict.charset, nGlyphs); @@ -468,15 +507,24 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, } } } else { - ptr = (Guchar *)file + dict.encoding; - encFormat = *ptr++; + pos = dict.encoding; + if (pos < 0 || pos >= len) { + goto err0; + } + encFormat = file[pos++]; if ((encFormat & 0x7f) == 0) { - nCodes = 1 + *ptr++; + if (pos >= len) { + goto err0; + } + nCodes = 1 + file[pos++]; if (nCodes > nGlyphs) { nCodes = nGlyphs; } + if (pos + nCodes - 1 > len) { + goto err0; + } for (i = 1; i < nCodes; ++i) { - c = *ptr++; + c = file[pos++]; sprintf(buf, "dup %d /", c); (*outputFunc)(outputStream, buf, strlen(buf)); getString(glyphNames[i], buf); @@ -484,11 +532,17 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, (*outputFunc)(outputStream, " put\n", 5); } } else if ((encFormat & 0x7f) == 1) { - nRanges = *ptr++; + if (pos >= len) { + goto err0; + } + nRanges = file[pos++]; + if (pos + 2 * nRanges > len) { + goto err0; + } nCodes = 1; for (i = 0; i < nRanges; ++i) { - c = *ptr++; - nLeft = *ptr++; + c = file[pos++]; + nLeft = file[pos++]; for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { sprintf(buf, "dup %d /", c); (*outputFunc)(outputStream, buf, strlen(buf)); @@ -501,11 +555,17 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, } } if (encFormat & 0x80) { - nSups = *ptr++; + if (pos >= len) { + goto err0; + } + nSups = file[pos++]; + if (pos + nSups * 3 > len) { + goto err0; + } for (i = 0; i < nSups; ++i) { - c = *ptr++; - sid = getWord(ptr, 2); - ptr += 2; + c = file[pos++]; + sid = getWord(pos, 2); + pos += 2; sprintf(buf, "dup %d /", c); (*outputFunc)(outputStream, buf, strlen(buf)); getString(sid, buf); @@ -513,6 +573,7 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, (*outputFunc)(outputStream, " put\n", 5); } } + err0:; } (*outputFunc)(outputStream, "readonly def\n", 13); } @@ -537,41 +598,21 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, nominalWidthX = privateDict.nominalWidthX; nominalWidthXFP = privateDict.nominalWidthXFP; - // get subrs - if (privateDict.subrsOffset != 0) { - subrsIdxPtr = (Guchar *)file + dict.privateOffset + - privateDict.subrsOffset; - nSubrs = getIndexLen(subrsIdxPtr); - sprintf(eBuf, "/Subrs %d array\n", nSubrs); - eexecWrite(eBuf); - idxPtr1 = getIndexValPtr(subrsIdxPtr, 0); - for (i = 0; i < nSubrs; ++i) { - idxPtr0 = idxPtr1; - idxPtr1 = getIndexValPtr(subrsIdxPtr, i+1); - n = idxPtr1 - idxPtr0; -#if 1 //~ Type 2 subrs are unimplemented - error(-1, "Unimplemented Type 2 subrs"); -#else - sprintf(eBuf, "dup %d %d RD ", i, n); - eexecWrite(eBuf); - eexecCvtGlyph(idxPtr0, n); - eexecWrite(" NP\n"); -#endif - } - eexecWrite("ND\n"); - } + // set up subroutines + subrIdxPos = dict.privateOffset + privateDict.subrsOffset; + i = getIndexLen(gsubrIdxPos); + gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; + i = getIndexLen(subrIdxPos); + subrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; // get CharStrings - charStringsIdxPtr = (Guchar *)file + dict.charStrings; - nCharStrings = getIndexLen(charStringsIdxPtr); + nCharStrings = getIndexLen(dict.charStrings); sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings); eexecWrite(eBuf); - idxPtr1 = getIndexValPtr(charStringsIdxPtr, 0); for (i = 0; i < nCharStrings; ++i) { - idxPtr0 = idxPtr1; - idxPtr1 = getIndexValPtr(charStringsIdxPtr, i+1); - n = idxPtr1 - idxPtr0; - eexecCvtGlyph(getString(glyphNames[i], buf), idxPtr0, n); + if ((idxPos = getIndexValPos(dict.charStrings, i, &idxLen)) >= 0) { + eexecCvtGlyph(getString(glyphNames[i], buf), idxPos, idxLen); + } } eexecWrite("end\n"); eexecWrite("end\n"); @@ -606,7 +647,7 @@ void Type1CFontFile::convertToCIDType0(char *psName, Gushort *charset; int *cidMap; Guchar *fdSelect; - Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr; + int idxPos, idxLen, pos; char buf[512], buf2[16]; int nGlyphs, nCIDs, gdBytes, nFDs; int fdSelectFmt, nRanges, gid0, gid1, fd, offset; @@ -635,29 +676,36 @@ void Type1CFontFile::convertToCIDType0(char *psName, privateDicts[0].nominalWidthX = 0; privateDicts[0].nominalWidthXFP = gFalse; } else { - fdArrayIdx = (Guchar *)file + dict.fdArrayOffset; - nFDs = getIndexLen(fdArrayIdx); + if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) { + goto err0; + } privateDicts = (Type1CPrivateDict *) gmalloc(nFDs * sizeof(Type1CPrivateDict)); - idxPtr1 = getIndexValPtr(fdArrayIdx, 0); for (i = 0; i < nFDs; ++i) { privateDicts[i].dictData = NULL; - idxPtr0 = idxPtr1; - idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1); - ptr = idxPtr0; + } + for (i = 0; i < nFDs; ++i) { + privateDicts[i].dictData = NULL; + if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) { + goto err1; + } + pos = idxPos; j = 0; - while (ptr < idxPtr1) { - if (*ptr <= 27 || *ptr == 31) { - key = *ptr++; + while (pos < idxPos + idxLen) { + if (file[pos] <= 27 || file[pos] == 31) { + key = file[pos++]; if (key == 0x0c) { - key = (key << 8) | *ptr++; + if (pos >= idxPos + idxLen) { + goto err1; + } + key = (key << 8) | file[pos++]; } if (key == 0x0012) { readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]); } j = 0; } else { - x = getNum(&ptr, &isFP); + x = getNum(&pos, &isFP); if (j < 48) { op[j] = x; fp[j++] = isFP; @@ -676,8 +724,9 @@ void Type1CFontFile::convertToCIDType0(char *psName, } // get the glyph count - charStringsIdxPtr = (Guchar *)file + dict.charStrings; - nGlyphs = getIndexLen(charStringsIdxPtr); + if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) { + goto err1; + } // read the FDSelect table fdSelect = (Guchar *)gmalloc(nGlyphs); @@ -686,19 +735,31 @@ void Type1CFontFile::convertToCIDType0(char *psName, fdSelect[i] = 0; } } else { - ptr = (Guchar *)file + dict.fdSelectOffset; - fdSelectFmt = *ptr++; + pos = dict.fdSelectOffset; + if (pos < 0 || pos >= len) { + goto err2; + } + fdSelectFmt = file[pos++]; if (fdSelectFmt == 0) { - memcpy(fdSelect, ptr, nGlyphs); + if (pos + nGlyphs > len) { + goto err2; + } + memcpy(fdSelect, file + pos, nGlyphs); } else if (fdSelectFmt == 3) { - nRanges = getWord(ptr, 2); - ptr += 2; - gid0 = getWord(ptr, 2); - ptr += 2; + if (pos + 4 > len) { + goto err2; + } + nRanges = getWord(pos, 2); + pos += 2; + gid0 = getWord(pos, 2); + pos += 2; + if (pos + nRanges * 3 > len) { + goto err2; + } for (i = 1; i <= nRanges; ++i) { - fd = *ptr++; - gid1 = getWord(ptr, 2); - ptr += 2; + fd = file[pos++]; + gid1 = getWord(pos, 2); + pos += 2; for (j = gid0; j < gid1; ++j) { fdSelect[j] = fd; } @@ -728,23 +789,30 @@ void Type1CFontFile::convertToCIDType0(char *psName, cidMap[charset[i]] = i; } + // set up global subroutines + i = getIndexLen(gsubrIdxPos); + gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; + // build the charstrings charStrings = new GString(); charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int)); for (i = 0; i < nCIDs; ++i) { charStringOffsets[i] = charStrings->getLength(); if (cidMap[i] >= 0) { - idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i]); - idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i]+1); - n = idxPtr1 - idxPtr0; - j = fdSelect[cidMap[i]]; - defaultWidthX = privateDicts[j].defaultWidthX; - defaultWidthXFP = privateDicts[j].defaultWidthXFP; - nominalWidthX = privateDicts[j].nominalWidthX; - nominalWidthXFP = privateDicts[j].nominalWidthXFP; - cvtGlyph(idxPtr0, n); - charStrings->append(charBuf); - delete charBuf; + if ((idxPos = getIndexValPos(dict.charStrings, + cidMap[i], &idxLen)) >= 0) { + j = fdSelect[cidMap[i]]; + defaultWidthX = privateDicts[j].defaultWidthX; + defaultWidthXFP = privateDicts[j].defaultWidthXFP; + nominalWidthX = privateDicts[j].nominalWidthX; + nominalWidthXFP = privateDicts[j].nominalWidthXFP; + subrIdxPos = dict.privateOffset + privateDicts[j].subrsOffset; + k = getIndexLen(subrIdxPos); + subrBias = (k < 1240) ? 107 : (k < 33900) ? 1131 : 32768; + cvtGlyph(idxPos, idxLen, gTrue); + charStrings->append(charBuf); + delete charBuf; + } } } charStringOffsets[nCIDs] = charStrings->getLength(); @@ -831,8 +899,6 @@ void Type1CFontFile::convertToCIDType0(char *psName, } (*outputFunc)(outputStream, "def\n", 4); - //~ need to deal with subrs - // start the binary section offset = (nCIDs + 1) * (1 + gdBytes); sprintf(buf, "(Hex) %d StartData\n", @@ -873,15 +939,20 @@ void Type1CFontFile::convertToCIDType0(char *psName, (*outputFunc)(outputStream, "\n", 1); } - for (i = 0; i < nFDs; ++i) { - delete privateDicts[i].dictData; - } - gfree(privateDicts); - gfree(cidMap); - gfree(charset); gfree(charStringOffsets); delete charStrings; + gfree(cidMap); + gfree(charset); + err2: gfree(fdSelect); + err1: + for (i = 0; i < nFDs; ++i) { + if (privateDicts[i].dictData) { + delete privateDicts[i].dictData; + } + } + gfree(privateDicts); + err0:; } void Type1CFontFile::convertToType0(char *psName, @@ -892,7 +963,7 @@ void Type1CFontFile::convertToType0(char *psName, Gushort *charset; int *cidMap; Guchar *fdSelect; - Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr; + int idxPos, idxLen, pos; char buf[512]; char eBuf[256]; int nGlyphs, nCIDs, nFDs; @@ -900,7 +971,7 @@ void Type1CFontFile::convertToType0(char *psName, int key; double x; GBool isFP; - int i, j, n; + int i, j; outputFunc = outputFuncA; outputStream = outputStreamA; @@ -920,29 +991,36 @@ void Type1CFontFile::convertToType0(char *psName, privateDicts[0].nominalWidthX = 0; privateDicts[0].nominalWidthXFP = gFalse; } else { - fdArrayIdx = (Guchar *)file + dict.fdArrayOffset; - nFDs = getIndexLen(fdArrayIdx); + if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) { + goto err0; + } privateDicts = (Type1CPrivateDict *) gmalloc(nFDs * sizeof(Type1CPrivateDict)); - idxPtr1 = getIndexValPtr(fdArrayIdx, 0); for (i = 0; i < nFDs; ++i) { privateDicts[i].dictData = NULL; - idxPtr0 = idxPtr1; - idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1); - ptr = idxPtr0; + } + for (i = 0; i < nFDs; ++i) { + privateDicts[i].dictData = NULL; + if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) { + goto err1; + } + pos = idxPos; j = 0; - while (ptr < idxPtr1) { - if (*ptr <= 27 || *ptr == 31) { - key = *ptr++; + while (pos < idxPos + idxLen) { + if (file[pos] <= 27 || file[pos] == 31) { + key = file[pos++]; if (key == 0x0c) { - key = (key << 8) | *ptr++; + if (pos >= idxPos + idxLen) { + goto err1; + } + key = (key << 8) | file[pos++]; } if (key == 0x0012) { readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]); } j = 0; } else { - x = getNum(&ptr, &isFP); + x = getNum(&pos, &isFP); if (j < 48) { op[j] = x; fp[j++] = isFP; @@ -961,8 +1039,9 @@ void Type1CFontFile::convertToType0(char *psName, } // get the glyph count - charStringsIdxPtr = (Guchar *)file + dict.charStrings; - nGlyphs = getIndexLen(charStringsIdxPtr); + if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) { + goto err1; + } // read the FDSelect table fdSelect = (Guchar *)gmalloc(nGlyphs); @@ -971,19 +1050,31 @@ void Type1CFontFile::convertToType0(char *psName, fdSelect[i] = 0; } } else { - ptr = (Guchar *)file + dict.fdSelectOffset; - fdSelectFmt = *ptr++; + pos = dict.fdSelectOffset; + if (pos < 0 || pos >= len) { + goto err2; + } + fdSelectFmt = file[pos++]; if (fdSelectFmt == 0) { - memcpy(fdSelect, ptr, nGlyphs); + if (pos + nGlyphs > len) { + goto err2; + } + memcpy(fdSelect, file + pos, nGlyphs); } else if (fdSelectFmt == 3) { - nRanges = getWord(ptr, 2); - ptr += 2; - gid0 = getWord(ptr, 2); - ptr += 2; + if (pos + 4 > len) { + goto err2; + } + nRanges = getWord(pos, 2); + pos += 2; + gid0 = getWord(pos, 2); + pos += 2; + if (pos + nRanges * 3 > len) { + goto err2; + } for (i = 1; i <= nRanges; ++i) { - fd = *ptr++; - gid1 = getWord(ptr, 2); - ptr += 2; + fd = file[pos++]; + gid1 = getWord(pos, 2); + pos += 2; for (j = gid0; j < gid1; ++j) { fdSelect[j] = fd; } @@ -1013,6 +1104,10 @@ void Type1CFontFile::convertToType0(char *psName, cidMap[charset[i]] = i; } + // set up global subroutines + i = getIndexLen(gsubrIdxPos); + gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; + // write the descendant Type 1 fonts for (i = 0; i < nCIDs; i += 256) { @@ -1074,24 +1169,28 @@ void Type1CFontFile::convertToType0(char *psName, nominalWidthX = privateDicts[fd].nominalWidthX; nominalWidthXFP = privateDicts[fd].nominalWidthXFP; + // set up the subroutines + subrIdxPos = dict.privateOffset + privateDicts[fd].subrsOffset; + j = getIndexLen(subrIdxPos); + subrBias = (j < 1240) ? 107 : (j < 33900) ? 1131 : 32768; + // start the CharStrings sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n"); eexecWrite(eBuf); // write the .notdef CharString - idxPtr0 = getIndexValPtr(charStringsIdxPtr, 0); - idxPtr1 = getIndexValPtr(charStringsIdxPtr, 1); - n = idxPtr1 - idxPtr0; - eexecCvtGlyph(".notdef", idxPtr0, n); + if ((idxPos = getIndexValPos(dict.charStrings, 0, &idxLen)) >= 0) { + eexecCvtGlyph(".notdef", idxPos, idxLen); + } // write the CharStrings for (j = 0; j < 256 && i+j < nCIDs; ++j) { if (cidMap[i+j] >= 0) { - idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]); - idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]+1); - n = idxPtr1 - idxPtr0; - sprintf(buf, "c%02x", j); - eexecCvtGlyph(buf, idxPtr0, n); + if ((idxPos = getIndexValPos(dict.charStrings, + cidMap[i+j], &idxLen)) >= 0) { + sprintf(buf, "c%02x", j); + eexecCvtGlyph(buf, idxPos, idxLen); + } } } eexecWrite("end\n"); @@ -1136,24 +1235,27 @@ void Type1CFontFile::convertToType0(char *psName, (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); // clean up - for (i = 0; i < nFDs; ++i) { - delete privateDicts[i].dictData; - } - gfree(privateDicts); gfree(cidMap); gfree(charset); + err2: gfree(fdSelect); + err1: + for (i = 0; i < nFDs; ++i) { + if (privateDicts[i].dictData) { + delete privateDicts[i].dictData; + } + } + gfree(privateDicts); + err0:; } void Type1CFontFile::readTopDict(Type1CTopDict *dict) { - Guchar *idxPtr0, *idxPtr1, *ptr; + int idxPos, idxLen, pos; double x; GBool isFP; int key; int i; - idxPtr0 = getIndexValPtr(topDictIdxPtr, 0); - idxPtr1 = getIndexValPtr(topDictIdxPtr, 1); dict->version = 0; dict->notice = 0; dict->copyright = 0; @@ -1188,13 +1290,19 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) { dict->supplement = 0; dict->fdArrayOffset = 0; dict->fdSelectOffset = 0; + if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) { + return; + } i = 0; - ptr = idxPtr0; - while (ptr < idxPtr1) { - if (*ptr <= 27 || *ptr == 31) { - key = *ptr++; + pos = idxPos; + while (pos < idxPos + idxLen) { + if (file[pos] <= 27 || file[pos] == 31) { + key = file[pos++]; if (key == 0x0c) { - key = (key << 8) | *ptr++; + if (pos >= idxPos + idxLen) { + break; + } + key = (key << 8) | file[pos++]; } switch (key) { case 0x0000: dict->version = (int)op[0]; break; @@ -1234,7 +1342,7 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) { } i = 0; } else { - x = getNum(&ptr, &isFP); + x = getNum(&pos, &isFP); if (i < 48) { op[i] = x; fp[i++] = isFP; @@ -1245,7 +1353,7 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) { void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict, int offset, int size) { - Guchar *idxPtr0, *idxPtr1, *ptr; + int pos; char eBuf[256]; int key; double x; @@ -1258,15 +1366,19 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict, privateDict->defaultWidthXFP = gFalse; privateDict->nominalWidthX = 0; privateDict->nominalWidthXFP = gFalse; - idxPtr0 = (Guchar *)file + offset; - idxPtr1 = idxPtr0 + size; - ptr = idxPtr0; + if (offset < 0 || offset + size > len) { + return; + } + pos = offset; i = 0; - while (ptr < idxPtr1) { - if (*ptr <= 27 || *ptr == 31) { - key = *ptr++; + while (pos < offset + size) { + if (file[pos] <= 27 || file[pos] == 31) { + key = file[pos++]; if (key == 0x0c) { - key = (key << 8) | *ptr++; + if (pos >= offset + size) { + break; + } + key = (key << 8) | file[pos++]; } switch (key) { case 0x0006: @@ -1349,7 +1461,7 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict, } i = 0; } else { - x = getNum(&ptr, &isFP); + x = getNum(&pos, &isFP); if (i < 48) { op[i] = x; fp[i++] = isFP; @@ -1360,7 +1472,7 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict, Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) { Gushort *glyphNames; - Guchar *ptr; + int pos; int charsetFormat, c; int nLeft, i, j; @@ -1372,20 +1484,31 @@ Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) { glyphNames = type1CExpertSubsetCharset; } else { glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort)); - glyphNames[0] = 0; - ptr = (Guchar *)file + charset; - charsetFormat = *ptr++; + for (i = 0; i < nGlyphs; ++i) { + glyphNames[i] = 0; + } + pos = charset; + if (pos < 0 || pos >= len) { + goto err0; + } + charsetFormat = file[pos++]; if (charsetFormat == 0) { + if (pos + (nGlyphs - 1) * 2 >= len) { + goto err0; + } for (i = 1; i < nGlyphs; ++i) { - glyphNames[i] = getWord(ptr, 2); - ptr += 2; + glyphNames[i] = getWord(pos, 2); + pos += 2; } } else if (charsetFormat == 1) { i = 1; while (i < nGlyphs) { - c = getWord(ptr, 2); - ptr += 2; - nLeft = *ptr++; + if (pos + 3 > len) { + goto err0; + } + c = getWord(pos, 2); + pos += 2; + nLeft = file[pos++]; for (j = 0; j <= nLeft && i < nGlyphs; ++j) { glyphNames[i++] = c++; } @@ -1393,16 +1516,20 @@ Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) { } else if (charsetFormat == 2) { i = 1; while (i < nGlyphs) { - c = getWord(ptr, 2); - ptr += 2; - nLeft = getWord(ptr, 2); - ptr += 2; + if (pos + 4 > len) { + goto err0; + } + c = getWord(pos, 2); + pos += 2; + nLeft = getWord(pos, 2); + pos += 2; for (j = 0; j <= nLeft && i < nGlyphs; ++j) { glyphNames[i++] = c++; } } } } + err0: return glyphNames; } @@ -1423,10 +1550,10 @@ void Type1CFontFile::eexecWrite(char *s) { } } -void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) { +void Type1CFontFile::eexecCvtGlyph(char *glyphName, int pos, int n) { char eBuf[256]; - cvtGlyph(s, n); + cvtGlyph(pos, n, gTrue); sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength()); eexecWrite(eBuf); eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength()); @@ -1434,28 +1561,37 @@ void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) { delete charBuf; } -void Type1CFontFile::cvtGlyph(Guchar *s, int n) { - int nHints; +void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) { int x; - GBool first = gTrue; + int subrPos, subrLen; double d, dx, dy; GBool dFP; Gushort r2; Guchar byte; int i, k; - charBuf = new GString(); - charBuf->append((char)73); - charBuf->append((char)58); - charBuf->append((char)147); - charBuf->append((char)134); + if (pos < 0 || pos + n > len) { + return; + } - i = 0; - nOps = 0; - nHints = 0; - while (i < n) { - if (s[i] == 12) { - switch (s[i+1]) { + if (top) { + charBuf = new GString(); + charBuf->append((char)73); + charBuf->append((char)58); + charBuf->append((char)147); + charBuf->append((char)134); + nOps = 0; + nHints = 0; + firstOp = gTrue; + } + + i = pos; + while (i < pos + n) { + if (file[i] == 12) { + if (i + 2 > pos + n) { + break; + } + switch (file[i+1]) { case 0: // dotsection (should be Type 1 only?) // ignored break; @@ -1564,19 +1700,19 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { case 28: // exch case 29: // index case 30: // roll - error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]); + error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); break; default: - error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]); + error(-1, "Illegal Type 2 charstring op: 12.%d", file[i+1]); break; } i += 2; nOps = 0; - } else if (s[i] == 19) { // hintmask + } else if (file[i] == 19) { // hintmask // ignored - if (first) { + if (firstOp) { cvtGlyphWidth(nOps == 1); - first = gFalse; + firstOp = gFalse; } if (nOps > 0) { if (nOps & 1) { @@ -1587,11 +1723,11 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { } i += 1 + ((nHints + 7) >> 3); nOps = 0; - } else if (s[i] == 20) { // cntrmask + } else if (file[i] == 20) { // cntrmask // ignored - if (first) { + if (firstOp) { cvtGlyphWidth(nOps == 1); - first = gFalse; + firstOp = gFalse; } if (nOps > 0) { if (nOps & 1) { @@ -1602,8 +1738,11 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { } i += 1 + ((nHints + 7) >> 3); nOps = 0; - } else if (s[i] == 28) { - x = (s[i+1] << 8) + s[i+2]; + } else if (file[i] == 28) { + if (i + 3 > len) { + break; + } + x = (file[i+1] << 8) + file[i+2]; if (x & 0x8000) { x |= -1 << 15; } @@ -1612,12 +1751,39 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { op[nOps++] = x; } i += 3; - } else if (s[i] <= 31) { - switch (s[i]) { + } else if (file[i] == 10) { // callsubr + if (nOps >= 1) { + k = subrBias + (int)op[nOps - 1]; + --nOps; + if ((subrPos = getIndexValPos(subrIdxPos, k, &subrLen)) >= 0) { + cvtGlyph(subrPos, subrLen, gFalse); + } + } else { + error(-1, "Too few args to Type 2 callsubr"); + } + // don't clear the stack + ++i; + } else if (file[i] == 29) { // callgsubr + if (nOps >= 1) { + k = gsubrBias + (int)op[nOps - 1]; + --nOps; + if ((subrPos = getIndexValPos(gsubrIdxPos, k, &subrLen)) >= 0) { + cvtGlyph(subrPos, subrLen, gFalse); + } + } else { + error(-1, "Too few args to Type 2 callgsubr"); + } + // don't clear the stack + ++i; + } else if (file[i] == 11) { // return + // don't clear the stack + ++i; + } else if (file[i] <= 31) { + switch (file[i]) { case 4: // vmoveto - if (first) { + if (firstOp) { cvtGlyphWidth(nOps == 2); - first = gFalse; + firstOp = gFalse; } if (nOps != 1) { error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); @@ -1668,9 +1834,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { } break; case 14: // endchar / seac - if (first) { + if (firstOp) { cvtGlyphWidth(nOps == 1 || nOps == 5); - first = gFalse; + firstOp = gFalse; } if (nOps == 4) { eexecDumpNum(0, 0); @@ -1686,9 +1852,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { } break; case 21: // rmoveto - if (first) { + if (firstOp) { cvtGlyphWidth(nOps == 3); - first = gFalse; + firstOp = gFalse; } if (nOps != 2) { error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); @@ -1698,9 +1864,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { eexecDumpOp1(21); break; case 22: // hmoveto - if (first) { + if (firstOp) { cvtGlyphWidth(nOps == 2); - first = gFalse; + firstOp = gFalse; } if (nOps != 1) { error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); @@ -1871,9 +2037,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { } break; case 1: // hstem - if (first) { + if (firstOp) { cvtGlyphWidth(nOps & 1); - first = gFalse; + firstOp = gFalse; } if (nOps & 1) { error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); @@ -1899,9 +2065,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { nHints += nOps / 2; break; case 3: // vstem - if (first) { + if (firstOp) { cvtGlyphWidth(nOps & 1); - first = gFalse; + firstOp = gFalse; } if (nOps & 1) { error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); @@ -1928,9 +2094,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { break; case 18: // hstemhm // ignored - if (first) { + if (firstOp) { cvtGlyphWidth(nOps & 1); - first = gFalse; + firstOp = gFalse; } if (nOps & 1) { error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); @@ -1939,49 +2105,56 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { break; case 23: // vstemhm // ignored - if (first) { + if (firstOp) { cvtGlyphWidth(nOps & 1); - first = gFalse; + firstOp = gFalse; } if (nOps & 1) { error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); } nHints += nOps / 2; break; - case 10: // callsubr - case 11: // return case 16: // blend - case 29: // callgsubr - error(-1, "Unimplemented Type 2 charstring op: %d", s[i]); + error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); break; default: - error(-1, "Illegal Type 2 charstring op: %d", s[i]); + error(-1, "Illegal Type 2 charstring op: %d", file[i]); break; } ++i; nOps = 0; - } else if (s[i] <= 246) { + } else if (file[i] <= 246) { if (nOps < 48) { fp[nOps] = gFalse; - op[nOps++] = (int)s[i] - 139; + op[nOps++] = (int)file[i] - 139; } ++i; - } else if (s[i] <= 250) { + } else if (file[i] <= 250) { + if (i + 2 > len) { + break; + } if (nOps < 48) { fp[nOps] = gFalse; - op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108; + op[nOps++] = (((int)file[i] - 247) << 8) + (int)file[i+1] + 108; } i += 2; - } else if (s[i] <= 254) { + } else if (file[i] <= 254) { + if (i + 2 > len) { + break; + } if (nOps < 48) { fp[nOps] = gFalse; - op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108; + op[nOps++] = -(((int)file[i] - 251) << 8) - (int)file[i+1] - 108; } i += 2; } else { - x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4]; - if (x & 0x80000000) + if (i + 5 > len) { + break; + } + x = (file[i+1] << 24) | (file[i+2] << 16) | (file[i+3] << 8) | file[i+4]; + if (x & 0x80000000) { x |= -1 << 31; + } if (nOps < 48) { fp[nOps] = gTrue; op[nOps++] = (double)x / 65536.0; @@ -1991,11 +2164,13 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) { } // charstring encryption - r2 = 4330; - for (i = 0; i < charBuf->getLength(); ++i) { - byte = charBuf->getChar(i) ^ (r2 >> 8); - charBuf->setChar(i, byte); - r2 = (byte + r2) * 52845 + 22719; + if (top) { + r2 = 4330; + for (i = 0; i < charBuf->getLength(); ++i) { + byte = charBuf->getChar(i) ^ (r2 >> 8); + charBuf->setChar(i, byte); + r2 = (byte + r2) * 52845 + 22719; + } } } @@ -2130,42 +2305,71 @@ void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA, sprintf(buf, "] def\n"); } -int Type1CFontFile::getIndexLen(Guchar *indexPtr) { - return (int)getWord(indexPtr, 2); +int Type1CFontFile::getIndexLen(int indexPos) { + if (indexPos + 2 > len) { + return -1; + } + return (int)getWord(indexPos, 2); } -Guchar *Type1CFontFile::getIndexValPtr(Guchar *indexPtr, int i) { - int n, offSize; - Guchar *idxStartPtr; +int Type1CFontFile::getIndexValPos(int indexPos, int i, int *valLen) { + int n, offSize, idxStartPos; + int pos0, pos1; - n = (int)getWord(indexPtr, 2); - offSize = indexPtr[2]; - idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1; - return idxStartPtr + getWord(indexPtr + 3 + i * offSize, offSize); + if (indexPos < 0 || indexPos + 3 > len) { + return -1; + } + n = (int)getWord(indexPos, 2); + if (i >= n) { + return -1; + } + offSize = file[indexPos + 2]; + if (offSize < 1 || offSize > 4) { + return -1; + } + idxStartPos = indexPos + 3 + (n + 1) * offSize - 1; + if (idxStartPos >= len) { + return -1; + } + pos0 = idxStartPos + getWord(indexPos + 3 + i * offSize, offSize); + pos1 = idxStartPos + getWord(indexPos + 3 + (i + 1) * offSize, offSize); + if (pos0 < 0 || pos0 >= len || pos1 < pos0 || pos1 > len) { + return -1; + } + *valLen = pos1 - pos0; + return pos0; } -Guchar *Type1CFontFile::getIndexEnd(Guchar *indexPtr) { - int n, offSize; - Guchar *idxStartPtr; +int Type1CFontFile::getIndexEnd(int indexPos) { + int n, offSize, idxStartPos; - n = (int)getWord(indexPtr, 2); - offSize = indexPtr[2]; - idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1; - return idxStartPtr + getWord(indexPtr + 3 + n * offSize, offSize); + if (indexPos + 3 > len) { + return -1; + } + n = (int)getWord(indexPos, 2); + offSize = file[indexPos + 2]; + idxStartPos = indexPos + 3 + (n + 1) * offSize - 1; + if (idxStartPos >= len) { + return -1; + } + return idxStartPos + getWord(indexPos + 3 + n * offSize, offSize); } -Guint Type1CFontFile::getWord(Guchar *ptr, int size) { +Guint Type1CFontFile::getWord(int pos, int size) { Guint x; int i; + if (pos < 0 || pos + size > len) { + return 0; + } x = 0; for (i = 0; i < size; ++i) { - x = (x << 8) + *ptr++; + x = (x << 8) + file[pos + i]; } return x; } -double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) { +double Type1CFontFile::getNum(int *pos, GBool *isFP) { static char nybChars[16] = "0123456789.ee -"; int b0, b, nyb0, nyb1; double x; @@ -2174,20 +2378,31 @@ double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) { x = 0; *isFP = gFalse; - b0 = (*ptr)[0]; + if (*pos >= len) { + return 0; + } + b0 = file[*pos]; if (b0 < 28) { x = 0; } else if (b0 == 28) { - x = ((*ptr)[1] << 8) + (*ptr)[2]; - *ptr += 3; + if (*pos + 3 <= len) { + x = (file[*pos + 1] << 8) + file[*pos + 2]; + *pos += 3; + } } else if (b0 == 29) { - x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4]; - *ptr += 5; + if (*pos + 5 <= len) { + x = (file[*pos + 1] << 24) + (file[*pos + 2] << 16) + + (file[*pos + 3] << 8) + file[*pos + 4]; + *pos += 5; + } } else if (b0 == 30) { - *ptr += 1; + *pos += 1; i = 0; do { - b = *(*ptr)++; + if (*pos >= len) { + break; + } + b = file[(*pos)++]; nyb0 = b >> 4; nyb1 = b & 0x0f; if (nyb0 == 0xf) { @@ -2225,32 +2440,35 @@ double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) { x = 0; } else if (b0 < 247) { x = b0 - 139; - *ptr += 1; + *pos += 1; } else if (b0 < 251) { - x = ((b0 - 247) << 8) + (*ptr)[1] + 108; - *ptr += 2; + if (*pos + 2 <= len) { + x = ((b0 - 247) << 8) + file[*pos + 1] + 108; + *pos += 2; + } } else { - x = -((b0 - 251) << 8) - (*ptr)[1] - 108; - *ptr += 2; + if (*pos + 2 <= len) { + x = -((b0 - 251) << 8) - file[*pos + 1] - 108; + *pos += 2; + } } return x; } char *Type1CFontFile::getString(int sid, char *buf) { - Guchar *idxPtr0, *idxPtr1; - int n; + int idxPos, n; if (sid < 391) { strcpy(buf, type1CStdStrings[sid]); } else { sid -= 391; - idxPtr0 = getIndexValPtr(stringIdxPtr, sid); - idxPtr1 = getIndexValPtr(stringIdxPtr, sid + 1); - if ((n = idxPtr1 - idxPtr0) > 255) { - n = 255; + idxPos = getIndexValPos(stringIdxPos, sid, &n); + if (idxPos < 0 || n < 0 || n > 255 || idxPos + n > len) { + buf[0] = '\0'; + } else { + strncpy(buf, (char *)&file[idxPos], n); + buf[n] = '\0'; } - strncpy(buf, (char *)idxPtr0, n); - buf[n] = '\0'; } return buf; } @@ -2617,6 +2835,12 @@ enum T42FontIndexMode { t42FontModeMacRoman }; +struct TrueTypeLoca { + int idx; + int pos; + int length; +}; + TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) { int pos, i, idx, n, length; Guint size, startPos, endPos; @@ -2638,6 +2862,10 @@ TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) { tableHdrs[i].checksum = getULong(pos+4); tableHdrs[i].offset = getULong(pos+8); tableHdrs[i].length = getULong(pos+12); + if (tableHdrs[i].offset + tableHdrs[i].length < tableHdrs[i].offset || + tableHdrs[i].offset + tableHdrs[i].length > (Guint)len) { + tableHdrs[i].offset = (Guint)-1; + } pos += 16; } @@ -2710,9 +2938,7 @@ char *TrueTypeFontFile::getName() { char **TrueTypeFontFile::getEncoding() { int cmap[256]; int nCmaps, cmapPlatform, cmapEncoding, cmapFmt; - int cmapLen, cmapOffset, cmapFirst; - int segCnt, segStart, segEnd, segDelta, segOffset; - int pos, i, j, k; + int pos, i, j; Guint fmt; GString *s; int stringIdx, stringPos, n; @@ -2734,6 +2960,8 @@ char **TrueTypeFontFile::getEncoding() { // if the font has a Windows-symbol cmap, use it; // otherwise, use the first cmap in the table + cmapPlatform = 0; // make gcc happy + cmapEncoding = 0; // make gcc happy for (i = 0; i < nCmaps; ++i) { cmapPlatform = getUShort(pos + 4 + 8*i); cmapEncoding = getUShort(pos + 4 + 8*i + 2); @@ -2750,56 +2978,17 @@ char **TrueTypeFontFile::getEncoding() { // read the cmap cmapFmt = getUShort(pos); - switch (cmapFmt) { - case 0: // byte encoding table (Apple standard) - cmapLen = getUShort(pos + 2); - for (i = 0; i < cmapLen && i < 256; ++i) { - cmap[i] = getByte(pos + 6 + i); - } - break; - case 4: // segment mapping to delta values (Microsoft standard) - if (cmapPlatform == 3 && cmapEncoding == 0) { - // Windows-symbol uses char codes 0xf000 - 0xf0ff - cmapOffset = 0xf000; - } else { - cmapOffset = 0; - } - segCnt = getUShort(pos + 6) / 2; - for (i = 0; i < segCnt; ++i) { - segEnd = getUShort(pos + 14 + 2*i); - segStart = getUShort(pos + 16 + 2*segCnt + 2*i); - segDelta = getUShort(pos + 16 + 4*segCnt + 2*i); - segOffset = getUShort(pos + 16 + 6*segCnt + 2*i); - if (segStart - cmapOffset <= 0xff && - segEnd - cmapOffset >= 0) { - for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset; - j <= segEnd && j - cmapOffset <= 0xff; - ++j) { - if (segOffset == 0) { - k = (j + segDelta) & 0xffff; - } else { - k = getUShort(pos + 16 + 6*segCnt + 2*i + - segOffset + 2 * (j - segStart)); - if (k != 0) { - k = (k + segDelta) & 0xffff; - } - } - cmap[j - cmapOffset] = k; - } + for (i = 0; i < 256; ++i) { + cmap[i] = getCmapEntry(cmapFmt, pos, i); + } + // Windows-symbol sometimes uses char codes 0xf000 - 0xf0ff, so + // we use these to override 0x0000 - 0x00ff + if (cmapPlatform == 3 && cmapEncoding == 0) { + for (i = 0; i < 256; ++i) { + if ((j = getCmapEntry(cmapFmt, pos, 0xf000 + i)) != 0) { + cmap[i] = j; } } - break; - case 6: // trimmed table mapping - cmapFirst = getUShort(pos + 6); - cmapLen = getUShort(pos + 8); - for (i = cmapFirst; i < 256 && i < cmapFirst + cmapLen; ++i) { - cmap[i] = getUShort(pos + 10 + 2*i); - } - break; - default: - error(-1, "Unimplemented cmap format (%d) in TrueType font file", - cmapFmt); - break; } } @@ -2838,9 +3027,13 @@ char **TrueTypeFontFile::getEncoding() { ++stringIdx, stringPos += 1 + getByte(stringPos)) ; } n = getByte(stringPos); - s = new GString(file + stringPos + 1, n); - encoding[i] = copyString(s->getCString()); - delete s; + if (stringPos >= 0 && stringPos + 1 + n <= len) { + s = new GString(file + stringPos + 1, n); + encoding[i] = copyString(s->getCString()); + delete s; + } else { + encoding[i] = copyString(macGlyphNames[0]); + } ++stringIdx; stringPos += 1 + n; } @@ -2882,6 +3075,7 @@ char **TrueTypeFontFile::getEncoding() { void TrueTypeFontFile::convertToType42(char *name, char **encodingA, CharCodeToUnicode *toUnicode, GBool pdfFontHasEncoding, + GBool pdfFontIsSymbolic, FontFileOutputFunc outputFunc, void *outputStream) { char buf[512]; @@ -2904,7 +3098,7 @@ void TrueTypeFontFile::convertToType42(char *name, char **encodingA, // write the guts of the dictionary cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream); - cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, + cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, pdfFontIsSymbolic, outputFunc, outputStream); cvtSfnts(outputFunc, outputStream, NULL); @@ -3161,7 +3355,7 @@ int TrueTypeFontFile::seekTable(char *tag) { for (i = 0; i < nTables; ++i) { if (!strncmp(tableHdrs[i].tag, tag, 4)) { - return tableHdrs[i].offset; + return (int)tableHdrs[i].offset; } } return -1; @@ -3172,6 +3366,9 @@ int TrueTypeFontFile::seekTableIdx(char *tag) { for (i = 0; i < nTables; ++i) { if (!strncmp(tableHdrs[i].tag, tag, 4)) { + if (tableHdrs[i].offset == (Guint)-1) { + return -1; + } return i; } } @@ -3208,6 +3405,7 @@ void TrueTypeFontFile::cvtEncoding(char **encodingA, GBool pdfFontHasEncoding, void TrueTypeFontFile::cvtCharStrings(char **encodingA, CharCodeToUnicode *toUnicode, GBool pdfFontHasEncoding, + GBool pdfFontIsSymbolic, FontFileOutputFunc outputFunc, void *outputStream) { int unicodeCmap, macRomanCmap, msSymbolCmap; @@ -3232,7 +3430,9 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA, // 1. If the PDF font has an encoding: // 1a. If the TrueType font has a Microsoft Unicode cmap, use it, // and use the Unicode indexes, not the char codes. - // 1b. If the TrueType font has a Macintosh Roman cmap, use it, + // 1b. If the PDF font is symbolic and the TrueType font has a + // Microsoft Symbol cmap, use it, and use (0xf000 + char code). + // 1c. If the TrueType font has a Macintosh Roman cmap, use it, // and reverse map the char names through MacRomanEncoding to // get char codes. // 2. If the PDF font does not have an encoding: @@ -3248,7 +3448,7 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA, for (i = 0; i < nCmaps; ++i) { cmapPlatform = getUShort(pos + 4 + 8*i); cmapEncoding = getUShort(pos + 4 + 8*i + 2); - if (cmapPlatform == 3 && cmapEncoding == 1) { + if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0) { unicodeCmap = i; } else if (cmapPlatform == 1 && cmapEncoding == 0) { macRomanCmap = i; @@ -3262,6 +3462,10 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA, if (unicodeCmap >= 0) { i = unicodeCmap; mode = t42FontModeUnicode; + } else if (pdfFontIsSymbolic && msSymbolCmap >= 0) { + i = msSymbolCmap; + mode = t42FontModeCharCodeOffset; + cmapOffset = 0xf000; } else if (macRomanCmap >= 0) { i = macRomanCmap; mode = t42FontModeMacRoman; @@ -3289,8 +3493,11 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA, // map char name to glyph index: // 1. use encoding to map name to char code // 2. use cmap to map char code to glyph index - j = 0; // make gcc happy - for (i = 0; i < 256; ++i) { + // N.B. We do this in reverse order because font subsets can have + // weird encodings that use the same character name twice, and + // the first definition is probably the one we want. + k = 0; // make gcc happy + for (i = 255; i >= 0; --i) { if (pdfFontHasEncoding) { name = encodingA[i]; } else { @@ -3301,24 +3508,26 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA, switch (mode) { case t42FontModeUnicode: toUnicode->mapToUnicode((CharCode)i, &u, 1); - j = (int)u; + k = getCmapEntry(cmapFmt, pos, (int)u); break; case t42FontModeCharCode: - j = i; + k = getCmapEntry(cmapFmt, pos, i); break; case t42FontModeCharCodeOffset: - j = cmapOffset + i; + if ((k = getCmapEntry(cmapFmt, pos, cmapOffset + i)) == 0) { + k = getCmapEntry(cmapFmt, pos, i); + } break; case t42FontModeMacRoman: j = globalParams->getMacRomanCharCode(name); + k = getCmapEntry(cmapFmt, pos, j); break; } // note: Distiller (maybe Adobe's PS interpreter in general) // doesn't like TrueType fonts that have CharStrings entries // which point to nonexistent glyphs, hence the (k < nGlyphs) // test - if ((k = getCmapEntry(cmapFmt, pos, j)) > 0 && - k < nGlyphs) { + if (k > 0 && k < nGlyphs) { (*outputFunc)(outputStream, "/", 1); (*outputFunc)(outputStream, name, strlen(name)); sprintf(buf, " %d def\n", k); @@ -3367,6 +3576,9 @@ int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) { segStart = getUShort(pos + 16 + 2*segCnt + 2*b); segDelta = getUShort(pos + 16 + 4*segCnt + 2*b); segOffset = getUShort(pos + 16 + 6*segCnt + 2*b); + if (code < segStart) { + return 0; + } if (segOffset == 0) { i = (code + segDelta) & 0xffff; } else { @@ -3393,12 +3605,24 @@ int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) { return 0; } +static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { + return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx; +} + +static int cmpTrueTypeLocaPos(const void *p1, const void *p2) { + if (((TrueTypeLoca *)p1)->pos == ((TrueTypeLoca *)p2)->pos) { + return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx; + } else { + return ((TrueTypeLoca *)p1)->pos - ((TrueTypeLoca *)p2)->pos; + } +} + void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc, void *outputStream, GString *name) { TTFontTableHdr newTableHdrs[nT42Tables]; char tableDir[12 + nT42Tables*16]; char headTable[54]; - int *origLocaTable; + TrueTypeLoca *origLocaTable; char *locaTable; int nNewTables; Guint checksum; @@ -3409,30 +3633,36 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc, memcpy(headTable, file + seekTable("head"), 54); headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0; - // read the original 'loca' table and construct the new one - // (pad each glyph out to a multiple of 4 bytes) - origLocaTable = (int *)gmalloc((nGlyphs + 1) * sizeof(int)); + // read the original 'loca' table and sort it into proper order -- + // some (non-compliant) fonts have out-of-order loca tables; in + // order to correctly handle the case where (compliant) fonts have + // empty entries in the middle of the table, cmpTrueTypeLocaPos uses + // pos 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) + origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * + sizeof(TrueTypeLoca)); pos = seekTable("loca"); for (i = 0; i <= nGlyphs; ++i) { + origLocaTable[i].idx = i; if (locaFmt) { - origLocaTable[i] = getULong(pos + 4*i); + origLocaTable[i].pos = getULong(pos + 4*i); } else { - origLocaTable[i] = 2 * getUShort(pos + 2*i); + origLocaTable[i].pos = 2 * getUShort(pos + 2*i); } } - locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); - if (locaFmt) { - locaTable[0] = locaTable[1] = locaTable[2] = locaTable[3] = 0; - } else { - locaTable[0] = locaTable[1] = 0; + qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaPos); + for (i = 0; i < nGlyphs; ++i) { + origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos; } + origLocaTable[nGlyphs].length = 0; + qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx); + + // construct the new 'loca' table, padding each glyph out to a + // multiple of 4 bytes + locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); pos = 0; - for (i = 1; i <= nGlyphs; ++i) { - length = origLocaTable[i] - origLocaTable[i-1]; - if (length & 3) { - length += 4 - (length & 3); - } - pos += length; + for (i = 0; i <= nGlyphs; ++i) { if (locaFmt) { locaTable[4*i ] = (char)(pos >> 24); locaTable[4*i+1] = (char)(pos >> 16); @@ -3442,6 +3672,11 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc, locaTable[2*i ] = (char)(pos >> 9); locaTable[2*i+1] = (char)(pos >> 1); } + length = origLocaTable[i].length; + if (length & 3) { + length += 4 - (length & 3); + } + pos += length; } // count the number of tables @@ -3471,11 +3706,15 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc, checksum = 0; glyfPos = seekTable("glyf"); for (j = 0; j < nGlyphs; ++j) { - glyphLength = origLocaTable[j+1] - origLocaTable[j]; + glyphLength = origLocaTable[j].length; pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0; length += glyphLength + pad; - checksum += computeTableChecksum(file + glyfPos + origLocaTable[j], - glyphLength); + if (glyphLength >= 0 && + glyfPos + origLocaTable[j].pos + glyphLength <= len) { + checksum += + computeTableChecksum(file + glyfPos + origLocaTable[j].pos, + glyphLength); + } } } else { if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) { @@ -3566,9 +3805,10 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc, } else if (i == t42GlyfTable) { glyfPos = seekTable("glyf"); for (j = 0; j < nGlyphs; ++j) { - length = origLocaTable[j+1] - origLocaTable[j]; - if (length > 0) { - dumpString(file + glyfPos + origLocaTable[j], length, + length = origLocaTable[j].length; + if (length > 0 && + glyfPos + origLocaTable[j].pos + length <= len) { + dumpString(file + glyfPos + origLocaTable[j].pos, length, outputFunc, outputStream); } } @@ -3577,8 +3817,11 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc, // already reported during the construction of the table // headers if ((length = newTableHdrs[i].length) > 0) { - dumpString(file + seekTable(t42Tables[i].tag), length, - outputFunc, outputStream); + j = seekTable(t42Tables[i].tag); + if (j >= 0) { + dumpString(file + seekTable(t42Tables[i].tag), length, + outputFunc, outputStream); + } } } } @@ -3679,209 +3922,265 @@ void TrueTypeFontFile::writeTTF(FILE *out) { }; GBool haveCmap, haveName, havePost; GBool dirCmap, dirName, dirPost; - int nNewTables, nAllTables, pad; + GBool unsortedLoca; + int nNewTables, nZeroLengthTables, nAllTables; + TTFontTableHdr *newTableHdrs; char *tableDir; - Guint t, pos; - int i, j; + TrueTypeLoca *origLocaTable; + char *locaTable; + int length, glyfLength; + Guint t, pos, pos2; + int i, j, k; - // check for missing tables + // check for missing/broken tables haveCmap = seekTable("cmap") >= 0; haveName = seekTable("name") >= 0; havePost = seekTable("post") >= 0; + unsortedLoca = gFalse; + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + if (locaFmt) { + pos2 = getULong(pos + 4*i); + } else { + pos2 = 2 * getUShort(pos + 2*i); + } + if (pos2 < pos) { + unsortedLoca = gTrue; + break; + } + pos = pos2; + } nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1); - if (!nNewTables && !mungedCmapSize) { - // none are missing - write the TTF file as is + nZeroLengthTables = 0; + for (i = 0; i < nTables; ++i) { + if (tableHdrs[i].length == 0) { + ++nZeroLengthTables; + } + } + if (!nNewTables && !nZeroLengthTables && !mungedCmapSize && !unsortedLoca) { + // nothing is broken - write the TTF file as is fwrite(file, 1, len, out); return; } + // if the glyph data isn't sorted (as listed in the 'loca' table), + // construct a new 'loca' table + if (unsortedLoca) { + origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * + sizeof(TrueTypeLoca)); + pos = seekTable("loca"); + for (i = 0; i <= nGlyphs; ++i) { + origLocaTable[i].idx = i; + if (locaFmt) { + origLocaTable[i].pos = getULong(pos + 4*i); + } else { + origLocaTable[i].pos = 2 * getUShort(pos + 2*i); + } + } + qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaPos); + for (i = 0; i < nGlyphs; ++i) { + origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos; + } + origLocaTable[nGlyphs].length = 0; + qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); + locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + if (locaFmt) { + locaTable[4*i ] = (char)(pos >> 24); + locaTable[4*i+1] = (char)(pos >> 16); + locaTable[4*i+2] = (char)(pos >> 8); + locaTable[4*i+3] = (char) pos; + } else { + locaTable[2*i ] = (char)(pos >> 9); + locaTable[2*i+1] = (char)(pos >> 1); + } + length = origLocaTable[i].length; + if (length & 3) { + length += 4 - (length & 3); + } + pos += length; + } + glyfLength = pos; + } else { + origLocaTable = NULL; // make gcc happy + locaTable = NULL; // make gcc happy + glyfLength = 0; // make gcc happy + } + // construct the new table directory - nAllTables = nTables + nNewTables; - tableDir = (char *)gmalloc(12 + nAllTables * 16); - memcpy(tableDir, file, 12 + nTables * 16); - tableDir[4] = (char)((nAllTables >> 8) & 0xff); - tableDir[5] = (char)(nAllTables & 0xff); - for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ; - t = 1 << (4 + i); - tableDir[6] = (char)((t >> 8) & 0xff); - tableDir[7] = (char)(t & 0xff); - tableDir[8] = (char)((i >> 8) & 0xff); - tableDir[9] = (char)(i & 0xff); - t = nAllTables * 16 - t; - tableDir[10] = (char)((t >> 8) & 0xff); - tableDir[11] = (char)(t & 0xff); + nAllTables = nTables - nZeroLengthTables + nNewTables; + newTableHdrs = (TTFontTableHdr *)gmalloc(nAllTables * + sizeof(TTFontTableHdr)); dirCmap = haveCmap; dirName = haveName; dirPost = havePost; + pos = 12 + nAllTables * 16; j = 0; - pad = (len & 3) ? 4 - (len & 3) : 0; - pos = len + pad + 16 * nNewTables; for (i = 0; i < nTables; ++i) { if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) { - tableDir[12 + 16*j ] = 'c'; - tableDir[12 + 16*j + 1] = 'm'; - tableDir[12 + 16*j + 2] = 'a'; - tableDir[12 + 16*j + 3] = 'p'; - tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum - tableDir[12 + 16*j + 5] = (char)0; - tableDir[12 + 16*j + 6] = (char)0; - tableDir[12 + 16*j + 7] = (char)0; - tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); - tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); - tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); - tableDir[12 + 16*j + 11] = (char)( pos & 0xff); - tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff); - tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff); - tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff); - tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff); - pos += sizeof(cmapTab); + memcpy(newTableHdrs[j].tag, "cmap", 4); + newTableHdrs[j].checksum = 0; //~ should compute the checksum + newTableHdrs[j].offset = pos; + pos += newTableHdrs[j].length = sizeof(cmapTab); + if (pos & 3) { + pos += 4 - (pos & 3); + } ++j; dirCmap = gTrue; } if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) { - tableDir[12 + 16*j ] = 'n'; - tableDir[12 + 16*j + 1] = 'a'; - tableDir[12 + 16*j + 2] = 'm'; - tableDir[12 + 16*j + 3] = 'e'; - tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum - tableDir[12 + 16*j + 5] = (char)0; - tableDir[12 + 16*j + 6] = (char)0; - tableDir[12 + 16*j + 7] = (char)0; - tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); - tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); - tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); - tableDir[12 + 16*j + 11] = (char)( pos & 0xff); - tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff); - tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff); - tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff); - tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff); - pos += sizeof(nameTab); + memcpy(newTableHdrs[j].tag, "name", 4); + newTableHdrs[j].checksum = 0; //~ should compute the checksum + newTableHdrs[j].offset = pos; + pos += newTableHdrs[j].length = sizeof(nameTab); + if (pos & 3) { + pos += 4 - (pos & 3); + } ++j; dirName = gTrue; } - if (!dirName && strncmp(tableHdrs[i].tag, "post", 4) > 0) { - tableDir[12 + 16*j ] = 'p'; - tableDir[12 + 16*j + 1] = 'o'; - tableDir[12 + 16*j + 2] = 's'; - tableDir[12 + 16*j + 3] = 't'; - tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum - tableDir[12 + 16*j + 5] = (char)0; - tableDir[12 + 16*j + 6] = (char)0; - tableDir[12 + 16*j + 7] = (char)0; - tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); - tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); - tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); - tableDir[12 + 16*j + 11] = (char)( pos & 0xff); - tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff); - tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff); - tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff); - tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff); - pos += sizeof(postTab); + if (!dirPost && strncmp(tableHdrs[i].tag, "post", 4) > 0) { + memcpy(newTableHdrs[j].tag, "post", 4); + newTableHdrs[j].checksum = 0; //~ should compute the checksum + newTableHdrs[j].offset = pos; + pos += newTableHdrs[j].length = sizeof(postTab); + if (pos & 3) { + pos += 4 - (pos & 3); + } ++j; dirPost = gTrue; } - tableDir[12 + 16*j ] = tableHdrs[i].tag[0]; - tableDir[12 + 16*j + 1] = tableHdrs[i].tag[1]; - tableDir[12 + 16*j + 2] = tableHdrs[i].tag[2]; - tableDir[12 + 16*j + 3] = tableHdrs[i].tag[3]; - tableDir[12 + 16*j + 4] = (char)((tableHdrs[i].checksum >> 24) & 0xff); - tableDir[12 + 16*j + 5] = (char)((tableHdrs[i].checksum >> 16) & 0xff); - tableDir[12 + 16*j + 6] = (char)((tableHdrs[i].checksum >> 8) & 0xff); - tableDir[12 + 16*j + 7] = (char)( tableHdrs[i].checksum & 0xff); - t = tableHdrs[i].offset + nNewTables * 16; - tableDir[12 + 16*j + 8] = (char)((t >> 24) & 0xff); - tableDir[12 + 16*j + 9] = (char)((t >> 16) & 0xff); - tableDir[12 + 16*j + 10] = (char)((t >> 8) & 0xff); - tableDir[12 + 16*j + 11] = (char)( t & 0xff); - tableDir[12 + 16*j + 12] = (char)((tableHdrs[i].length >> 24) & 0xff); - tableDir[12 + 16*j + 13] = (char)((tableHdrs[i].length >> 16) & 0xff); - tableDir[12 + 16*j + 14] = (char)((tableHdrs[i].length >> 8) & 0xff); - tableDir[12 + 16*j + 15] = (char)( tableHdrs[i].length & 0xff); - ++j; + // throw away zero-length tables - they confuse FreeType + if (tableHdrs[i].length > 0) { + memcpy(newTableHdrs[j].tag, tableHdrs[i].tag, 4); + newTableHdrs[j].checksum = tableHdrs[i].checksum; + newTableHdrs[j].offset = pos; + if (unsortedLoca && !strncmp(tableHdrs[i].tag, "loca", 4)) { + newTableHdrs[j].length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + } else if (unsortedLoca && !strncmp(tableHdrs[i].tag, "glyf", 4)) { + newTableHdrs[j].length = glyfLength; + } else { + newTableHdrs[j].length = tableHdrs[i].length; + } + pos += newTableHdrs[j].length; + if (pos & 3) { + pos += 4 - (pos & 3); + } + ++j; + } } if (!dirCmap) { - tableDir[12 + 16*j ] = 'c'; - tableDir[12 + 16*j + 1] = 'm'; - tableDir[12 + 16*j + 2] = 'a'; - tableDir[12 + 16*j + 3] = 'p'; - tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum - tableDir[12 + 16*j + 5] = (char)0; - tableDir[12 + 16*j + 6] = (char)0; - tableDir[12 + 16*j + 7] = (char)0; - tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); - tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); - tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); - tableDir[12 + 16*j + 11] = (char)( pos & 0xff); - tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff); - tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff); - tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >> 8) & 0xff); - tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab) & 0xff); - pos += sizeof(cmapTab); + memcpy(newTableHdrs[j].tag, "cmap", 4); + newTableHdrs[j].checksum = 0; //~ should compute the checksum + newTableHdrs[j].offset = pos; + pos += newTableHdrs[j].length = sizeof(cmapTab); + if (pos & 3) { + pos += 4 - (pos & 3); + } ++j; - dirCmap = gTrue; } if (!dirName) { - tableDir[12 + 16*j ] = 'n'; - tableDir[12 + 16*j + 1] = 'a'; - tableDir[12 + 16*j + 2] = 'm'; - tableDir[12 + 16*j + 3] = 'e'; - tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum - tableDir[12 + 16*j + 5] = (char)0; - tableDir[12 + 16*j + 6] = (char)0; - tableDir[12 + 16*j + 7] = (char)0; - tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); - tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); - tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); - tableDir[12 + 16*j + 11] = (char)( pos & 0xff); - tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff); - tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff); - tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >> 8) & 0xff); - tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab) & 0xff); - pos += sizeof(nameTab); + memcpy(newTableHdrs[j].tag, "name", 4); + newTableHdrs[j].checksum = 0; //~ should compute the checksum + newTableHdrs[j].offset = pos; + pos += newTableHdrs[j].length = sizeof(nameTab); + if (pos & 3) { + pos += 4 - (pos & 3); + } ++j; - dirName = gTrue; } if (!dirPost) { - tableDir[12 + 16*j ] = 'p'; - tableDir[12 + 16*j + 1] = 'o'; - tableDir[12 + 16*j + 2] = 's'; - tableDir[12 + 16*j + 3] = 't'; - tableDir[12 + 16*j + 4] = (char)0; //~ should compute the checksum - tableDir[12 + 16*j + 5] = (char)0; - tableDir[12 + 16*j + 6] = (char)0; - tableDir[12 + 16*j + 7] = (char)0; - tableDir[12 + 16*j + 8] = (char)((pos >> 24) & 0xff); - tableDir[12 + 16*j + 9] = (char)((pos >> 16) & 0xff); - tableDir[12 + 16*j + 10] = (char)((pos >> 8) & 0xff); - tableDir[12 + 16*j + 11] = (char)( pos & 0xff); - tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff); - tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff); - tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >> 8) & 0xff); - tableDir[12 + 16*j + 15] = (char)( sizeof(postTab) & 0xff); - pos += sizeof(postTab); + memcpy(newTableHdrs[j].tag, "post", 4); + newTableHdrs[j].checksum = 0; //~ should compute the checksum + newTableHdrs[j].offset = pos; + pos += newTableHdrs[j].length = sizeof(postTab); + if (pos & 3) { + pos += 4 - (pos & 3); + } ++j; - dirPost = gTrue; + } + tableDir = (char *)gmalloc(12 + nAllTables * 16); + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = (char)((nAllTables >> 8) & 0xff); // numTables + tableDir[5] = (char)(nAllTables & 0xff); + for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ; + t = 1 << (4 + i); + tableDir[6] = (char)((t >> 8) & 0xff); // searchRange + tableDir[7] = (char)(t & 0xff); + tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector + tableDir[9] = (char)(i & 0xff); + t = nAllTables * 16 - t; + tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift + tableDir[11] = (char)(t & 0xff); + pos = 12; + for (i = 0; i < nAllTables; ++i) { + tableDir[pos ] = newTableHdrs[i].tag[0]; + tableDir[pos+ 1] = newTableHdrs[i].tag[1]; + tableDir[pos+ 2] = newTableHdrs[i].tag[2]; + tableDir[pos+ 3] = newTableHdrs[i].tag[3]; + tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24); + tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16); + tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8); + tableDir[pos+ 7] = (char) newTableHdrs[i].checksum; + tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24); + tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16); + tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8); + tableDir[pos+11] = (char) newTableHdrs[i].offset; + tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24); + tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16); + tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8); + tableDir[pos+15] = (char) newTableHdrs[i].length; + pos += 16; } // write the table directory fwrite(tableDir, 1, 12 + 16 * nAllTables, out); - // write the original tables - fwrite(file + 12 + 16*nTables, 1, len - (12 + 16*nTables), out); - - // write the new tables - for (i = 0; i < pad; ++i) { - fputc((char)0, out); - } - if (!haveCmap) { - fwrite(cmapTab, 1, sizeof(cmapTab), out); - } - if (!haveName) { - fwrite(nameTab, 1, sizeof(nameTab), out); - } - if (!havePost) { - fwrite(postTab, 1, sizeof(postTab), out); + // write the tables + for (i = 0; i < nAllTables; ++i) { + if (!haveCmap && !strncmp(newTableHdrs[i].tag, "cmap", 4)) { + fwrite(cmapTab, 1, newTableHdrs[i].length, out); + } else if (!haveName && !strncmp(newTableHdrs[i].tag, "name", 4)) { + fwrite(nameTab, 1, newTableHdrs[i].length, out); + } else if (!havePost && !strncmp(newTableHdrs[i].tag, "post", 4)) { + fwrite(postTab, 1, newTableHdrs[i].length, out); + } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "loca", 4)) { + fwrite(locaTable, 1, newTableHdrs[i].length, out); + } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "glyf", 4)) { + pos = seekTable("glyf"); + for (j = 0; j < nGlyphs; ++j) { + length = origLocaTable[j].length; + if (length > 0 && + pos + origLocaTable[j].pos + length <= (Guint)len) { + fwrite(file + pos + origLocaTable[j].pos, 1, length, out); + if ((k = length & 3)) { + for (; k < 4; ++k) { + fputc((char)0, out); + } + } + } + } + } else { + fwrite(file + seekTable(newTableHdrs[i].tag), + 1, newTableHdrs[i].length, out); + } + if ((j = (newTableHdrs[i].length & 3))) { + for (; j < 4; ++j) { + fputc((char)0, out); + } + } } - + gfree(tableDir); + gfree(newTableHdrs); + if (unsortedLoca) { + gfree(origLocaTable); + gfree(locaTable); + } } diff --git a/pdf/xpdf/FontFile.h b/pdf/xpdf/FontFile.h index 7293992..a71653c 100644 --- a/pdf/xpdf/FontFile.h +++ b/pdf/xpdf/FontFile.h @@ -2,7 +2,7 @@ // // FontFile.h // -// Copyright 1999-2002 Glyph & Cog, LLC +// Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== @@ -75,6 +75,7 @@ public: Type1CFontFile(char *fileA, int lenA); virtual ~Type1CFontFile(); + GBool isOk() { return ok; } virtual char *getName(); virtual char **getEncoding(); @@ -97,14 +98,14 @@ public: private: - void readNameAndEncoding(); + void readEncoding(); void readTopDict(Type1CTopDict *dict); void readPrivateDict(Type1CPrivateDict *privateDict, int offset, int size); Gushort *readCharset(int charset, int nGlyphs); void eexecWrite(char *s); - void eexecCvtGlyph(char *glyphName, Guchar *s, int n); - void cvtGlyph(Guchar *s, int n); + void eexecCvtGlyph(char *glyphName, int pos, int n); + void cvtGlyph(int pos, int n, GBool top); void cvtGlyphWidth(GBool useOp); void eexecDumpNum(double x, GBool fpA); void eexecDumpOp1(int opA); @@ -112,29 +113,33 @@ private: void eexecWriteCharstring(Guchar *s, int n); void getDeltaInt(char *buf, char *key, double *opA, int n); void getDeltaReal(char *buf, char *key, double *opA, int n); - int getIndexLen(Guchar *indexPtr); - Guchar *getIndexValPtr(Guchar *indexPtr, int i); - Guchar *getIndexEnd(Guchar *indexPtr); - Guint getWord(Guchar *ptr, int size); - double getNum(Guchar **ptr, GBool *fp); + int getIndexLen(int indexPos); + int getIndexValPos(int indexPos, int i, int *valLen); + int getIndexEnd(int indexPos); + Guint getWord(int pos, int size); + double getNum(int *pos, GBool *fp); char *getString(int sid, char *buf); - char *file; + Guchar *file; int len; GString *name; char **encoding; - int topOffSize; - Guchar *topDictIdxPtr; - Guchar *stringIdxPtr; - Guchar *gsubrIdxPtr; + int topDictIdxPos; + int stringIdxPos; + int gsubrIdxPos; + int subrIdxPos; + int gsubrBias; + int subrBias; FontFileOutputFunc outputFunc; void *outputStream; double op[48]; // operands GBool fp[48]; // true if operand is fixed point 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 double defaultWidthX; // default glyph width double nominalWidthX; // nominal glyph width GBool defaultWidthXFP; // true if defaultWidthX is fixed point @@ -142,6 +147,8 @@ private: Gushort r1; // eexec encryption key GString *charBuf; // charstring output buffer int line; // number of eexec chars on current line + + GBool ok; }; //------------------------------------------------------------------------ @@ -171,6 +178,7 @@ public: void convertToType42(char *name, char **encodingA, CharCodeToUnicode *toUnicode, GBool pdfFontHasEncoding, + GBool pdfFontIsSymbolic, FontFileOutputFunc outputFunc, void *outputStream); // Convert to a Type 2 CIDFont, suitable for embedding in a @@ -217,7 +225,7 @@ private: void cvtEncoding(char **encodingA, GBool pdfFontHasEncoding, FontFileOutputFunc outputFunc, void *outputStream); void cvtCharStrings(char **encodingA, CharCodeToUnicode *toUnicode, - GBool pdfFontHasEncoding, + GBool pdfFontHasEncoding, GBool pdfFontIsSymbolic, FontFileOutputFunc outputFunc, void *outputStream); int getCmapEntry(int cmapFmt, int pos, int code); void cvtSfnts(FontFileOutputFunc outputFunc, void *outputStream, diff --git a/pdf/xpdf/Function.cc b/pdf/xpdf/Function.cc index cafb63f..28eed87 100644 --- a/pdf/xpdf/Function.cc +++ b/pdf/xpdf/Function.cc @@ -2,7 +2,7 @@ // // Function.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -413,7 +413,6 @@ void SampledFunction::transform(double *in, double *out) { ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { Object obj1, obj2; - GBool hasN; int i; ok = gFalse; @@ -426,23 +425,14 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { error(-1, "Exponential function with more than one input"); goto err1; } - hasN = hasRange; - - //----- default values - for (i = 0; i < funcMaxOutputs; ++i) { - c0[i] = 0; - c1[i] = 1; - } //----- C0 if (dict->lookup("C0", &obj1)->isArray()) { - if (!hasN) { - n = obj1.arrayGetLength(); - hasN = gTrue; - } else if (obj1.arrayGetLength() != n) { + if (hasRange && obj1.arrayGetLength() != n) { error(-1, "Function's C0 array is wrong length"); goto err2; } + n = obj1.arrayGetLength(); for (i = 0; i < n; ++i) { obj1.arrayGet(i, &obj2); if (!obj2.isNum()) { @@ -452,15 +442,19 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { c0[i] = obj2.getNum(); obj2.free(); } + } else { + if (hasRange && n != 1) { + error(-1, "Function's C0 array is wrong length"); + goto err2; + } + n = 1; + c0[0] = 0; } obj1.free(); //----- C1 if (dict->lookup("C1", &obj1)->isArray()) { - if (!hasN) { - n = obj1.arrayGetLength(); - hasN = gTrue; - } else if (obj1.arrayGetLength() != n) { + if (obj1.arrayGetLength() != n) { error(-1, "Function's C1 array is wrong length"); goto err2; } @@ -473,6 +467,12 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { c1[i] = obj2.getNum(); obj2.free(); } + } else { + if (n != 1) { + error(-1, "Function's C1 array is wrong length"); + goto err2; + } + c1[0] = 1; } obj1.free(); @@ -484,13 +484,6 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { e = obj1.getNum(); obj1.free(); - // this isn't supposed to happen, but I've run into (broken) PDF - // files where it does - if (!hasN) { - error(-1, "Exponential function does not define number of output values"); - n = 1; - } - ok = gTrue; return; diff --git a/pdf/xpdf/Function.h b/pdf/xpdf/Function.h index eb88211..d795a51 100644 --- a/pdf/xpdf/Function.h +++ b/pdf/xpdf/Function.h @@ -2,7 +2,7 @@ // // Function.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Gfx.cc b/pdf/xpdf/Gfx.cc index 21136b1..63896d8 100644 --- a/pdf/xpdf/Gfx.cc +++ b/pdf/xpdf/Gfx.cc @@ -2,7 +2,7 @@ // // Gfx.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Gfx.h b/pdf/xpdf/Gfx.h index c3c57cf..c7aef11 100644 --- a/pdf/xpdf/Gfx.h +++ b/pdf/xpdf/Gfx.h @@ -2,7 +2,7 @@ // // Gfx.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/GfxFont.cc b/pdf/xpdf/GfxFont.cc index b3b6a71..d687588 100644 --- a/pdf/xpdf/GfxFont.cc +++ b/pdf/xpdf/GfxFont.cc @@ -2,7 +2,7 @@ // // GfxFont.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -35,6 +35,11 @@ struct StdFontMapEntry { char *properName; }; +// Acrobat 4.0 and earlier substituted Base14-compatible fonts without +// providing Widths and a FontDescriptor, so we munge the names into +// the proper Base14 names. This table is from implementation note 44 +// in the PDF 1.4 spec, with some additions based on empirical +// evidence. static StdFontMapEntry stdFontMap[] = { { "Arial", "Helvetica" }, { "Arial,Bold", "Helvetica-Bold" }, @@ -304,11 +309,14 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits) { } void GfxFont::findExtFontFile() { + static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL }; + static char *ttExts[] = { ".ttf", NULL }; + if (name) { if (type == fontType1) { - extFontFile = globalParams->findFontFile(name, ".pfa", ".pfb"); + extFontFile = globalParams->findFontFile(name, type1Exts); } else if (type == fontTrueType) { - extFontFile = globalParams->findFontFile(name, ".ttf", NULL); + extFontFile = globalParams->findFontFile(name, ttExts); } } } @@ -396,10 +404,8 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, type = typeA; ctu = NULL; - // Acrobat 4.0 and earlier substituted Base14-compatible fonts - // without providing Widths and a FontDescriptor, so we munge the - // names into the proper Base14 names. (This table is from - // implementation note 44 in the PDF 1.4 spec.) + // do font name substitution for various aliases of the Base 14 font + // names if (name) { a = 0; b = sizeof(stdFontMap) / sizeof(StdFontMapEntry); @@ -553,14 +559,18 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, fontFile = new Type1FontFile(buf, len); } else { fontFile = new Type1CFontFile(buf, len); + if (!((Type1CFontFile *)fontFile)->isOk()) { + delete fontFile; + fontFile = NULL; + } } - if (fontFile->getName()) { + if (fontFile && fontFile->getName()) { if (embFontName) { delete embFontName; } embFontName = new GString(fontFile->getName()); } - if (!baseEnc) { + if (fontFile && !baseEnc) { baseEnc = fontFile->getEncoding(); baseEncFromFontFile = gTrue; } @@ -713,6 +723,9 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, fontDict->lookup("Widths", &obj1); if (obj1.isArray()) { flags |= fontFixedWidth; + if (obj1.arrayGetLength() < lastChar - firstChar + 1) { + lastChar = firstChar + obj1.arrayGetLength() - 1; + } for (code = firstChar; code <= lastChar; ++code) { obj1.arrayGet(code - firstChar, &obj2); if (obj2.isNum()) { @@ -827,12 +840,12 @@ Dict *Gfx8BitFont::getResources() { // GfxCIDFont //------------------------------------------------------------------------ -static int cmpWidthExcep(const void *w1, const void *w2) { +static int CDECL cmpWidthExcep(const void *w1, const void *w2) { return ((GfxFontCIDWidthExcep *)w1)->first - ((GfxFontCIDWidthExcep *)w2)->first; } -static int cmpWidthExcepV(const void *w1, const void *w2) { +static int CDECL cmpWidthExcepV(const void *w1, const void *w2) { return ((GfxFontCIDWidthExcepV *)w1)->first - ((GfxFontCIDWidthExcepV *)w2)->first; } diff --git a/pdf/xpdf/GfxFont.h b/pdf/xpdf/GfxFont.h index bcabe5f..23371b3 100644 --- a/pdf/xpdf/GfxFont.h +++ b/pdf/xpdf/GfxFont.h @@ -2,7 +2,7 @@ // // GfxFont.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/GfxState.cc b/pdf/xpdf/GfxState.cc index a978b50..7efd0b9 100644 --- a/pdf/xpdf/GfxState.cc +++ b/pdf/xpdf/GfxState.cc @@ -2,7 +2,7 @@ // // GfxState.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/GfxState.h b/pdf/xpdf/GfxState.h index cfe8f9b..a0b1d14 100644 --- a/pdf/xpdf/GfxState.h +++ b/pdf/xpdf/GfxState.h @@ -2,7 +2,7 @@ // // GfxState.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/GlobalParams.cc b/pdf/xpdf/GlobalParams.cc index ded583f..c5083b2 100644 --- a/pdf/xpdf/GlobalParams.cc +++ b/pdf/xpdf/GlobalParams.cc @@ -2,7 +2,7 @@ // // GlobalParams.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -353,6 +353,12 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { } else if (!cmd->cmp("displayCIDFontT1")) { parseDisplayFont(tokens, displayCIDFonts, displayFontT1, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontTT")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontTT, fileName, line); + } else if (!cmd->cmp("displayCIDFontTT")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontTT, fileName, line); } else if (!cmd->cmp("psFile")) { parsePSFile(tokens, fileName, line); } else if (!cmd->cmp("psFont")) { @@ -1061,26 +1067,17 @@ GBool GlobalParams::getTextKeepTinyChars() { return tiny; } -GString *GlobalParams::findFontFile(GString *fontName, - char *ext1, char *ext2) { +GString *GlobalParams::findFontFile(GString *fontName, char **exts) { GString *dir, *fileName; + char **ext; FILE *f; int i; for (i = 0; i < fontDirs->getLength(); ++i) { dir = (GString *)fontDirs->get(i); - if (ext1) { - fileName = appendToPath(dir->copy(), fontName->getCString()); - fileName->append(ext1); - if ((f = fopen(fileName->getCString(), "r"))) { - fclose(f); - return fileName; - } - delete fileName; - } - if (ext2) { + for (ext = exts; *ext; ++ext) { fileName = appendToPath(dir->copy(), fontName->getCString()); - fileName->append(ext2); + fileName->append(*ext); if ((f = fopen(fileName->getCString(), "r"))) { fclose(f); return fileName; @@ -1218,7 +1215,9 @@ void GlobalParams::setPSFile(char *file) { GBool GlobalParams::setPSPaperSize(char *size) { globalParamsLock; - if (!strcmp(size, "letter")) { + if (!strcmp(size, "match")) { + psPaperWidth = psPaperHeight = -1; + } else if (!strcmp(size, "letter")) { psPaperWidth = 612; psPaperHeight = 792; } else if (!strcmp(size, "legal")) { diff --git a/pdf/xpdf/GlobalParams.h b/pdf/xpdf/GlobalParams.h index 5fb3be3..dee9e25 100644 --- a/pdf/xpdf/GlobalParams.h +++ b/pdf/xpdf/GlobalParams.h @@ -2,7 +2,7 @@ // // GlobalParams.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -156,7 +156,7 @@ public: GBool getPSASCIIHex(); EndOfLineKind getTextEOL(); GBool getTextKeepTinyChars(); - GString *findFontFile(GString *fontName, char *ext1, char *ext2); + GString *findFontFile(GString *fontName, char **exts); GString *getInitialZoom(); FontRastControl getT1libControl(); FontRastControl getFreeTypeControl(); diff --git a/pdf/xpdf/ImageOutputDev.cc b/pdf/xpdf/ImageOutputDev.cc index 1a6d87e..29c7f0f 100644 --- a/pdf/xpdf/ImageOutputDev.cc +++ b/pdf/xpdf/ImageOutputDev.cc @@ -2,7 +2,7 @@ // // ImageOutputDev.cc // -// Copyright 1998-2002 Glyph & Cog, LLC +// Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/ImageOutputDev.h b/pdf/xpdf/ImageOutputDev.h index c3eb36e..73f2f15 100644 --- a/pdf/xpdf/ImageOutputDev.h +++ b/pdf/xpdf/ImageOutputDev.h @@ -2,7 +2,7 @@ // // ImageOutputDev.h // -// Copyright 1998-2002 Glyph & Cog, LLC +// Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Lexer.cc b/pdf/xpdf/Lexer.cc index 982295e..1fa166f 100644 --- a/pdf/xpdf/Lexer.cc +++ b/pdf/xpdf/Lexer.cc @@ -2,7 +2,7 @@ // // Lexer.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Lexer.h b/pdf/xpdf/Lexer.h index 2dfe314..398d27c 100644 --- a/pdf/xpdf/Lexer.h +++ b/pdf/xpdf/Lexer.h @@ -2,7 +2,7 @@ // // Lexer.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Link.cc b/pdf/xpdf/Link.cc index 0c3a869..39b7ceb 100644 --- a/pdf/xpdf/Link.cc +++ b/pdf/xpdf/Link.cc @@ -2,7 +2,7 @@ // // Link.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -148,7 +148,7 @@ LinkDest::LinkDest(Array *a) { // get page if (a->getLength() < 2) { - error(-1, "Annotation destination array has wrong length"); + error(-1, "Annotation destination array is too short"); return; } a->getNF(0, &obj1); @@ -219,16 +219,16 @@ LinkDest::LinkDest(Array *a) { // Fit link } else if (obj1.isName("Fit")) { - if (a->getLength() != 2) { - error(-1, "Annotation destination array has wrong length"); + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); goto err2; } kind = destFit; // FitH link } else if (obj1.isName("FitH")) { - if (a->getLength() != 3) { - error(-1, "Annotation destination array has wrong length"); + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); goto err2; } kind = destFitH; @@ -241,8 +241,8 @@ LinkDest::LinkDest(Array *a) { // FitV link } else if (obj1.isName("FitV")) { - if (a->getLength() != 3) { - error(-1, "Annotation destination array has wrong length"); + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); goto err2; } kind = destFitV; @@ -255,8 +255,8 @@ LinkDest::LinkDest(Array *a) { // FitR link } else if (obj1.isName("FitR")) { - if (a->getLength() != 6) { - error(-1, "Annotation destination array has wrong length"); + if (a->getLength() < 6) { + error(-1, "Annotation destination array is too short"); goto err2; } kind = destFitR; @@ -287,16 +287,16 @@ LinkDest::LinkDest(Array *a) { // FitB link } else if (obj1.isName("FitB")) { - if (a->getLength() != 2) { - error(-1, "Annotation destination array has wrong length"); + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); goto err2; } kind = destFitB; // FitBH link } else if (obj1.isName("FitBH")) { - if (a->getLength() != 3) { - error(-1, "Annotation destination array has wrong length"); + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); goto err2; } kind = destFitBH; @@ -309,8 +309,8 @@ LinkDest::LinkDest(Array *a) { // FitBV link } else if (obj1.isName("FitBV")) { - if (a->getLength() != 3) { - error(-1, "Annotation destination array has wrong length"); + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); goto err2; } kind = destFitBV; diff --git a/pdf/xpdf/Link.h b/pdf/xpdf/Link.h index e19c3c0..20ed450 100644 --- a/pdf/xpdf/Link.h +++ b/pdf/xpdf/Link.h @@ -2,7 +2,7 @@ // // Link.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/NameToCharCode.cc b/pdf/xpdf/NameToCharCode.cc index 29a1dbb..8f22a90 100644 --- a/pdf/xpdf/NameToCharCode.cc +++ b/pdf/xpdf/NameToCharCode.cc @@ -2,7 +2,7 @@ // // NameToCharCode.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/NameToCharCode.h b/pdf/xpdf/NameToCharCode.h index 622e7d6..65453c3 100644 --- a/pdf/xpdf/NameToCharCode.h +++ b/pdf/xpdf/NameToCharCode.h @@ -2,7 +2,7 @@ // // NameToCharCode.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/NameToUnicodeTable.h b/pdf/xpdf/NameToUnicodeTable.h index 99bcf1d..4f28fff 100644 --- a/pdf/xpdf/NameToUnicodeTable.h +++ b/pdf/xpdf/NameToUnicodeTable.h @@ -2,7 +2,7 @@ // // NameToUnicodeTable.h // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Object.cc b/pdf/xpdf/Object.cc index a1c71af..b0976fd 100644 --- a/pdf/xpdf/Object.cc +++ b/pdf/xpdf/Object.cc @@ -2,7 +2,7 @@ // // Object.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Object.h b/pdf/xpdf/Object.h index d8a5fb5..8f0b370 100644 --- a/pdf/xpdf/Object.h +++ b/pdf/xpdf/Object.h @@ -2,7 +2,7 @@ // // Object.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/OutputDev.cc b/pdf/xpdf/OutputDev.cc index 15e6a86..cbb5df5 100644 --- a/pdf/xpdf/OutputDev.cc +++ b/pdf/xpdf/OutputDev.cc @@ -2,7 +2,7 @@ // // OutputDev.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -38,7 +38,7 @@ void OutputDev::setDefaultCTM(double *ctm) { defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det; } -void OutputDev::cvtDevToUser(int dx, int dy, double *ux, double *uy) { +void OutputDev::cvtDevToUser(double dx, double dy, double *ux, double *uy) { *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4]; *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5]; } diff --git a/pdf/xpdf/OutputDev.h b/pdf/xpdf/OutputDev.h index 995c7e7..f050c03 100644 --- a/pdf/xpdf/OutputDev.h +++ b/pdf/xpdf/OutputDev.h @@ -2,7 +2,7 @@ // // OutputDev.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -73,7 +73,7 @@ public: //----- coordinate conversion // Convert between device and user coordinates. - virtual void cvtDevToUser(int dx, int dy, double *ux, double *uy); + virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy); virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy); //----- link borders diff --git a/pdf/xpdf/PBMOutputDev.cc b/pdf/xpdf/PBMOutputDev.cc index 3443299..dde860a 100644 --- a/pdf/xpdf/PBMOutputDev.cc +++ b/pdf/xpdf/PBMOutputDev.cc @@ -2,7 +2,7 @@ // // PBMOutputDev.cc // -// Copyright 1998-2002 Glyph & Cog, LLC +// Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/PBMOutputDev.h b/pdf/xpdf/PBMOutputDev.h index 6926ce0..9d1539d 100644 --- a/pdf/xpdf/PBMOutputDev.h +++ b/pdf/xpdf/PBMOutputDev.h @@ -2,7 +2,7 @@ // // PBMOutputDev.h // -// Copyright 1998-2002 Glyph & Cog, LLC +// Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/PDFDoc.cc b/pdf/xpdf/PDFDoc.cc index ff6cefa..3df9472 100644 --- a/pdf/xpdf/PDFDoc.cc +++ b/pdf/xpdf/PDFDoc.cc @@ -2,7 +2,7 @@ // // PDFDoc.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/PDFDoc.h b/pdf/xpdf/PDFDoc.h index ff6e359..99832f8 100644 --- a/pdf/xpdf/PDFDoc.h +++ b/pdf/xpdf/PDFDoc.h @@ -2,7 +2,7 @@ // // PDFDoc.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/PSOutputDev.cc b/pdf/xpdf/PSOutputDev.cc index 9844ab3..7bef193 100644 --- a/pdf/xpdf/PSOutputDev.cc +++ b/pdf/xpdf/PSOutputDev.cc @@ -2,7 +2,7 @@ // // PSOutputDev.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -18,6 +18,7 @@ #include #include #include "GString.h" +#include "GList.h" #include "config.h" #include "GlobalParams.h" #include "Object.h" @@ -100,7 +101,7 @@ static char *prolog[] = { " /customcolorimage {", " gsave", " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", - " 0 4 getinterval cvx", + " 0 4 getinterval", " [ exch /dup load exch { mul exch dup } /forall load", " /pop load dup ] cvx", " ] setcolorspace", @@ -328,11 +329,15 @@ static char *prolog[] = { "/pdfImSep {", " findcmykcustomcolor exch", " dup /Width get /pdfImBuf1 exch string def", + " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def", + " /pdfImDecodeLow exch def", " begin Width Height BitsPerComponent ImageMatrix DataSource end", " /pdfImData exch def", " { pdfImData pdfImBuf1 readstring pop", " 0 1 2 index length 1 sub {", - " 1 index exch 2 copy get 255 exch sub put", + " 1 index exch 2 copy get", + " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi", + " 255 exch sub put", " } for }", " 6 5 roll customcolorimage", " { currentfile pdfImBuf readline", @@ -503,6 +508,7 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, fontFileIDs = NULL; fontFileNames = NULL; font16Enc = NULL; + xobjStack = NULL; embFontList = NULL; customColors = NULL; t3String = NULL; @@ -547,6 +553,7 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, fontFileIDs = NULL; fontFileNames = NULL; font16Enc = NULL; + xobjStack = NULL; embFontList = NULL; customColors = NULL; t3String = NULL; @@ -577,6 +584,11 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, mode = modeA; paperWidth = globalParams->getPSPaperWidth(); paperHeight = globalParams->getPSPaperHeight(); + if (paperWidth < 0 || paperHeight < 0) { + page = catalog->getPage(firstPage); + paperWidth = (int)(page->getWidth() + 0.5); + paperHeight = (int)(page->getHeight() + 0.5); + } if (mode == psModeForm) { lastPage = firstPage; } @@ -601,6 +613,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *)); font16EncLen = 0; font16EncSize = 0; + xobjStack = new GList(); // initialize embedded font resource comment list embFontList = new GString(); @@ -813,6 +826,9 @@ PSOutputDev::~PSOutputDev() { } gfree(font16Enc); } + if (xobjStack) { + delete xobjStack; + } while (customColors) { cc = customColors; customColors = cc->next; @@ -821,8 +837,10 @@ PSOutputDev::~PSOutputDev() { } void PSOutputDev::setupResources(Dict *resDict) { - Object xObjDict, xObj, resObj; - int i; + Object xObjDict, xObjRef, xObj, resObj; + Ref ref0, ref1; + GBool skip; + int i, j; setupFonts(resDict); setupImages(resDict); @@ -830,15 +848,40 @@ void PSOutputDev::setupResources(Dict *resDict) { resDict->lookup("XObject", &xObjDict); if (xObjDict.isDict()) { for (i = 0; i < xObjDict.dictGetLength(); ++i) { - xObjDict.dictGetVal(i, &xObj); - if (xObj.isStream()) { - xObj.streamGetDict()->lookup("Resources", &resObj); - if (resObj.isDict()) { - setupResources(resObj.getDict()); + + // avoid infinite recursion on XObjects + skip = gFalse; + if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) { + ref0 = xObjRef.getRef(); + for (j = 0; j < xobjStack->getLength(); ++j) { + ref1 = *(Ref *)xobjStack->get(j); + if (ref1.num == ref0.num && ref1.gen == ref0.gen) { + skip = gTrue; + break; + } + } + if (!skip) { + xobjStack->append(&ref0); } - resObj.free(); } - xObj.free(); + if (!skip) { + + // process the XObject's resource dictionary + xObjDict.dictGetVal(i, &xObj); + if (xObj.isStream()) { + xObj.streamGetDict()->lookup("Resources", &resObj); + if (resObj.isDict()) { + setupResources(resObj.getDict()); + } + resObj.free(); + } + xObj.free(); + } + + if (xObjRef.isRef() && !skip) { + xobjStack->del(xobjStack->getLength() - 1); + } + xObjRef.free(); } } xObjDict.free(); @@ -869,6 +912,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { GString *psNameStr; char *psName; char type3Name[64], buf[16]; + GBool subst; UnicodeMap *uMap; char *charName; double xs, ys; @@ -894,6 +938,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { xs = ys = 1; psNameStr = NULL; + subst = gFalse; // check for resident 8-bit font if (font->getName() && @@ -964,6 +1009,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { // do 8-bit font substitution } else if (!font->isCIDFont()) { + subst = gTrue; name = font->getName(); psName = NULL; if (name) { @@ -1025,6 +1071,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { getPSFont16(font->getName(), ((GfxCIDFont *)font)->getCollection(), font->getWMode()))) { + subst = gTrue; psName = fontParam->psFontName->getCString(); if (font16EncLen >= font16EncSize) { font16EncSize += 16; @@ -1069,6 +1116,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { writePSFmt((i == 0) ? "[ " : " "); for (j = 0; j < 8; ++j) { if (font->getType() == fontTrueType && + !subst && !((Gfx8BitFont *)font)->getHasEncoding()) { sprintf(buf, "c%02x", i+j); charName = buf; @@ -1288,7 +1336,9 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, // convert it to a Type 1 font fontBuf = font->readEmbFontFile(xref, &fontLen); t1cFile = new Type1CFontFile(fontBuf, fontLen); - t1cFile->convertToType1(outputFunc, outputStream); + if (t1cFile->isOk()) { + t1cFile->convertToType1(outputFunc, outputStream); + } delete t1cFile; gfree(fontBuf); @@ -1330,6 +1380,7 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, ctu = ((Gfx8BitFont *)font)->getToUnicode(); ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(), ctu, ((Gfx8BitFont *)font)->getHasEncoding(), + ((Gfx8BitFont *)font)->isSymbolic(), outputFunc, outputStream); ctu->decRefCnt(); delete ttFile; @@ -1375,6 +1426,7 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) { ctu = ((Gfx8BitFont *)font)->getToUnicode(); ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(), ctu, ((Gfx8BitFont *)font)->getHasEncoding(), + ((Gfx8BitFont *)font)->isSymbolic(), outputFunc, outputStream); ctu->decRefCnt(); delete ttFile; @@ -1414,12 +1466,14 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, // convert it to a Type 0 font fontBuf = font->readEmbFontFile(xref, &fontLen); t1cFile = new Type1CFontFile(fontBuf, fontLen); - if (globalParams->getPSLevel() >= psLevel3) { - // Level 3: use a CID font - t1cFile->convertToCIDType0(psName, outputFunc, outputStream); - } else { - // otherwise: use a non-CID composite font - t1cFile->convertToType0(psName, outputFunc, outputStream); + if (t1cFile->isOk()) { + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + t1cFile->convertToCIDType0(psName, outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + t1cFile->convertToType0(psName, outputFunc, outputStream); + } } delete t1cFile; gfree(fontBuf); @@ -3309,6 +3363,15 @@ GString *PSOutputDev::filterPSName(GString *name) { char c; name2 = new GString(); + + // ghostscript chokes on names that begin with out-of-limits + // numbers, e.g., 1e4foo is handled correctly (as a name), but + // 1e999foo generates a limitcheck error + c = name->getChar(0); + if (c >= '0' && c <= '9') { + name2->append('f'); + } + for (i = 0; i < name->getLength(); ++i) { c = name->getChar(i); if (c <= (char)0x20 || c >= (char)0x7f || diff --git a/pdf/xpdf/PSOutputDev.h b/pdf/xpdf/PSOutputDev.h index fbfc3a5..f7896cc 100644 --- a/pdf/xpdf/PSOutputDev.h +++ b/pdf/xpdf/PSOutputDev.h @@ -2,7 +2,7 @@ // // PSOutputDev.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -217,6 +217,8 @@ private: PSFont16Enc *font16Enc; // encodings for substitute 16-bit fonts int font16EncLen; // number of entries in font16Enc array int font16EncSize; // size of font16Enc array + GList *xobjStack; // stack of XObject dicts currently being + // processed double tx, ty; // global translation double xScale, yScale; // global scaling diff --git a/pdf/xpdf/PSTokenizer.cc b/pdf/xpdf/PSTokenizer.cc index 570a7ba..a65c324 100644 --- a/pdf/xpdf/PSTokenizer.cc +++ b/pdf/xpdf/PSTokenizer.cc @@ -2,7 +2,7 @@ // // PSTokenizer.cc // -// Copyright 2002 Glyph & Cog, LLC +// Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/PSTokenizer.h b/pdf/xpdf/PSTokenizer.h index c885ae1..4d5ee97 100644 --- a/pdf/xpdf/PSTokenizer.h +++ b/pdf/xpdf/PSTokenizer.h @@ -2,7 +2,7 @@ // // PSTokenizer.h // -// Copyright 2002 Glyph & Cog, LLC +// Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Page.cc b/pdf/xpdf/Page.cc index 72b4a8e..3f6bc09 100644 --- a/pdf/xpdf/Page.cc +++ b/pdf/xpdf/Page.cc @@ -2,7 +2,7 @@ // // Page.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Page.h b/pdf/xpdf/Page.h index 911c5b0..cb8706b 100644 --- a/pdf/xpdf/Page.h +++ b/pdf/xpdf/Page.h @@ -2,7 +2,7 @@ // // Page.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Parser.cc b/pdf/xpdf/Parser.cc index 4bcb0ce..deb894a 100644 --- a/pdf/xpdf/Parser.cc +++ b/pdf/xpdf/Parser.cc @@ -2,7 +2,7 @@ // // Parser.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Parser.h b/pdf/xpdf/Parser.h index 7b7a812..3bc3ab2 100644 --- a/pdf/xpdf/Parser.h +++ b/pdf/xpdf/Parser.h @@ -2,7 +2,7 @@ // // Parser.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/SFont.cc b/pdf/xpdf/SFont.cc index 53214b0..1f421dd 100644 --- a/pdf/xpdf/SFont.cc +++ b/pdf/xpdf/SFont.cc @@ -2,7 +2,7 @@ // // SFont.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/SFont.h b/pdf/xpdf/SFont.h index 8481dda..aadf991 100644 --- a/pdf/xpdf/SFont.h +++ b/pdf/xpdf/SFont.h @@ -4,7 +4,7 @@ // // Base class for font rasterizers. // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Stream-CCITT.h b/pdf/xpdf/Stream-CCITT.h index f5a77b0..c4458fe 100644 --- a/pdf/xpdf/Stream-CCITT.h +++ b/pdf/xpdf/Stream-CCITT.h @@ -4,7 +4,7 @@ // // Tables for CCITT Fax decoding. // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/Stream.cc b/pdf/xpdf/Stream.cc index b2abef8..11b51b6 100644 --- a/pdf/xpdf/Stream.cc +++ b/pdf/xpdf/Stream.cc @@ -2,7 +2,7 @@ // // Stream.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -2141,7 +2141,7 @@ GBool DCTStream::readMCURow() { // Read one scan from a progressive or non-interleaved JPEG stream. void DCTStream::readScan() { int data[64]; - int x1, y1, dy1, x2, y2, y3, cc, i; + int x1, y1, dx1, dy1, x2, y2, y3, cc, i; int h, v, horiz, vert, hSub, vSub; int *p1; int c; @@ -2152,13 +2152,15 @@ void DCTStream::readScan() { break; } } + dx1 = mcuWidth / compInfo[cc].hSample; dy1 = mcuHeight / compInfo[cc].vSample; } else { + dx1 = mcuWidth; dy1 = mcuHeight; } - for (y1 = 0; y1 < bufHeight; y1 += dy1) { - for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { + for (y1 = 0; y1 < height; y1 += dy1) { + for (x1 = 0; x1 < width; x1 += dx1) { // deal with restart marker if (restartInterval > 0 && restartCtr == 0) { @@ -2186,7 +2188,7 @@ void DCTStream::readScan() { hSub = horiz / 8; vSub = vert / 8; for (y2 = 0; y2 < dy1; y2 += vert) { - for (x2 = 0; x2 < mcuWidth; x2 += horiz) { + for (x2 = 0; x2 < dx1; x2 += horiz) { // pull out the current values p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; @@ -2282,8 +2284,10 @@ GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, return gFalse; } i += run; - j = dctZigZag[i++]; - data[j] = amp; + if (i < 64) { + j = dctZigZag[i++]; + data[j] = amp; + } } } return gTrue; @@ -2369,7 +2373,7 @@ GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, eobRun = 0; for (k = 0; k < j; ++k) { if ((bit = readBit()) == EOF) { - return 9999; + return gFalse; } eobRun = (eobRun << 1) | bit; } @@ -3446,6 +3450,8 @@ GBool FlateStream::readDynamicCodes() { int len, repeat, code; int i; + codeLenCodeTab.codes = NULL; + // read lengths if ((numLitCodes = getCodeWord(5)) == EOF) { goto err; @@ -3488,23 +3494,35 @@ GBool FlateStream::readDynamicCodes() { if ((repeat = getCodeWord(2)) == EOF) { goto err; } - for (repeat += 3; repeat > 0; --repeat) { + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } + for (; repeat > 0; --repeat) { codeLengths[i++] = len; } } else if (code == 17) { if ((repeat = getCodeWord(3)) == EOF) { goto err; } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } len = 0; - for (repeat += 3; repeat > 0; --repeat) { + for (; repeat > 0; --repeat) { codeLengths[i++] = 0; } } else if (code == 18) { if ((repeat = getCodeWord(7)) == EOF) { goto err; } + repeat += 11; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } len = 0; - for (repeat += 11; repeat > 0; --repeat) { + for (; repeat > 0; --repeat) { codeLengths[i++] = 0; } } else { diff --git a/pdf/xpdf/Stream.h b/pdf/xpdf/Stream.h index b0a0c26..31c0a97 100644 --- a/pdf/xpdf/Stream.h +++ b/pdf/xpdf/Stream.h @@ -2,7 +2,7 @@ // // Stream.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/T1Font.cc b/pdf/xpdf/T1Font.cc index 9815e49..a03351d 100644 --- a/pdf/xpdf/T1Font.cc +++ b/pdf/xpdf/T1Font.cc @@ -2,7 +2,7 @@ // // T1Font.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -301,7 +301,9 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, XColor xcolor; int bgR, bgG, bgB; Gulong colors[17]; - Guchar *p; + Guchar *bitmap, *p; + GBool tempBitmap; + XImage *img; int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0; int xx, yy, xx1; Guchar pix, mPix; @@ -310,7 +312,8 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, engine = fontFile->engine; // generate the glyph pixmap - if (!(p = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh))) { + if (!(bitmap = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh, + &tempBitmap))) { return gFalse; } @@ -332,7 +335,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, w0 = w - x0; } if (w0 < 0) { - return gTrue; + goto done; } if (y0 < 0) { y1 = -y0; @@ -343,17 +346,29 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, h0 = h - y0; } if (h0 < 0) { - return gTrue; + goto done; + } + + // getGlyphPixmap may have returned a larger-than-cache-entry + // bitmap, in which case we need to allocate a temporary XImage here + if (tempBitmap) { + if (!(img = XCreateImage(engine->display, engine->visual, engine->depth, + ZPixmap, 0, NULL, gw, gh, 8, 0))) { + goto done; + } + img->data = (char *)gmalloc(gh * img->bytes_per_line); + } else { + img = image; } // read the X image XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1, - ZPixmap, image, x1, y1); + ZPixmap, img, x1, y1); if (engine->aa) { // compute the colors - xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2); + xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2); XQueryColor(engine->display, engine->colormap, &xcolor); bgR = xcolor.red; bgG = xcolor.green; @@ -380,6 +395,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, } // stuff the glyph pixmap into the X image + p = bitmap; for (yy = 0; yy < gh; ++yy) { for (xx = 0; xx < gw; ++xx) { pix = *p++; @@ -387,7 +403,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, if (pix > mPix) { pix = mPix; } - XPutPixel(image, xx, yy, colors[pix]); + XPutPixel(img, xx, yy, colors[pix]); } } } @@ -398,12 +414,13 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, colors[1] = engine->findColor(r, g, b); // stuff the glyph bitmap into the X image + p = bitmap; for (yy = 0; yy < gh; ++yy) { for (xx = 0; xx < gw; xx += 8) { pix = *p++; for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) { if (pix & 0x01) { - XPutPixel(image, xx1, yy, colors[1]); + XPutPixel(img, xx1, yy, colors[1]); } pix >>= 1; } @@ -413,12 +430,22 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, } // draw the X image - XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0); + XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0); + if (tempBitmap) { + gfree(img->data); + img->data = NULL; + XDestroyImage(img); + } + done: + if (tempBitmap) { + gfree(bitmap); + } return gTrue; } -Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h) { +Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h, + GBool *tempBitmap) { T1FontEngine *engine; GLYPH *glyph; int gSize; @@ -442,6 +469,7 @@ Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h) { } } cacheTags[i+j].mru = 0x8000; + *tempBitmap = gFalse; return cache + (i+j) * glyphSize; } } @@ -455,42 +483,45 @@ Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h) { if (!glyph) { return NULL; } + + // copy the glyph into the cache or a temporary bitmap *x = -glyph->metrics.leftSideBearing; *y = glyph->metrics.ascent; *w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing; *h = glyph->metrics.ascent - glyph->metrics.descent; - if (*w > glyphW || *h > glyphH) { -#if 1 //~ debug - fprintf(stderr, "Weird t1lib glyph size: %d > %d or %d > %d\n", - *w, glyphW, *h, glyphH); -#endif - return NULL; + if (engine->aa) { + gSize = *w * *h; + } else { + gSize = ((*w + 7) >> 3) * *h; } - - // store glyph pixmap in cache - ret = NULL; - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { - cacheTags[i+j].mru = 0x8000; - cacheTags[i+j].code = c; - cacheTags[i+j].x = *x; - cacheTags[i+j].y = *y; - cacheTags[i+j].w = *w; - cacheTags[i+j].h = *h; - if (engine->aa) { - gSize = *w * *h; - } else { - gSize = ((*w + 7) >> 3) * *h; - } - ret = cache + (i+j) * glyphSize; - if (glyph->bits) { - memcpy(ret, glyph->bits, gSize); + if (*w > glyphW || *h > glyphH) { + // the glyph doesn't fit in the bounding box -- return a + // temporary, uncached bitmap (this shouldn't happen but some + // fonts have incorrect bboxes) + ret = (Guchar *)gmalloc(gSize); + *tempBitmap = gTrue; + } else { + // store glyph pixmap in cache + ret = NULL; // make gcc happy + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { + cacheTags[i+j].mru = 0x8000; + cacheTags[i+j].code = c; + cacheTags[i+j].x = *x; + cacheTags[i+j].y = *y; + cacheTags[i+j].w = *w; + cacheTags[i+j].h = *h; + ret = cache + (i+j) * glyphSize; } else { - memset(ret, 0, gSize); + ++cacheTags[i+j].mru; } - } else { - ++cacheTags[i+j].mru; } + *tempBitmap = gFalse; + } + if (glyph->bits) { + memcpy(ret, glyph->bits, gSize); + } else { + memset(ret, 0, gSize); } return ret; } diff --git a/pdf/xpdf/T1Font.h b/pdf/xpdf/T1Font.h index cfd7f62..416f533 100644 --- a/pdf/xpdf/T1Font.h +++ b/pdf/xpdf/T1Font.h @@ -4,7 +4,7 @@ // // An X wrapper for the t1lib Type 1 font rasterizer. // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -90,7 +90,8 @@ public: private: - Guchar *getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h); + Guchar *getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h, + GBool *tempBitmap); T1FontFile *fontFile; int id; diff --git a/pdf/xpdf/TTFont.cc b/pdf/xpdf/TTFont.cc index 6107fd4..fc6d849 100644 --- a/pdf/xpdf/TTFont.cc +++ b/pdf/xpdf/TTFont.cc @@ -2,7 +2,7 @@ // // TTFont.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== @@ -80,7 +80,7 @@ TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName, unicodeCmap = macRomanCmap = msSymbolCmap = 0xffff; for (i = 0; i < props.num_CharMaps; ++i) { if (!TT_Get_CharMap_ID(face, i, &platform, &encoding)) { - if (platform == 3 && encoding == 1) { + if ((platform == 3 && encoding == 1) || platform == 0) { unicodeCmap = i; } else if (platform == 1 && encoding == 0) { macRomanCmap = i; diff --git a/pdf/xpdf/TTFont.h b/pdf/xpdf/TTFont.h index 997076c..96208e2 100644 --- a/pdf/xpdf/TTFont.h +++ b/pdf/xpdf/TTFont.h @@ -4,7 +4,7 @@ // // An X wrapper for the FreeType TrueType font rasterizer. // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/TextOutputDev.cc b/pdf/xpdf/TextOutputDev.cc index b782b42..3fcc9ec 100644 --- a/pdf/xpdf/TextOutputDev.cc +++ b/pdf/xpdf/TextOutputDev.cc @@ -2,7 +2,7 @@ // // TextOutputDev.cc // -// Copyright 1997-2002 Glyph & Cog, LLC +// Copyright 1997-2003 Glyph & Cog, LLC // //======================================================================== @@ -17,6 +17,10 @@ #include #include #include +#ifdef WIN32 +#include // for O_BINARY +#include // for setmode +#endif #include "gmem.h" #include "GString.h" #include "GList.h" @@ -49,7 +53,7 @@ // Max difference in x,y coordinates (as a fraction of the font size) // allowed for duplicated text (fake boldface, drop shadows) which is // to be discarded. -#define dupMaxDeltaX 0.2 +#define dupMaxDeltaX 0.1 #define dupMaxDeltaY 0.2 // Min overlap (as a fraction of the font size) required for two @@ -124,14 +128,11 @@ TextFontInfo::TextFontInfo(GfxState *state) { horizScaling *= t1 / t2; } - if (!gfxFont) { - minSpaceWidth = horizScaling * wordDefMinSpaceWidth; - maxSpaceWidth = horizScaling * wordDefMaxSpaceWidth; - } else if (gfxFont->isCIDFont()) { + minSpaceWidth = horizScaling * wordDefMinSpaceWidth; + maxSpaceWidth = horizScaling * wordDefMaxSpaceWidth; + if (gfxFont && gfxFont->isCIDFont()) { //~ handle 16-bit fonts - minSpaceWidth = horizScaling * wordDefMinSpaceWidth; - maxSpaceWidth = horizScaling * wordDefMaxSpaceWidth; - } else { + } else if (gfxFont && gfxFont->getType() != fontType3) { avgWidth = 0; n = 0; for (i = 0; i < 256; ++i) { @@ -141,9 +142,11 @@ TextFontInfo::TextFontInfo(GfxState *state) { ++n; } } - avgWidth /= n; - minSpaceWidth = horizScaling * wordMinSpaceWidth * avgWidth; - maxSpaceWidth = horizScaling * wordMaxSpaceWidth * avgWidth; + if (n > 0) { + avgWidth /= n; + minSpaceWidth = horizScaling * wordMinSpaceWidth * avgWidth; + maxSpaceWidth = horizScaling * wordMaxSpaceWidth * avgWidth; + } } } @@ -169,11 +172,13 @@ GBool TextFontInfo::matches(GfxState *state) { // TextWord //------------------------------------------------------------------------ -TextWord::TextWord(GfxState *state, double x0, double y0, +TextWord::TextWord(GfxState *state, double x0, double y0, int charPosA, TextFontInfo *fontA, double fontSizeA) { GfxFont *gfxFont; double x, y; + charPos = charPosA; + charLen = 0; font = fontA; fontSize = fontSizeA; state->transform(x0, y0, &x, &y); @@ -249,6 +254,7 @@ void TextWord::merge(TextWord *word2) { xRight[len + i] = word2->xRight[i]; } len += word2->len; + charLen += word2->charLen; } //------------------------------------------------------------------------ @@ -299,7 +305,6 @@ GBool TextLine::yxBefore(TextLine *line2) { // Merge another line's words onto the end of this line. void TextLine::merge(TextLine *line2) { - TextWord *word; int newLen, i; xMax = line2->xMax; @@ -310,9 +315,9 @@ void TextLine::merge(TextLine *line2) { yMax = line2->yMax; } xSpaceR = line2->xSpaceR; - for (word = words; word->next; word = word->next) ; - word->spaceAfter = gTrue; - word->next = line2->words; + lastWord->spaceAfter = gTrue; + lastWord->next = line2->words; + lastWord = line2->lastWord; line2->words = NULL; newLen = len + 1 + line2->len; text = (Unicode *)grealloc(text, newLen * sizeof(Unicode)); @@ -424,6 +429,7 @@ TextFlow::~TextFlow() { TextPage::TextPage(GBool rawOrderA) { rawOrder = rawOrderA; curWord = NULL; + charPos = 0; font = NULL; fontSize = 0; nest = 0; @@ -516,7 +522,7 @@ void TextPage::beginWord(GfxState *state, double x0, double y0) { return; } - curWord = new TextWord(state, x0, y0, font, fontSize); + curWord = new TextWord(state, x0, y0, charPos, font, fontSize); } void TextPage::addChar(GfxState *state, double x, double y, @@ -558,6 +564,8 @@ void TextPage::addChar(GfxState *state, double x, double y, // break words at space character if (uLen == 1 && u[0] == (Unicode)0x20) { + ++curWord->charLen; + ++charPos; endWord(); return; } @@ -568,11 +576,22 @@ void TextPage::addChar(GfxState *state, double x, double y, n = curWord->len; if (n > 0 && x1 - curWord->xRight[n-1] > curWord->font->minSpaceWidth * curWord->fontSize) { - // large char spacing is sometimes used to move text around endWord(); beginWord(state, x, y); } + // page rotation and/or transform matrices can cause text to be + // drawn in reverse order -- in this case, swap the begin/end + // coordinates and break text into individual chars + if (w1 < 0) { + endWord(); + beginWord(state, x + dx, y + dy); + x1 += w1; + y1 += h1; + w1 = -w1; + h1 = -h1; + } + // add the characters to the current word if (uLen != 0) { w1 /= uLen; @@ -581,6 +600,8 @@ void TextPage::addChar(GfxState *state, double x, double y, for (i = 0; i < uLen; ++i) { curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]); } + ++curWord->charLen; + ++charPos; } void TextPage::endWord() { @@ -635,14 +656,14 @@ void TextPage::addWord(TextWord *word) { wordPtr = word; } -void TextPage::coalesce() { - TextWord *word0, *word1, *word2, *word3, *word4; +void TextPage::coalesce(GBool physLayout) { + TextWord *word0, *word1, *word2; TextLine *line0, *line1, *line2, *line3, *line4, *lineList; TextBlock *blk0, *blk1, *blk2, *blk3, *blk4, *blk5, *blk6; TextBlock *yxBlocks, *blocks, *blkStack; TextFlow *flow0, *flow1; - double sz, xLimit, minSpace, maxSpace, yLimit; - double fit1, fit2; + double sz, xLimit, yLimit; + double fit1, fit2, sp1, sp2; GBool found; UnicodeMap *uMap; GBool isUnicode; @@ -720,7 +741,8 @@ void TextPage::coalesce() { word2->xMin < xLimit && word2->font == word0->font && fabs(word2->fontSize - sz) < 0.05 && - fabs(word2->yBase - word0->yBase) < 0.05; + fabs(word2->yBase - word0->yBase) < 0.05 && + word2->charPos == word0->charPos + word0->charLen; } else { found = gFalse; for (word1 = word0, word2 = word0->next; @@ -728,7 +750,8 @@ void TextPage::coalesce() { word1 = word2, word2 = word2->next) { if (word2->font == word0->font && fabs(word2->fontSize - sz) < 0.05 && - fabs(word2->yBase - word0->yBase) < 0.05) { + fabs(word2->yBase - word0->yBase) < 0.05 && + word2->charPos == word0->charPos + word0->charLen) { found = gTrue; break; } @@ -760,84 +783,83 @@ void TextPage::coalesce() { //----- assemble words into lines - uMap = globalParams->getTextEncoding(); - isUnicode = uMap ? uMap->isUnicode() : gFalse; - - lineList = NULL; - line0 = NULL; + lineList = line0 = NULL; while (words) { - // build a new line object + // remove the first word from the word list word0 = words; words = words->next; word0->next = NULL; - line1 = new TextLine(); - line1->words = word0; - line1->xMin = word0->xMin; - line1->xMax = word0->xMax; - line1->yMin = word0->yMin; - line1->yMax = word0->yMax; - line1->yBase = word0->yBase; - line1->font = word0->font; - line1->fontSize = word0->fontSize; - line1->len = word0->len; - minSpace = line1->fontSize * word0->font->minSpaceWidth; - maxSpace = line1->fontSize * word0->font->maxSpaceWidth; - - // find subsequent words in the line - while (words) { - xLimit = line1->xMax + maxSpace; - fit1 = fit2 = 0; - word3 = word4 = NULL; - if (rawOrder) { - if (words && - words->xMin < xLimit && - ((fit1 = lineFit(line1, word0, words)) >= 0)) { - word3 = NULL; - word4 = words; - } + + // find the best line (if any) for the word + if (rawOrder) { + if (line0 && lineFit(line0, word0, &sp2) >= 0) { + line1 = line0; + sp1 = sp2; } else { - for (word1 = NULL, word2 = words; - word2 && word2->xMin < xLimit; - word1 = word2, word2 = word2->next) { - fit2 = lineFit(line1, word0, word2); - if (fit2 >= 0 && (!word4 || - (word4 && fit2 < fit1))) { - fit1 = fit2; - word3 = word1; - word4 = word2; - } - } + line1 = NULL; + sp1 = 0; } - if (word4) { - if (word3) { - word3->next = word4->next; - } else { - words = word4->next; - } - word0->next = word4; - word4->next = NULL; - if (word4->xMax > line1->xMax) { - line1->xMax = word4->xMax; - } - if (word4->yMin < line1->yMin) { - line1->yMin = word4->yMin; - } - if (word4->yMax > line1->yMax) { - line1->yMax = word4->yMax; - } - line1->len += word4->len; - if (fit1 > minSpace) { - word0->spaceAfter = gTrue; - ++line1->len; + } else { + line1 = NULL; + fit1 = 0; + sp1 = 0; + for (line2 = lineList; line2; line2 = line2->next) { + fit2 = lineFit(line2, word0, &sp2); + if (fit2 >= 0 && (!line1 || fit2 < fit1)) { + line1 = line2; + fit1 = fit2; + sp1 = sp2; } - word0 = word4; + } + } + + // found a line: append the word + if (line1) { + word1 = line1->lastWord; + word1->next = word0; + line1->lastWord = word0; + if (word0->xMax > line1->xMax) { + line1->xMax = word0->xMax; + } + if (word0->yMin < line1->yMin) { + line1->yMin = word0->yMin; + } + if (word0->yMax > line1->yMax) { + line1->yMax = word0->yMax; + } + line1->len += word0->len; + if (sp1 > line1->fontSize * line1->font->minSpaceWidth) { + word1->spaceAfter = gTrue; + ++line1->len; + } + + // didn't find a line: create a new line + } else { + line1 = new TextLine(); + line1->words = line1->lastWord = word0; + line1->xMin = word0->xMin; + line1->xMax = word0->xMax; + line1->yMin = word0->yMin; + line1->yMax = word0->yMax; + line1->yBase = word0->yBase; + line1->font = word0->font; + line1->fontSize = word0->fontSize; + line1->len = word0->len; + if (line0) { + line0->next = line1; } else { - break; + lineList = line1; } + line0 = line1; } + } + + // build the line text + uMap = globalParams->getTextEncoding(); + isUnicode = uMap ? uMap->isUnicode() : gFalse; - // build the line text + for (line1 = lineList; line1; line1 = line1->next) { line1->text = (Unicode *)gmalloc(line1->len * sizeof(Unicode)); line1->xRight = (double *)gmalloc(line1->len * sizeof(double)); line1->col = (int *)gmalloc(line1->len * sizeof(int)); @@ -871,13 +893,6 @@ void TextPage::coalesce() { line1->hyphenated = gTrue; } - // insert line on list - if (line0) { - line0->next = line1; - } else { - lineList = line1; - } - line0 = line1; } if (uMap) { @@ -932,6 +947,26 @@ void TextPage::coalesce() { } } +#if 0 // for debugging + printf("*** lines in xy order, after column assignment ***\n"); + for (line0 = lineList; line0; line0 = line0->next) { + printf("[line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f col=%d len=%d]\n", + line0->xMin, line0->xMax, line0->yMin, line0->yMax, + line0->yBase, line0->col[0], line0->len); + for (word0 = line0->words; word0; word0 = word0->next) { + printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSz=%.2f space=%d: '", + word0->xMin, word0->xMax, word0->yMin, word0->yMax, + word0->yBase, word0->fontSize, word0->spaceAfter); + for (i = 0; i < word0->len; ++i) { + fputc(word0->text[i] & 0xff, stdout); + } + printf("'\n"); + } + } + printf("\n"); + fflush(stdout); +#endif + //----- assemble lines into blocks if (rawOrder) { @@ -1181,6 +1216,7 @@ void TextPage::coalesce() { // +------+ +------+ +-----------+ // | blk4 | | blk6 | ... | blk4+blk6 | // +------+ +------+ +-----------+ + yLimit = 0; // make gcc happy if (blkStack) { yLimit = blkStack->yMax + blkMaxSpacing * blkStack->lines->fontSize; } @@ -1249,8 +1285,10 @@ void TextPage::coalesce() { blk0 = blk4; // push the block on the traversal stack - blk4->stackNext = blkStack; - blkStack = blk4; + if (!physLayout) { + blk4->stackNext = blkStack; + blkStack = blk4; + } } } } // (!rawOrder) @@ -1456,18 +1494,21 @@ void TextPage::coalesce() { #endif } -// Returns a non-negative number if can be added to -// (whose last word is ). A smaller return value indicates -// a better fit. If cannot be added to at all, returns -// a negative number. -double TextPage::lineFit(TextLine *line, TextWord *lastWord, TextWord *word) { +// If can be added the end of , return the absolute value +// of the difference between 's baseline and 's baseline, +// and set * to the horizontal space between the current last +// word in and . A smaller return value indicates a +// better fit. Otherwise, return a negative number. +double TextPage::lineFit(TextLine *line, TextWord *word, double *space) { + TextWord *lastWord; double fontSize0, fontSize1; double dx, dxLimit; + lastWord = line->lastWord; fontSize0 = line->fontSize; fontSize1 = word->fontSize; dx = word->xMin - lastWord->xMax; - dxLimit = fontSize0 * line->font->maxSpaceWidth; + dxLimit = fontSize0 * lastWord->font->maxSpaceWidth; // check inter-word spacing if (dx < fontSize0 * lineMinDeltaX || @@ -1475,36 +1516,30 @@ double TextPage::lineFit(TextLine *line, TextWord *lastWord, TextWord *word) { return -1; } - // ensure a non-negative return value - if (dx < 0) { - dx = 0; - } + if ( + // look for adjacent words with close baselines and close font sizes + (fabs(line->yBase - word->yBase) < lineMaxBaselineDelta * fontSize0 && + fontSize0 < lineMaxFontSizeRatio * fontSize1 && + fontSize1 < lineMaxFontSizeRatio * fontSize0) || - // look for adjacent words with close baselines and close font sizes - if (fabs(line->yBase - word->yBase) < lineMaxBaselineDelta * fontSize0 && - fontSize0 < lineMaxFontSizeRatio * fontSize1 && - fontSize1 < lineMaxFontSizeRatio * fontSize0) { - return dx; - } + // look for a superscript + (fontSize1 > lineMinSuperscriptFontSizeRatio * fontSize0 && + fontSize1 < lineMaxSuperscriptFontSizeRatio * fontSize0 && + (word->yMax < lastWord->yMax || + word->yBase < lastWord->yBase) && + word->yMax - lastWord->yMin > lineMinSuperscriptOverlap * fontSize0 && + dx < fontSize0 * lineMaxSuperscriptDeltaX) || - // look for a superscript - if (fontSize1 > lineMinSuperscriptFontSizeRatio * fontSize0 && - fontSize1 < lineMaxSuperscriptFontSizeRatio * fontSize0 && - (word->yMax < lastWord->yMax || - word->yBase < lastWord->yBase) && - word->yMax - lastWord->yMin > lineMinSuperscriptOverlap * fontSize0 && - dx < fontSize0 * lineMaxSuperscriptDeltaX) { - return dx; - } + // look for a subscript + (fontSize1 > lineMinSubscriptFontSizeRatio * fontSize0 && + fontSize1 < lineMaxSubscriptFontSizeRatio * fontSize0 && + (word->yMin > lastWord->yMin || + word->yBase > lastWord->yBase) && + line->yMax - word->yMin > lineMinSubscriptOverlap * fontSize0 && + dx < fontSize0 * lineMaxSubscriptDeltaX)) { - // look for a subscript - if (fontSize1 > lineMinSubscriptFontSizeRatio * fontSize0 && - fontSize1 < lineMaxSubscriptFontSizeRatio * fontSize0 && - (word->yMin > lastWord->yMin || - word->yBase > lastWord->yBase) && - line->yMax - word->yMin > lineMinSubscriptOverlap * fontSize0 && - dx < fontSize0 * lineMaxSubscriptDeltaX) { - return dx; + *space = dx; + return fabs(word->yBase - line->yBase); } return -1; @@ -1737,7 +1772,7 @@ GString *TextPage::getText(double xMin, double yMin, } i = 0; - while (1) { + while (i < line->len) { x0 = (i==0) ? line->xMin : line->xRight[i-1]; x1 = line->xRight[i]; if (0.5 * (x0 + x1) > xMin) { @@ -1745,6 +1780,9 @@ GString *TextPage::getText(double xMin, double yMin, } ++i; } + if (i == line->len) { + continue; + } col = line->col[i]; if (firstCol < 0 || col < firstCol) { @@ -1755,9 +1793,8 @@ GString *TextPage::getText(double xMin, double yMin, // extract the text col = firstCol; multiLine = gFalse; - for (prevLine = NULL, line = lines; - line; - prevLine = line, line = line->pageNext) { + prevLine = NULL; + for (line = lines; line; line = line->pageNext) { if (line->yMin > yMax) { break; } @@ -1773,7 +1810,7 @@ GString *TextPage::getText(double xMin, double yMin, } i = 0; - while (1) { + while (i < line->len) { x0 = (i==0) ? line->xMin : line->xRight[i-1]; x1 = line->xRight[i]; if (0.5 * (x0 + x1) > xMin) { @@ -1781,9 +1818,12 @@ GString *TextPage::getText(double xMin, double yMin, } ++i; } + if (i == line->len) { + continue; + } // insert a return - if (col > line->col[i] || + if (line->col[i] < col || (prevLine && line->yMin > prevLine->yMax - lineOverlapSlack * prevLine->fontSize)) { @@ -1791,6 +1831,7 @@ GString *TextPage::getText(double xMin, double yMin, col = firstCol; multiLine = gTrue; } + prevLine = line; // line this block up with the correct column for (; col < line->col[i]; ++col) { @@ -1821,6 +1862,53 @@ GString *TextPage::getText(double xMin, double yMin, return s; } +GBool TextPage::findCharRange(int pos, int length, + double *xMin, double *yMin, + double *xMax, double *yMax) { + TextLine *line; + TextWord *word; + double x; + GBool first; + int i; + + //~ this doesn't correctly handle: + //~ - ranges split across multiple lines (the highlighted region + //~ is the bounding box of all the parts of the range) + //~ - cases where characters don't convert one-to-one into Unicode + first = gTrue; + for (line = lines; line; line = line->pageNext) { + for (word = line->words; word; word = word->next) { + if (pos < word->charPos + word->charLen && + word->charPos < pos + length) { + i = pos - word->charPos; + if (i < 0) { + i = 0; + } + x = (i == 0) ? word->xMin : word->xRight[i - 1]; + if (first || x < *xMin) { + *xMin = x; + } + i = pos + length - word->charPos; + if (i >= word->len) { + i = word->len - 1; + } + x = word->xRight[i]; + if (first || x > *xMax) { + *xMax = x; + } + if (first || word->yMin < *yMin) { + *yMin = word->yMin; + } + if (first || word->yMax > *yMax) { + *yMax = word->yMax; + } + first = gFalse; + } + } + } + return !first; +} + void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, GBool physLayout) { UnicodeMap *uMap; @@ -1870,7 +1958,8 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, col += line->convertedLen; // print one or more returns if necessary - if (!line->pageNext || + if (rawOrder || + !line->pageNext || line->pageNext->col[0] < col || line->pageNext->yMin > line->yMax - lineOverlapSlack * line->fontSize) { @@ -1927,8 +2016,12 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, void TextPage::startPage(GfxState *state) { clear(); - pageWidth = state->getPageWidth(); - pageHeight = state->getPageHeight(); + if (state) { + pageWidth = state->getPageWidth(); + pageHeight = state->getPageHeight(); + } else { + pageWidth = pageHeight = 0; + } } void TextPage::clear() { @@ -1953,6 +2046,7 @@ void TextPage::clear() { deleteGList(fonts, TextFontInfo); curWord = NULL; + charPos = 0; font = NULL; fontSize = 0; nest = 0; @@ -1985,6 +2079,10 @@ TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA, if (fileName) { if (!strcmp(fileName, "-")) { outputStream = stdout; +#ifdef WIN32 + // keep DOS from munging the end-of-line characters + setmode(fileno(stdout), O_BINARY); +#endif } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) { needClose = gTrue; } else { @@ -2029,7 +2127,7 @@ void TextOutputDev::startPage(int pageNum, GfxState *state) { } void TextOutputDev::endPage() { - text->coalesce(); + text->coalesce(physLayout); if (outputStream) { text->dump(outputStream, outputFunc, physLayout); } @@ -2066,5 +2164,10 @@ GString *TextOutputDev::getText(double xMin, double yMin, return text->getText(xMin, yMin, xMax, yMax); } +GBool TextOutputDev::findCharRange(int pos, int length, + double *xMin, double *yMin, + double *xMax, double *yMax) { + return text->findCharRange(pos, length, xMin, yMin, xMax, yMax); +} diff --git a/pdf/xpdf/TextOutputDev.h b/pdf/xpdf/TextOutputDev.h index 8e94f04..e0c22c2 100644 --- a/pdf/xpdf/TextOutputDev.h +++ b/pdf/xpdf/TextOutputDev.h @@ -2,7 +2,7 @@ // // TextOutputDev.h // -// Copyright 1997-2002 Glyph & Cog, LLC +// Copyright 1997-2003 Glyph & Cog, LLC // //======================================================================== @@ -65,7 +65,7 @@ class TextWord { public: // Constructor. - TextWord(GfxState *state, double x0, double y0, + TextWord(GfxState *state, double x0, double y0, int charPosA, TextFontInfo *fontA, double fontSize); @@ -89,6 +89,9 @@ private: double *xRight; // right-hand x coord of each char int len; // length of text and xRight int size; // size of text and xRight arrays + int charPos; // character position (within content stream) + int charLen; // number of content stream characters in + // this word TextFontInfo *font; // font information double fontSize; // font size GBool spaceAfter; // set if there is a space between this @@ -123,6 +126,7 @@ private: TextFontInfo *font; // primary font double fontSize; // primary font size TextWord *words; // words in this line + TextWord *lastWord; // last word in this line Unicode *text; // Unicode text of the line, including // spaces between words double *xRight; // right-hand x coord of each Unicode char @@ -222,12 +226,12 @@ public: // Coalesce strings that look like parts of the same line. - void coalesce(); + void coalesce(GBool physLayout); // Find a string. If is true, starts looking at top of page; // otherwise starts looking at ,. If is true, // stops looking at bottom of page; otherwise stops looking at - // ,. If found, sets the text bounding rectange and + // ,. If found, sets the text bounding rectangle and // returns true; otherwise returns false. GBool findText(Unicode *s, int len, GBool top, GBool bottom, @@ -238,6 +242,13 @@ public: GString *getText(double xMin, double yMin, double xMax, double yMax); + // Find a string by character position and length. If found, sets + // the text bounding rectangle and returns true; otherwise returns + // false. + GBool findCharRange(int pos, int length, + double *xMin, double *yMin, + double *xMax, double *yMax); + // Dump contents of page to a file. void dump(void *outputStream, TextOutputFunc outputFunc, GBool physLayout); @@ -249,7 +260,7 @@ public: private: void clear(); - double lineFit(TextLine *line, TextWord *lastWord, TextWord *word); + double lineFit(TextLine *line, TextWord *word, double *space); GBool lineFit2(TextLine *line0, TextLine *line1); GBool blockFit(TextBlock *blk, TextLine *line); GBool blockFit2(TextBlock *blk0, TextBlock *blk1); @@ -259,6 +270,8 @@ private: double pageWidth, pageHeight; // width and height of current page TextWord *curWord; // currently active string + int charPos; // next character position (within content + // stream) TextFontInfo *font; // current font double fontSize; // current font size int nest; // current nesting level (for Type 3 fonts) @@ -347,7 +360,7 @@ public: // Find a string. If is true, starts looking at top of page; // otherwise starts looking at ,. If is true, // stops looking at bottom of page; otherwise stops looking at - // ,. If found, sets the text bounding rectange and + // ,. If found, sets the text bounding rectangle and // returns true; otherwise returns false. GBool findText(Unicode *s, int len, GBool top, GBool bottom, @@ -358,6 +371,13 @@ public: GString *getText(double xMin, double yMin, double xMax, double yMax); + // Find a string by character position and length. If found, sets + // the text bounding rectangle and returns true; otherwise returns + // false. + GBool findCharRange(int pos, int length, + double *xMin, double *yMin, + double *xMax, double *yMax); + private: diff --git a/pdf/xpdf/UnicodeMap.cc b/pdf/xpdf/UnicodeMap.cc index bfa5ecc..e6284eb 100644 --- a/pdf/xpdf/UnicodeMap.cc +++ b/pdf/xpdf/UnicodeMap.cc @@ -2,7 +2,7 @@ // // UnicodeMap.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/UnicodeMap.h b/pdf/xpdf/UnicodeMap.h index 60c0c27..24de28c 100644 --- a/pdf/xpdf/UnicodeMap.h +++ b/pdf/xpdf/UnicodeMap.h @@ -4,7 +4,7 @@ // // Mapping from Unicode to an encoding. // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/XOutputDev.cc b/pdf/xpdf/XOutputDev.cc index f9064fa..2100355 100644 --- a/pdf/xpdf/XOutputDev.cc +++ b/pdf/xpdf/XOutputDev.cc @@ -2,7 +2,7 @@ // // XOutputDev.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -1005,7 +1005,7 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp, if (freetypeControl != fontRastNone) { font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont, m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, subst); + m11, m12, m21, m22, gFalse, subst); } } #endif @@ -1020,7 +1020,7 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp, if (freetypeControl != fontRastNone) { font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont, m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, subst); + m11, m12, m21, m22, gFalse, subst); } #endif #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) @@ -1091,6 +1091,11 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref, return NULL; } ff = new Type1CFontFile(fontBuf, fontLen); + if (!ff->isOk()) { + delete ff; + gfree(fontBuf); + return NULL; + } ff->convertToType1(outputToFile, f); delete ff; gfree(fontBuf); @@ -1263,7 +1268,7 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref, // create the Font font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont, m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); + m11, m12, m21, m22, gTrue, gFalse); // on systems with Unix hard link semantics, this will remove the // last link to the temp file @@ -1275,7 +1280,7 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref, } else if ((fileName = gfxFont->getExtFontFile())) { font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont, m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); + m11, m12, m21, m22, gFalse, gFalse); } else { font = NULL; @@ -1294,6 +1299,7 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref, double m22Orig, double m11, double m12, double m21, double m22, + GBool embedded, GBool subst) { Ref *id; FTFontFile *fontFile; @@ -1304,14 +1310,16 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref, if (gfxFont->getType() == fontCIDType2) { fontFile = new FTFontFile(ftEngine, fileName->getCString(), ((GfxCIDFont *)gfxFont)->getCIDToGID(), - ((GfxCIDFont *)gfxFont)->getCIDToGIDLen()); + ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(), + embedded); } else { // fontCIDType0, fontCIDType0C - fontFile = new FTFontFile(ftEngine, fileName->getCString()); + fontFile = new FTFontFile(ftEngine, fileName->getCString(), embedded); } } else { fontFile = new FTFontFile(ftEngine, fileName->getCString(), ((Gfx8BitFont *)gfxFont)->getEncoding(), - ((Gfx8BitFont *)gfxFont)->getHasEncoding()); + ((Gfx8BitFont *)gfxFont)->getHasEncoding(), + ((Gfx8BitFont *)gfxFont)->isSymbolic()); } if (!fontFile->isOk()) { error(-1, "Couldn't create FreeType font from '%s'", @@ -1769,6 +1777,7 @@ XOutputDev::XOutputDev(Display *displayA, int screenNumA, // set up the font cache and fonts gfxFont = NULL; font = NULL; + needFontUpdate = gFalse; fontCache = new XOutputFontCache(display, depth, this, globalParams->getT1libControl(), globalParams->getFreeTypeControl()); @@ -1850,7 +1859,7 @@ void XOutputDev::startPage(int pageNum, GfxState *state) { void XOutputDev::endPage() { XOutputState *s; - text->coalesce(); + text->coalesce(gTrue); // clear state stack, free all GCs, free the clip region while (save) { @@ -1944,8 +1953,8 @@ void XOutputDev::restoreState(GfxState *state) { save = save->next; delete s; - // restore the font - updateFont(state); + // we'll need to restore the font + needFontUpdate = gTrue; } } @@ -1955,7 +1964,7 @@ void XOutputDev::updateAll(GfxState *state) { updateMiterLimit(state); updateFillColor(state); updateStrokeColor(state); - updateFont(state); + needFontUpdate = gTrue; } void XOutputDev::updateCTM(GfxState *state, double m11, double m12, @@ -2063,6 +2072,8 @@ void XOutputDev::updateStrokeColor(GfxState *state) { void XOutputDev::updateFont(GfxState *state) { double m11, m12, m21, m22; + needFontUpdate = gFalse; + text->updateFont(state); if (!(gfxFont = state->getFont())) { @@ -2505,6 +2516,10 @@ void XOutputDev::drawChar(GfxState *state, double x, double y, double *ctm; double saveCTM[6]; + if (needFontUpdate) { + updateFont(state); + } + text->addChar(state, x, y, dx, dy, code, u, uLen); if (!font) { @@ -2579,6 +2594,9 @@ GBool XOutputDev::beginType3Char(GfxState *state, double x1, y1, xMin, yMin, xMax, yMax, xt, yt; int i, j; + if (needFontUpdate) { + updateFont(state); + } if (!gfxFont) { return gFalse; } diff --git a/pdf/xpdf/XOutputDev.h b/pdf/xpdf/XOutputDev.h index 149fd6e..7a6544d 100644 --- a/pdf/xpdf/XOutputDev.h +++ b/pdf/xpdf/XOutputDev.h @@ -2,7 +2,7 @@ // // XOutputDev.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -422,7 +422,8 @@ private: double m11Orig, double m12Orig, double m21Orig, double m22Orig, double m11, double m12, - double m21, double m22, GBool subst); + double m21, double m22, + GBool embedded, GBool subst); #endif #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) XOutputFont *tryGetTTFont(XRef *xref, GfxFont *gfxFont, @@ -640,6 +641,7 @@ private: tmpRects[numTmpSubpaths]; GfxFont *gfxFont; // current PDF font XOutputFont *font; // current font + GBool needFontUpdate; // set when the font needs to be updated XOutputFontCache *fontCache; // font cache T3FontCache * // Type 3 font cache t3FontCache[xOutT3FontCacheSize]; diff --git a/pdf/xpdf/XRef.cc b/pdf/xpdf/XRef.cc index 901caa5..56cb131 100644 --- a/pdf/xpdf/XRef.cc +++ b/pdf/xpdf/XRef.cc @@ -2,7 +2,7 @@ // // XRef.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -325,6 +325,11 @@ GBool XRef::readXRef(Guint *pos) { if (obj2.isInt()) { *pos = (Guint)obj2.getInt(); more = gTrue; + } else if (obj2.isRef()) { + // certain buggy PDF generators generate "/Prev NNN 0 R" instead + // of "/Prev NNN" + *pos = (Guint)obj2.getRefNum(); + more = gTrue; } else { more = gFalse; } diff --git a/pdf/xpdf/XRef.h b/pdf/xpdf/XRef.h index ebe5b54..3f5a598 100644 --- a/pdf/xpdf/XRef.h +++ b/pdf/xpdf/XRef.h @@ -2,7 +2,7 @@ // // XRef.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/pdffonts.cc b/pdf/xpdf/pdffonts.cc index fcb739a..f3a1b48 100644 --- a/pdf/xpdf/pdffonts.cc +++ b/pdf/xpdf/pdffonts.cc @@ -2,7 +2,7 @@ // // pdffonts.cc // -// Copyright 2001-2002 Glyph & Cog, LLC +// Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/pdfimages.cc b/pdf/xpdf/pdfimages.cc index 5e35bfb..e8a42aa 100644 --- a/pdf/xpdf/pdfimages.cc +++ b/pdf/xpdf/pdfimages.cc @@ -2,7 +2,7 @@ // // pdfimages.cc // -// Copyright 1998-2002 Glyph & Cog, LLC +// Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/pdfinfo.cc b/pdf/xpdf/pdfinfo.cc index f1df095..f856a6d 100644 --- a/pdf/xpdf/pdfinfo.cc +++ b/pdf/xpdf/pdfinfo.cc @@ -2,7 +2,7 @@ // // pdfinfo.cc // -// Copyright 1998-2002 Glyph & Cog, LLC +// Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== @@ -72,11 +72,12 @@ int main(int argc, char *argv[]) { GString *ownerPW, *userPW; UnicodeMap *uMap; Object info; - double w, h; + double w, h, wISO, hISO; FILE *f; GString *metadata; GBool ok; int exitCode; + int i; exitCode = 99; @@ -169,9 +170,18 @@ int main(int argc, char *argv[]) { if ((fabs(w - 612) < 0.1 && fabs(h - 792) < 0.1) || (fabs(w - 792) < 0.1 && fabs(h - 612) < 0.1)) { printf(" (letter)"); - } else if ((fabs(w - 595) < 0.1 && fabs(h - 842) < 0.1) || - (fabs(w - 842) < 0.1 && fabs(h - 595) < 0.1)) { - printf(" (A4)"); + } else { + hISO = sqrt(sqrt(2)) * 7200 / 2.54; + wISO = hISO / sqrt(2); + for (i = 0; i <= 6; ++i) { + if ((fabs(w - wISO) < 1 && fabs(h - hISO) < 1) || + (fabs(w - hISO) < 1 && fabs(h - wISO) < 1)) { + printf(" (A%d)", i); + break; + } + hISO = wISO; + wISO /= sqrt(2); + } } printf("\n"); } diff --git a/pdf/xpdf/pdftopbm.cc b/pdf/xpdf/pdftopbm.cc index 76f60a6..704a3d0 100644 --- a/pdf/xpdf/pdftopbm.cc +++ b/pdf/xpdf/pdftopbm.cc @@ -2,7 +2,7 @@ // // pdftopbm.cc // -// Copyright 1998-2002 Glyph & Cog, LLC +// Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/pdftops.cc b/pdf/xpdf/pdftops.cc index d5d2de8..2bb2e3b 100644 --- a/pdf/xpdf/pdftops.cc +++ b/pdf/xpdf/pdftops.cc @@ -2,7 +2,7 @@ // // pdftops.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -89,7 +89,7 @@ static ArgDesc argDesc[] = { {"-noembcidtt", argFlag, &noEmbedCIDTTFonts, 0, "don't embed CID TrueType fonts"}, {"-paper", argString, paperSize, sizeof(paperSize), - "paper size (letter, legal, A4, A3)"}, + "paper size (letter, legal, A4, A3, match)"}, {"-paperw", argInt, &paperWidth, 0, "paper width, in points"}, {"-paperh", argInt, &paperHeight, 0, @@ -181,6 +181,7 @@ int main(int argc, char *argv[]) { if (paperSize[0]) { if (!globalParams->setPSPaperSize(paperSize)) { fprintf(stderr, "Invalid paper size\n"); + delete fileName; goto err0; } } else { @@ -295,8 +296,8 @@ int main(int argc, char *argv[]) { delete psFileName; err1: delete doc; - delete globalParams; err0: + delete globalParams; // check for memory leaks Object::memCheck(stderr); diff --git a/pdf/xpdf/pdftotext.cc b/pdf/xpdf/pdftotext.cc index 8b13ff2..a67f924 100644 --- a/pdf/xpdf/pdftotext.cc +++ b/pdf/xpdf/pdftotext.cc @@ -2,7 +2,7 @@ // // pdftotext.cc // -// Copyright 1997-2002 Glyph & Cog, LLC +// Copyright 1997-2003 Glyph & Cog, LLC // //======================================================================== diff --git a/pdf/xpdf/vms_make.com b/pdf/xpdf/vms_make.com index 35cc7c1..174debb 100644 --- a/pdf/xpdf/vms_make.com +++ b/pdf/xpdf/vms_make.com @@ -4,7 +4,7 @@ $! Xpdf compile script for VMS. $! $! Written by Patrick Moreau, Martin P.J. Zinser. $! -$! Copyright 1996-2002 Glyph & Cog, LLC +$! Copyright 1996-2003 Glyph & Cog, LLC $! $!======================================================================== $! @@ -27,8 +27,8 @@ $ COMMON_LIBS = "[]common.olb/lib,[-.goo]libgoo.olb/lib" $! $ XPDF_OBJS = "xpdf.obj,FTFont.obj,PSOutputDev.obj," + - "SFont.obj,T1Font.obj,TextOutputDev.obj,TTFont.obj," + - - "XOutputDev.obj,XPDFApp.o,XPDFCore.o,XPDFTree.o," + - - "XPDFViewer.o,XPixmapOutputDev.o" + "XOutputDev.obj,XPDFApp.obj,XPDFCore.obj,XPDFTree.obj," + - + "XPDFViewer.obj,XPixmapOutputDev.obj" $ XPDF_LIBS = "" $! $ PDFTOPS_OBJS = "pdftops.obj,PSOutputDev.obj" diff --git a/pdf/xpdf/xpdf.cc b/pdf/xpdf/xpdf.cc index 290cfe9..73a0fe2 100644 --- a/pdf/xpdf/xpdf.cc +++ b/pdf/xpdf/xpdf.cc @@ -2,7 +2,7 @@ // // xpdf.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -71,7 +71,7 @@ static ArgDesc argDesc[] = { {"-ps", argString, psFileArg, sizeof(psFileArg), "default PostScript file name or command"}, {"-paper", argString, paperSize, sizeof(paperSize), - "paper size (letter, legal, A4, A3)"}, + "paper size (letter, legal, A4, A3, match)"}, {"-paperw", argInt, &paperWidth, 0, "paper width, in points"}, {"-paperh", argInt, &paperHeight, 0, diff --git a/pdf/xpdf/xpdfconfig.h b/pdf/xpdf/xpdfconfig.h index ef1764a..eda629c 100644 --- a/pdf/xpdf/xpdfconfig.h +++ b/pdf/xpdf/xpdfconfig.h @@ -2,7 +2,7 @@ // // config.h // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -14,22 +14,23 @@ //------------------------------------------------------------------------ // xpdf version -#define xpdfVersion "2.01" -#define xpdfVersionNum 2.01 +#define xpdfVersion "2.02" +#define xpdfVersionNum 2.02 #define xpdfMajorVersion 2 -#define xpdfMinorVersion 1 +#define xpdfMinorVersion 2 #define xpdfMajorVersionStr "2" +#define xpdfMinorVersionStr "2" // supported PDF version #define supportedPDFVersionStr "1.4" #define supportedPDFVersionNum 1.4 // copyright notice -#define xpdfCopyright "Copyright 1996-2002 Glyph & Cog, LLC" +#define xpdfCopyright "Copyright 1996-2003 Glyph & Cog, LLC" // Windows resource file stuff -#define winxpdfVersion "WinXpdf 2.01" -#define xpdfCopyrightAmp "Copyright 1996-2002 Glyph && Cog, LLC" +#define winxpdfVersion "WinXpdf 2.02" +#define xpdfCopyrightAmp "Copyright 1996-2003 Glyph && Cog, LLC" //------------------------------------------------------------------------ // paper size -- cgit v0.9.1