//
// GHash.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// GHash.h
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// GList.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// GList.h
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Simple variable-length string type.
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Simple variable-length string type.
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Miscellaneous file and directory name manipulation.
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Miscellaneous file and directory name manipulation.
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
*
* Memory routines with out-of-memory checking.
*
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
*/
#include <aconf.h>
*
* Memory routines with out-of-memory checking.
*
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
*/
#ifndef GMEM_H
//
// Use gmalloc/gfree for C++ new/delete operators.
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
*
* Some useful simple types.
*
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
*/
#ifndef GTYPES_H
*
* Command line argument parser.
*
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
*/
#include <locale.h>
*
* Command line argument parser.
*
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
*/
#ifndef PARSEARGS_H
$!
$! Written by Patrick Moreau, Martin P.J. Zinser.
$!
-$! Copyright 1996-2002 Glyph & Cog, LLC
+$! Copyright 1996-2003 Glyph & Cog, LLC
$!
$!========================================================================
$!
//
// Annot.cc
//
-// Copyright 2000-2002 Glyph & Cog, LLC
+// Copyright 2000-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Annot.h
//
-// Copyright 2000-2002 Glyph & Cog, LLC
+// Copyright 2000-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Array.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
#pragma implementation
#endif
+#include <stdlib.h>
#include <stddef.h>
#include "gmem.h"
#include "Object.h"
}
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);
}
//
// Array.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// BuiltinFont.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// BuiltinFont.h
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// BuiltinFontTables.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// CMap.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// CMap.h
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Catalog.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Catalog.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// CharCodeToUnicode.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Mapping from character codes to Unicode.
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Decrypt.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Decrypt.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Dict.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Dict.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Error.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Error.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// FTFont.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//------------------------------------------------------------------------
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;
// 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:
// 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) {
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;
}
FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
- Gushort *cidToGIDA, int cidToGIDLenA) {
+ Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded) {
+ int i;
+
ok = gFalse;
engine = engineA;
codeMap = NULL;
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;
}
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;
}
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;
}
// 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;
}
w0 = w - x0;
}
if (w0 < 0) {
- return gTrue;
+ goto done;
}
if (y0 < 0) {
y1 = -y0;
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;
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;
pix = 4;
}
if (pix > 0) {
- XPutPixel(image, xx, yy, colors[pix]);
+ XPutPixel(img, xx, yy, colors[pix]);
}
}
}
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;
}
}
// 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;
}
}
cacheTags[i+j].mru = 0x8000;
+ *tempBitmap = gFalse;
return cache + (i+j) * glyphSize;
}
}
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;
}
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) {
//
// An X wrapper for the FreeType font rasterizer.
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
// 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();
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);
//
// FontEncodingTables.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// FontFile.cc
//
-// Copyright 1999-2002 Glyph & Cog, LLC
+// Copyright 1999-2003 Glyph & Cog, LLC
//
//========================================================================
};
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() {
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;
}
// 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];
}
i = 0;
} else {
- x = getNum(&ptr, &isFP);
+ x = getNum(&pos, &isFP);
if (i < 48) {
op[i++] = x;
}
}
// get number of glyphs from charstrings index
- nGlyphs = getIndexLen((Guchar *)file + charstrings);
+ nGlyphs = getIndexLen(charstrings);
// read charset (GID -> name mapping)
glyphNames = readCharset(charset, nGlyphs);
}
}
} 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;
}
}
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);
}
}
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;
// 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());
}
// get number of glyphs from charstrings index
- nGlyphs = getIndexLen((Guchar *)file + dict.charStrings);
+ nGlyphs = getIndexLen(dict.charStrings);
// read charset
glyphNames = readCharset(dict.charset, nGlyphs);
}
}
} 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);
(*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));
}
}
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);
(*outputFunc)(outputStream, " put\n", 5);
}
}
+ err0:;
}
(*outputFunc)(outputStream, "readonly def\n", 13);
}
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");
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;
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;
}
// 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);
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;
}
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();
}
(*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",
(*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,
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;
int key;
double x;
GBool isFP;
- int i, j, n;
+ int i, j;
outputFunc = outputFuncA;
outputStream = outputStreamA;
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;
}
// 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);
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;
}
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) {
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");
(*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;
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;
}
i = 0;
} else {
- x = getNum(&ptr, &isFP);
+ x = getNum(&pos, &isFP);
if (i < 48) {
op[i] = x;
fp[i++] = isFP;
void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
int offset, int size) {
- Guchar *idxPtr0, *idxPtr1, *ptr;
+ int pos;
char eBuf[256];
int key;
double x;
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:
}
i = 0;
} else {
- x = getNum(&ptr, &isFP);
+ x = getNum(&pos, &isFP);
if (i < 48) {
op[i] = x;
fp[i++] = isFP;
Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
Gushort *glyphNames;
- Guchar *ptr;
+ int pos;
int charsetFormat, c;
int nLeft, i, j;
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++;
}
} 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;
}
}
}
-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());
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;
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) {
}
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) {
}
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;
}
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);
}
break;
case 14: // endchar / seac
- if (first) {
+ if (firstOp) {
cvtGlyphWidth(nOps == 1 || nOps == 5);
- first = gFalse;
+ firstOp = gFalse;
}
if (nOps == 4) {
eexecDumpNum(0, 0);
}
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);
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);
}
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);
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);
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);
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;
}
// 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;
+ }
}
}
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;
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) {
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;
}
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;
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;
}
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;
// 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);
// 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;
}
}
++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;
}
void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
CharCodeToUnicode *toUnicode,
GBool pdfFontHasEncoding,
+ GBool pdfFontIsSymbolic,
FontFileOutputFunc outputFunc,
void *outputStream) {
char buf[512];
// 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);
for (i = 0; i < nTables; ++i) {
if (!strncmp(tableHdrs[i].tag, tag, 4)) {
- return tableHdrs[i].offset;
+ return (int)tableHdrs[i].offset;
}
}
return -1;
for (i = 0; i < nTables; ++i) {
if (!strncmp(tableHdrs[i].tag, tag, 4)) {
+ if (tableHdrs[i].offset == (Guint)-1) {
+ return -1;
+ }
return i;
}
}
void TrueTypeFontFile::cvtCharStrings(char **encodingA,
CharCodeToUnicode *toUnicode,
GBool pdfFontHasEncoding,
+ GBool pdfFontIsSymbolic,
FontFileOutputFunc outputFunc,
void *outputStream) {
int unicodeCmap, macRomanCmap, msSymbolCmap;
// 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:
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;
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;
// 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 {
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);
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 {
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;
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);
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
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) {
} 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);
}
}
// 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);
+ }
}
}
}
};
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);
+ }
}
//
// FontFile.h
//
-// Copyright 1999-2002 Glyph & Cog, LLC
+// Copyright 1999-2003 Glyph & Cog, LLC
//
//========================================================================
Type1CFontFile(char *fileA, int lenA);
virtual ~Type1CFontFile();
+ GBool isOk() { return ok; }
virtual char *getName();
virtual char **getEncoding();
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);
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
Gushort r1; // eexec encryption key
GString *charBuf; // charstring output buffer
int line; // number of eexec chars on current line
+
+ GBool ok;
};
//------------------------------------------------------------------------
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
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,
//
// Function.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
Object obj1, obj2;
- GBool hasN;
int i;
ok = gFalse;
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()) {
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;
}
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();
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;
//
// Function.h
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Gfx.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Gfx.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// GfxFont.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
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" },
}
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);
}
}
}
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);
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;
}
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()) {
// 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;
}
//
// GfxFont.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// GfxState.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// GfxState.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// GlobalParams.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
} 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")) {
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;
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")) {
//
// GlobalParams.h
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
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();
//
// ImageOutputDev.cc
//
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
//
//========================================================================
//
// ImageOutputDev.h
//
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Lexer.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Lexer.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Link.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
// 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);
// 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;
// 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;
// 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;
// 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;
// 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;
//
// Link.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// NameToCharCode.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// NameToCharCode.h
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// NameToUnicodeTable.h
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Object.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Object.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// OutputDev.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
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];
}
//
// OutputDev.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//----- 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
//
// PBMOutputDev.cc
//
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
//
//========================================================================
//
// PBMOutputDev.h
//
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
//
//========================================================================
//
// PDFDoc.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// PDFDoc.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// PSOutputDev.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
#include <signal.h>
#include <math.h>
#include "GString.h"
+#include "GList.h"
#include "config.h"
#include "GlobalParams.h"
#include "Object.h"
" /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",
"/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",
fontFileIDs = NULL;
fontFileNames = NULL;
font16Enc = NULL;
+ xobjStack = NULL;
embFontList = NULL;
customColors = NULL;
t3String = NULL;
fontFileIDs = NULL;
fontFileNames = NULL;
font16Enc = NULL;
+ xobjStack = NULL;
embFontList = NULL;
customColors = NULL;
t3String = NULL;
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;
}
fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
font16EncLen = 0;
font16EncSize = 0;
+ xobjStack = new GList();
// initialize embedded font resource comment list
embFontList = new GString();
}
gfree(font16Enc);
}
+ if (xobjStack) {
+ delete xobjStack;
+ }
while (customColors) {
cc = customColors;
customColors = cc->next;
}
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);
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();
GString *psNameStr;
char *psName;
char type3Name[64], buf[16];
+ GBool subst;
UnicodeMap *uMap;
char *charName;
double xs, ys;
xs = ys = 1;
psNameStr = NULL;
+ subst = gFalse;
// check for resident 8-bit font
if (font->getName() &&
// do 8-bit font substitution
} else if (!font->isCIDFont()) {
+ subst = gTrue;
name = font->getName();
psName = NULL;
if (name) {
getPSFont16(font->getName(),
((GfxCIDFont *)font)->getCollection(),
font->getWMode()))) {
+ subst = gTrue;
psName = fontParam->psFontName->getCString();
if (font16EncLen >= font16EncSize) {
font16EncSize += 16;
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;
// 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);
ctu = ((Gfx8BitFont *)font)->getToUnicode();
ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
+ ((Gfx8BitFont *)font)->isSymbolic(),
outputFunc, outputStream);
ctu->decRefCnt();
delete ttFile;
ctu = ((Gfx8BitFont *)font)->getToUnicode();
ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
+ ((Gfx8BitFont *)font)->isSymbolic(),
outputFunc, outputStream);
ctu->decRefCnt();
delete ttFile;
// 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);
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 ||
//
// PSOutputDev.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
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
//
// PSTokenizer.cc
//
-// Copyright 2002 Glyph & Cog, LLC
+// Copyright 2002-2003 Glyph & Cog, LLC
//
//========================================================================
//
// PSTokenizer.h
//
-// Copyright 2002 Glyph & Cog, LLC
+// Copyright 2002-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Page.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Page.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Parser.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Parser.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// SFont.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Base class for font rasterizers.
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Tables for CCITT Fax decoding.
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Stream.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
// 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;
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) {
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)];
return gFalse;
}
i += run;
- j = dctZigZag[i++];
- data[j] = amp;
+ if (i < 64) {
+ j = dctZigZag[i++];
+ data[j] = amp;
+ }
}
}
return gTrue;
eobRun = 0;
for (k = 0; k < j; ++k) {
if ((bit = readBit()) == EOF) {
- return 9999;
+ return gFalse;
}
eobRun = (eobRun << 1) | bit;
}
int len, repeat, code;
int i;
+ codeLenCodeTab.codes = NULL;
+
// read lengths
if ((numLitCodes = getCodeWord(5)) == EOF) {
goto err;
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 {
//
// Stream.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// T1Font.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
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;
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;
}
w0 = w - x0;
}
if (w0 < 0) {
- return gTrue;
+ goto done;
}
if (y0 < 0) {
y1 = -y0;
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;
}
// stuff the glyph pixmap into the X image
+ p = bitmap;
for (yy = 0; yy < gh; ++yy) {
for (xx = 0; xx < gw; ++xx) {
pix = *p++;
if (pix > mPix) {
pix = mPix;
}
- XPutPixel(image, xx, yy, colors[pix]);
+ XPutPixel(img, xx, yy, colors[pix]);
}
}
}
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;
}
}
// 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;
}
}
cacheTags[i+j].mru = 0x8000;
+ *tempBitmap = gFalse;
return cache + (i+j) * glyphSize;
}
}
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;
}
//
// An X wrapper for the t1lib Type 1 font rasterizer.
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
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;
//
// TTFont.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
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;
//
// An X wrapper for the FreeType TrueType font rasterizer.
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// TextOutputDev.cc
//
-// Copyright 1997-2002 Glyph & Cog, LLC
+// Copyright 1997-2003 Glyph & Cog, LLC
//
//========================================================================
#include <stddef.h>
#include <math.h>
#include <ctype.h>
+#ifdef WIN32
+#include <fcntl.h> // for O_BINARY
+#include <io.h> // for setmode
+#endif
#include "gmem.h"
#include "GString.h"
#include "GList.h"
// 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
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) {
++n;
}
}
- avgWidth /= n;
- minSpaceWidth = horizScaling * wordMinSpaceWidth * avgWidth;
- maxSpaceWidth = horizScaling * wordMaxSpaceWidth * avgWidth;
+ if (n > 0) {
+ avgWidth /= n;
+ minSpaceWidth = horizScaling * wordMinSpaceWidth * avgWidth;
+ maxSpaceWidth = horizScaling * wordMaxSpaceWidth * avgWidth;
+ }
}
}
// 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);
xRight[len + i] = word2->xRight[i];
}
len += word2->len;
+ charLen += word2->charLen;
}
//------------------------------------------------------------------------
// Merge another line's words onto the end of this line.
void TextLine::merge(TextLine *line2) {
- TextWord *word;
int newLen, i;
xMax = line2->xMax;
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));
TextPage::TextPage(GBool rawOrderA) {
rawOrder = rawOrderA;
curWord = NULL;
+ charPos = 0;
font = NULL;
fontSize = 0;
nest = 0;
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,
// break words at space character
if (uLen == 1 && u[0] == (Unicode)0x20) {
+ ++curWord->charLen;
+ ++charPos;
endWord();
return;
}
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;
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() {
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;
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;
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;
}
//----- 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));
line1->hyphenated = gTrue;
}
- // insert line on list
- if (line0) {
- line0->next = line1;
- } else {
- lineList = line1;
- }
- line0 = line1;
}
if (uMap) {
}
}
+#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) {
// +------+ +------+ +-----------+
// | blk4 | | blk6 | ... | blk4+blk6 |
// +------+ +------+ +-----------+
+ yLimit = 0; // make gcc happy
if (blkStack) {
yLimit = blkStack->yMax + blkMaxSpacing * blkStack->lines->fontSize;
}
blk0 = blk4;
// push the block on the traversal stack
- blk4->stackNext = blkStack;
- blkStack = blk4;
+ if (!physLayout) {
+ blk4->stackNext = blkStack;
+ blkStack = blk4;
+ }
}
}
} // (!rawOrder)
#endif
}
-// Returns a non-negative number if <word> can be added to <line>
-// (whose last word is <lastWord>). A smaller return value indicates
-// a better fit. If <word> cannot be added to <line> at all, returns
-// a negative number.
-double TextPage::lineFit(TextLine *line, TextWord *lastWord, TextWord *word) {
+// If <word> can be added the end of <line>, return the absolute value
+// of the difference between <line>'s baseline and <word>'s baseline,
+// and set *<space> to the horizontal space between the current last
+// word in <line> and <word>. 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 ||
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;
}
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) {
}
++i;
}
+ if (i == line->len) {
+ continue;
+ }
col = line->col[i];
if (firstCol < 0 || col < firstCol) {
// 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;
}
}
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) {
}
++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)) {
col = firstCol;
multiLine = gTrue;
}
+ prevLine = line;
// line this block up with the correct column
for (; col < line->col[i]; ++col) {
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;
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) {
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() {
deleteGList(fonts, TextFontInfo);
curWord = NULL;
+ charPos = 0;
font = NULL;
fontSize = 0;
nest = 0;
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 {
}
void TextOutputDev::endPage() {
- text->coalesce();
+ text->coalesce(physLayout);
if (outputStream) {
text->dump(outputStream, outputFunc, physLayout);
}
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);
+}
//
// TextOutputDev.h
//
-// Copyright 1997-2002 Glyph & Cog, LLC
+// Copyright 1997-2003 Glyph & Cog, LLC
//
//========================================================================
public:
// Constructor.
- TextWord(GfxState *state, double x0, double y0,
+ TextWord(GfxState *state, double x0, double y0, int charPosA,
TextFontInfo *fontA, double fontSize);
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
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
// Coalesce strings that look like parts of the same line.
- void coalesce();
+ void coalesce(GBool physLayout);
// Find a string. If <top> is true, starts looking at top of page;
// otherwise starts looking at <xMin>,<yMin>. If <bottom> is true,
// stops looking at bottom of page; otherwise stops looking at
- // <xMax>,<yMax>. If found, sets the text bounding rectange and
+ // <xMax>,<yMax>. If found, sets the text bounding rectangle and
// returns true; otherwise returns false.
GBool findText(Unicode *s, int len,
GBool top, GBool bottom,
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);
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);
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)
// Find a string. If <top> is true, starts looking at top of page;
// otherwise starts looking at <xMin>,<yMin>. If <bottom> is true,
// stops looking at bottom of page; otherwise stops looking at
- // <xMax>,<yMax>. If found, sets the text bounding rectange and
+ // <xMax>,<yMax>. If found, sets the text bounding rectangle and
// returns true; otherwise returns false.
GBool findText(Unicode *s, int len,
GBool top, GBool bottom,
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:
//
// UnicodeMap.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// Mapping from Unicode to an encoding.
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// XOutputDev.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
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
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)
return NULL;
}
ff = new Type1CFontFile(fontBuf, fontLen);
+ if (!ff->isOk()) {
+ delete ff;
+ gfree(fontBuf);
+ return NULL;
+ }
ff->convertToType1(outputToFile, f);
delete ff;
gfree(fontBuf);
// 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
} 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;
double m22Orig,
double m11, double m12,
double m21, double m22,
+ GBool embedded,
GBool subst) {
Ref *id;
FTFontFile *fontFile;
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'",
// set up the font cache and fonts
gfxFont = NULL;
font = NULL;
+ needFontUpdate = gFalse;
fontCache = new XOutputFontCache(display, depth, this,
globalParams->getT1libControl(),
globalParams->getFreeTypeControl());
void XOutputDev::endPage() {
XOutputState *s;
- text->coalesce();
+ text->coalesce(gTrue);
// clear state stack, free all GCs, free the clip region
while (save) {
save = save->next;
delete s;
- // restore the font
- updateFont(state);
+ // we'll need to restore the font
+ needFontUpdate = gTrue;
}
}
updateMiterLimit(state);
updateFillColor(state);
updateStrokeColor(state);
- updateFont(state);
+ needFontUpdate = gTrue;
}
void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
void XOutputDev::updateFont(GfxState *state) {
double m11, m12, m21, m22;
+ needFontUpdate = gFalse;
+
text->updateFont(state);
if (!(gfxFont = state->getFont())) {
double *ctm;
double saveCTM[6];
+ if (needFontUpdate) {
+ updateFont(state);
+ }
+
text->addChar(state, x, y, dx, dy, code, u, uLen);
if (!font) {
double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
int i, j;
+ if (needFontUpdate) {
+ updateFont(state);
+ }
if (!gfxFont) {
return gFalse;
}
//
// XOutputDev.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
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,
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];
//
// XRef.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
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;
}
//
// XRef.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//
// pdffonts.cc
//
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//
// pdfimages.cc
//
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
//
//========================================================================
//
// pdfinfo.cc
//
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
//
//========================================================================
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;
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");
}
//
// pdftopbm.cc
//
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
//
//========================================================================
//
// pdftops.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
{"-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,
if (paperSize[0]) {
if (!globalParams->setPSPaperSize(paperSize)) {
fprintf(stderr, "Invalid paper size\n");
+ delete fileName;
goto err0;
}
} else {
delete psFileName;
err1:
delete doc;
- delete globalParams;
err0:
+ delete globalParams;
// check for memory leaks
Object::memCheck(stderr);
//
// pdftotext.cc
//
-// Copyright 1997-2002 Glyph & Cog, LLC
+// Copyright 1997-2003 Glyph & Cog, LLC
//
//========================================================================
$!
$! Written by Patrick Moreau, Martin P.J. Zinser.
$!
-$! Copyright 1996-2002 Glyph & Cog, LLC
+$! Copyright 1996-2003 Glyph & Cog, LLC
$!
$!========================================================================
$!
$!
$ 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"
//
// xpdf.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
{"-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,
//
// config.h
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
//------------------------------------------------------------------------
// 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