diff options
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-3.04/fofi/FoFiIdentifier.cc')
-rw-r--r-- | Build/source/libs/xpdf/xpdf-3.04/fofi/FoFiIdentifier.cc | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/Build/source/libs/xpdf/xpdf-3.04/fofi/FoFiIdentifier.cc b/Build/source/libs/xpdf/xpdf-3.04/fofi/FoFiIdentifier.cc new file mode 100644 index 00000000000..978cc700ee3 --- /dev/null +++ b/Build/source/libs/xpdf/xpdf-3.04/fofi/FoFiIdentifier.cc @@ -0,0 +1,887 @@ +//======================================================================== +// +// FoFiIdentifier.cc +// +// Copyright 2009 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include "gtypes.h" +#include "gmem.h" +#include "GString.h" +#include "GList.h" +#include "FoFiIdentifier.h" + +//------------------------------------------------------------------------ + +class Reader { +public: + + virtual ~Reader() {} + + // Read one byte. Returns -1 if past EOF. + virtual int getByte(int pos) = 0; + + // Read a big-endian unsigned 16-bit integer. Fills in *val and + // returns true if successful. + virtual GBool getU16BE(int pos, int *val) = 0; + + // Read a big-endian unsigned 32-bit integer. Fills in *val and + // returns true if successful. + virtual GBool getU32BE(int pos, Guint *val) = 0; + + // Read a little-endian unsigned 32-bit integer. Fills in *val and + // returns true if successful. + virtual GBool getU32LE(int pos, Guint *val) = 0; + + // Read a big-endian unsigned <size>-byte integer, where 1 <= size + // <= 4. Fills in *val and returns true if successful. + virtual GBool getUVarBE(int pos, int size, Guint *val) = 0; + + // Compare against a string. Returns true if equal. + virtual GBool cmp(int pos, const char *s) = 0; + +}; + +//------------------------------------------------------------------------ + +class MemReader: public Reader { +public: + + static MemReader *make(char *bufA, int lenA); + virtual ~MemReader(); + virtual int getByte(int pos); + virtual GBool getU16BE(int pos, int *val); + virtual GBool getU32BE(int pos, Guint *val); + virtual GBool getU32LE(int pos, Guint *val); + virtual GBool getUVarBE(int pos, int size, Guint *val); + virtual GBool cmp(int pos, const char *s); + +private: + + MemReader(char *bufA, int lenA); + + char *buf; + int len; +}; + +MemReader *MemReader::make(char *bufA, int lenA) { + return new MemReader(bufA, lenA); +} + +MemReader::MemReader(char *bufA, int lenA) { + buf = bufA; + len = lenA; +} + +MemReader::~MemReader() { +} + +int MemReader::getByte(int pos) { + if (pos < 0 || pos >= len) { + return -1; + } + return buf[pos] & 0xff; +} + +GBool MemReader::getU16BE(int pos, int *val) { + if (pos < 0 || pos > len - 2) { + return gFalse; + } + *val = ((buf[pos] & 0xff) << 8) + + (buf[pos+1] & 0xff); + return gTrue; +} + +GBool MemReader::getU32BE(int pos, Guint *val) { + if (pos < 0 || pos > len - 4) { + return gFalse; + } + *val = ((buf[pos] & 0xff) << 24) + + ((buf[pos+1] & 0xff) << 16) + + ((buf[pos+2] & 0xff) << 8) + + (buf[pos+3] & 0xff); + return gTrue; +} + +GBool MemReader::getU32LE(int pos, Guint *val) { + if (pos < 0 || pos > len - 4) { + return gFalse; + } + *val = (buf[pos] & 0xff) + + ((buf[pos+1] & 0xff) << 8) + + ((buf[pos+2] & 0xff) << 16) + + ((buf[pos+3] & 0xff) << 24); + return gTrue; +} + +GBool MemReader::getUVarBE(int pos, int size, Guint *val) { + int i; + + if (size < 1 || size > 4 || pos < 0 || pos > len - size) { + return gFalse; + } + *val = 0; + for (i = 0; i < size; ++i) { + *val = (*val << 8) + (buf[pos + i] & 0xff); + } + return gTrue; +} + +GBool MemReader::cmp(int pos, const char *s) { + int n; + + n = (int)strlen(s); + if (pos < 0 || len < n || pos > len - n) { + return gFalse; + } + return !memcmp(buf + pos, s, n); +} + +//------------------------------------------------------------------------ + +class FileReader: public Reader { +public: + + static FileReader *make(char *fileName); + virtual ~FileReader(); + virtual int getByte(int pos); + virtual GBool getU16BE(int pos, int *val); + virtual GBool getU32BE(int pos, Guint *val); + virtual GBool getU32LE(int pos, Guint *val); + virtual GBool getUVarBE(int pos, int size, Guint *val); + virtual GBool cmp(int pos, const char *s); + +private: + + FileReader(FILE *fA); + GBool fillBuf(int pos, int len); + + FILE *f; + char buf[1024]; + int bufPos, bufLen; +}; + +FileReader *FileReader::make(char *fileName) { + FILE *fA; + + if (!(fA = fopen(fileName, "rb"))) { + return NULL; + } + return new FileReader(fA); +} + +FileReader::FileReader(FILE *fA) { + f = fA; + bufPos = 0; + bufLen = 0; +} + +FileReader::~FileReader() { + fclose(f); +} + +int FileReader::getByte(int pos) { + if (!fillBuf(pos, 1)) { + return -1; + } + return buf[pos - bufPos] & 0xff; +} + +GBool FileReader::getU16BE(int pos, int *val) { + if (!fillBuf(pos, 2)) { + return gFalse; + } + *val = ((buf[pos - bufPos] & 0xff) << 8) + + (buf[pos - bufPos + 1] & 0xff); + return gTrue; +} + +GBool FileReader::getU32BE(int pos, Guint *val) { + if (!fillBuf(pos, 4)) { + return gFalse; + } + *val = ((buf[pos - bufPos] & 0xff) << 24) + + ((buf[pos - bufPos + 1] & 0xff) << 16) + + ((buf[pos - bufPos + 2] & 0xff) << 8) + + (buf[pos - bufPos + 3] & 0xff); + return gTrue; +} + +GBool FileReader::getU32LE(int pos, Guint *val) { + if (!fillBuf(pos, 4)) { + return gFalse; + } + *val = (buf[pos - bufPos] & 0xff) + + ((buf[pos - bufPos + 1] & 0xff) << 8) + + ((buf[pos - bufPos + 2] & 0xff) << 16) + + ((buf[pos - bufPos + 3] & 0xff) << 24); + return gTrue; +} + +GBool FileReader::getUVarBE(int pos, int size, Guint *val) { + int i; + + if (size < 1 || size > 4 || !fillBuf(pos, size)) { + return gFalse; + } + *val = 0; + for (i = 0; i < size; ++i) { + *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff); + } + return gTrue; +} + +GBool FileReader::cmp(int pos, const char *s) { + int n; + + n = (int)strlen(s); + if (!fillBuf(pos, n)) { + return gFalse; + } + return !memcmp(buf - bufPos + pos, s, n); +} + +GBool FileReader::fillBuf(int pos, int len) { + if (pos < 0 || len < 0 || len > (int)sizeof(buf) || + pos > INT_MAX - (int)sizeof(buf)) { + return gFalse; + } + if (pos >= bufPos && pos + len <= bufPos + bufLen) { + return gTrue; + } + if (fseek(f, pos, SEEK_SET)) { + return gFalse; + } + bufPos = pos; + bufLen = (int)fread(buf, 1, sizeof(buf), f); + if (bufLen < len) { + return gFalse; + } + return gTrue; +} + +//------------------------------------------------------------------------ + +class StreamReader: public Reader { +public: + + static StreamReader *make(int (*getCharA)(void *data), void *dataA); + virtual ~StreamReader(); + virtual int getByte(int pos); + virtual GBool getU16BE(int pos, int *val); + virtual GBool getU32BE(int pos, Guint *val); + virtual GBool getU32LE(int pos, Guint *val); + virtual GBool getUVarBE(int pos, int size, Guint *val); + virtual GBool cmp(int pos, const char *s); + +private: + + StreamReader(int (*getCharA)(void *data), void *dataA); + GBool fillBuf(int pos, int len); + + int (*getChar)(void *data); + void *data; + int streamPos; + char buf[1024]; + int bufPos, bufLen; +}; + +StreamReader *StreamReader::make(int (*getCharA)(void *data), void *dataA) { + return new StreamReader(getCharA, dataA); +} + +StreamReader::StreamReader(int (*getCharA)(void *data), void *dataA) { + getChar = getCharA; + data = dataA; + streamPos = 0; + bufPos = 0; + bufLen = 0; +} + +StreamReader::~StreamReader() { +} + +int StreamReader::getByte(int pos) { + if (!fillBuf(pos, 1)) { + return -1; + } + return buf[pos - bufPos] & 0xff; +} + +GBool StreamReader::getU16BE(int pos, int *val) { + if (!fillBuf(pos, 2)) { + return gFalse; + } + *val = ((buf[pos - bufPos] & 0xff) << 8) + + (buf[pos - bufPos + 1] & 0xff); + return gTrue; +} + +GBool StreamReader::getU32BE(int pos, Guint *val) { + if (!fillBuf(pos, 4)) { + return gFalse; + } + *val = ((buf[pos - bufPos] & 0xff) << 24) + + ((buf[pos - bufPos + 1] & 0xff) << 16) + + ((buf[pos - bufPos + 2] & 0xff) << 8) + + (buf[pos - bufPos + 3] & 0xff); + return gTrue; +} + +GBool StreamReader::getU32LE(int pos, Guint *val) { + if (!fillBuf(pos, 4)) { + return gFalse; + } + *val = (buf[pos - bufPos] & 0xff) + + ((buf[pos - bufPos + 1] & 0xff) << 8) + + ((buf[pos - bufPos + 2] & 0xff) << 16) + + ((buf[pos - bufPos + 3] & 0xff) << 24); + return gTrue; +} + +GBool StreamReader::getUVarBE(int pos, int size, Guint *val) { + int i; + + if (size < 1 || size > 4 || !fillBuf(pos, size)) { + return gFalse; + } + *val = 0; + for (i = 0; i < size; ++i) { + *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff); + } + return gTrue; +} + +GBool StreamReader::cmp(int pos, const char *s) { + int n; + + n = (int)strlen(s); + if (!fillBuf(pos, n)) { + return gFalse; + } + return !memcmp(buf - bufPos + pos, s, n); +} + +GBool StreamReader::fillBuf(int pos, int len) { + int c; + + if (pos < 0 || len < 0 || len > (int)sizeof(buf) || + pos > INT_MAX - (int)sizeof(buf)) { + return gFalse; + } + if (pos < bufPos) { + return gFalse; + } + + // if requested region will not fit in the current buffer... + if (pos + len > bufPos + (int)sizeof(buf)) { + + // if the start of the requested data is already in the buffer, move + // it to the start of the buffer + if (pos < bufPos + bufLen) { + bufLen -= pos - bufPos; + memmove(buf, buf + (pos - bufPos), bufLen); + bufPos = pos; + + // otherwise discard data from the + // stream until we get to the requested position + } else { + bufPos += bufLen; + bufLen = 0; + while (bufPos < pos) { + if ((c = (*getChar)(data)) < 0) { + return gFalse; + } + ++bufPos; + } + } + } + + // read the rest of the requested data + while (bufPos + bufLen < pos + len) { + if ((c = (*getChar)(data)) < 0) { + return gFalse; + } + buf[bufLen++] = (char)c; + } + + return gTrue; +} + +//------------------------------------------------------------------------ + +static FoFiIdentifierType identify(Reader *reader); +static FoFiIdentifierType identifyOpenType(Reader *reader); +static FoFiIdentifierType identifyCFF(Reader *reader, int start); + +FoFiIdentifierType FoFiIdentifier::identifyMem(char *file, int len) { + MemReader *reader; + FoFiIdentifierType type; + + if (!(reader = MemReader::make(file, len))) { + return fofiIdError; + } + type = identify(reader); + delete reader; + return type; +} + +FoFiIdentifierType FoFiIdentifier::identifyFile(char *fileName) { + FileReader *reader; + FoFiIdentifierType type; + int n; + + if (!(reader = FileReader::make(fileName))) { + return fofiIdError; + } + type = identify(reader); + delete reader; + + // Mac OS X dfont files don't have any sort of header or magic number, + // so look at the file name extension + if (type == fofiIdUnknown) { + n = (int)strlen(fileName); + if (n >= 6 && !strcmp(fileName + n - 6, ".dfont")) { + type = fofiIdDfont; + } + } + + return type; +} + +FoFiIdentifierType FoFiIdentifier::identifyStream(int (*getChar)(void *data), + void *data) { + StreamReader *reader; + FoFiIdentifierType type; + + if (!(reader = StreamReader::make(getChar, data))) { + return fofiIdError; + } + type = identify(reader); + delete reader; + return type; +} + +static FoFiIdentifierType identify(Reader *reader) { + Guint n; + + //----- PFA + if (reader->cmp(0, "%!PS-AdobeFont-1") || + reader->cmp(0, "%!FontType1")) { + return fofiIdType1PFA; + } + + //----- PFB + if (reader->getByte(0) == 0x80 && + reader->getByte(1) == 0x01 && + reader->getU32LE(2, &n)) { + if ((n >= 16 && reader->cmp(6, "%!PS-AdobeFont-1")) || + (n >= 11 && reader->cmp(6, "%!FontType1"))) { + return fofiIdType1PFB; + } + } + + //----- TrueType + if ((reader->getByte(0) == 0x00 && + reader->getByte(1) == 0x01 && + reader->getByte(2) == 0x00 && + reader->getByte(3) == 0x00) || + (reader->getByte(0) == 0x74 && // 'true' + reader->getByte(1) == 0x72 && + reader->getByte(2) == 0x75 && + reader->getByte(3) == 0x65)) { + return fofiIdTrueType; + } + if (reader->getByte(0) == 0x74 && // 'ttcf' + reader->getByte(1) == 0x74 && + reader->getByte(2) == 0x63 && + reader->getByte(3) == 0x66) { + return fofiIdTrueTypeCollection; + } + + //----- OpenType + if (reader->getByte(0) == 0x4f && // 'OTTO + reader->getByte(1) == 0x54 && + reader->getByte(2) == 0x54 && + reader->getByte(3) == 0x4f) { + return identifyOpenType(reader); + } + + //----- CFF + if (reader->getByte(0) == 0x01 && + reader->getByte(1) == 0x00) { + return identifyCFF(reader, 0); + } + // some tools embed CFF fonts with an extra whitespace char at the + // beginning + if (reader->getByte(1) == 0x01 && + reader->getByte(2) == 0x00) { + return identifyCFF(reader, 1); + } + + return fofiIdUnknown; +} + +static FoFiIdentifierType identifyOpenType(Reader *reader) { + FoFiIdentifierType type; + Guint offset; + int nTables, i; + + if (!reader->getU16BE(4, &nTables)) { + return fofiIdUnknown; + } + for (i = 0; i < nTables; ++i) { + if (reader->cmp(12 + i*16, "CFF ")) { + if (reader->getU32BE(12 + i*16 + 8, &offset) && + offset < (Guint)INT_MAX) { + type = identifyCFF(reader, (int)offset); + if (type == fofiIdCFF8Bit) { + type = fofiIdOpenTypeCFF8Bit; + } else if (type == fofiIdCFFCID) { + type = fofiIdOpenTypeCFFCID; + } + return type; + } + return fofiIdUnknown; + } + } + return fofiIdUnknown; +} + +static FoFiIdentifierType identifyCFF(Reader *reader, int start) { + Guint offset0, offset1; + int hdrSize, offSize0, offSize1, pos, endPos, b0, n, i; + + //----- read the header + if (reader->getByte(start) != 0x01 || + reader->getByte(start + 1) != 0x00) { + return fofiIdUnknown; + } + if ((hdrSize = reader->getByte(start + 2)) < 0) { + return fofiIdUnknown; + } + if ((offSize0 = reader->getByte(start + 3)) < 1 || offSize0 > 4) { + return fofiIdUnknown; + } + pos = start + hdrSize; + if (pos < 0) { + return fofiIdUnknown; + } + + //----- skip the name index + if (!reader->getU16BE(pos, &n)) { + return fofiIdUnknown; + } + if (n == 0) { + pos += 2; + } else { + if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) { + return fofiIdUnknown; + } + if (!reader->getUVarBE(pos + 3 + n * offSize1, offSize1, &offset1) || + offset1 > (Guint)INT_MAX) { + return fofiIdUnknown; + } + pos += 3 + (n + 1) * offSize1 + (int)offset1 - 1; + } + if (pos < 0) { + return fofiIdUnknown; + } + + //----- parse the top dict index + if (!reader->getU16BE(pos, &n) || n < 1) { + return fofiIdUnknown; + } + if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) { + return fofiIdUnknown; + } + if (!reader->getUVarBE(pos + 3, offSize1, &offset0) || + offset0 > (Guint)INT_MAX || + !reader->getUVarBE(pos + 3 + offSize1, offSize1, &offset1) || + offset1 > (Guint)INT_MAX || + offset0 > offset1) { + return fofiIdUnknown; + } + pos = pos + 3 + (n + 1) * offSize1 + (int)offset0 - 1; + endPos = pos + 3 + (n + 1) * offSize1 + (int)offset1 - 1; + if (pos < 0 || endPos < 0 || pos > endPos) { + return fofiIdUnknown; + } + + //----- parse the top dict, look for ROS as first entry + // for a CID font, the top dict starts with: + // <int> <int> <int> ROS + for (i = 0; i < 3; ++i) { + b0 = reader->getByte(pos++); + if (b0 == 0x1c) { + pos += 2; + } else if (b0 == 0x1d) { + pos += 4; + } else if (b0 >= 0xf7 && b0 <= 0xfe) { + pos += 1; + } else if (b0 < 0x20 || b0 > 0xf6) { + return fofiIdCFF8Bit; + } + if (pos >= endPos || pos < 0) { + return fofiIdCFF8Bit; + } + } + if (pos + 1 < endPos && + reader->getByte(pos) == 12 && + reader->getByte(pos + 1) == 30) { + return fofiIdCFFCID; + } else { + return fofiIdCFF8Bit; + } +} + +//------------------------------------------------------------------------ + +static GList *getTTCFontList(FILE *f); +static GList *getDfontFontList(FILE *f); + +GList *FoFiIdentifier::getFontList(char *fileName) { + FILE *f; + char buf[4]; + GList *ret; + + if (!(f = fopen(fileName, "rb"))) { + return NULL; + } + if (fread(buf, 1, 4, f) == 4 && + buf[0] == 0x74 && // 'ttcf' + buf[1] == 0x74 && + buf[2] == 0x63 && + buf[3] == 0x66) { + ret = getTTCFontList(f); + } else { + ret = getDfontFontList(f); + } + fclose(f); + return ret; +} + +static GList *getTTCFontList(FILE *f) { + Guchar buf[12]; + Guchar *buf2; + int fileLength, nFonts; + int tabDirOffset, nTables, nameTabOffset, nNames, stringsOffset; + int stringPlatform, stringLength, stringOffset; + GBool stringUnicode; + int i, j; + GList *ret; + + fseek(f, 0, SEEK_END); + fileLength = (int)ftell(f); + if (fileLength < 0) { + goto err1; + } + fseek(f, 8, SEEK_SET); + if (fread(buf, 1, 4, f) != 4) { + goto err1; + } + nFonts = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + if (nFonts < 0 || + 12 + 4 * nFonts > fileLength) { + goto err1; + } + ret = new GList(); + for (i = 0; i < nFonts; ++i) { + fseek(f, 12 + 4 * i, SEEK_SET); + if (fread(buf, 1, 4, f) != 4) { + goto err2; + } + tabDirOffset = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + if (tabDirOffset < 0 || + tabDirOffset + 12 < 0 || + tabDirOffset + 12 > fileLength) { + goto err2; + } + fseek(f, tabDirOffset, SEEK_SET); + if (fread(buf, 1, 12, f) != 12) { + goto err2; + } + nTables = (buf[4] << 8) | buf[5]; + if (tabDirOffset + 12 + 16 * nTables < 0 || + tabDirOffset + 12 + 16 * nTables > fileLength) { + goto err2; + } + buf2 = (Guchar *)gmallocn(nTables, 16); + if ((int)fread(buf2, 1, 16 * nTables, f) != 16 * nTables) { + goto err3; + } + nameTabOffset = 0; // make gcc happy + for (j = 0; j < nTables; ++j) { + if (buf2[16*j + 0] == 'n' && + buf2[16*j + 1] == 'a' && + buf2[16*j + 2] == 'm' && + buf2[16*j + 3] == 'e') { + nameTabOffset = (buf2[16*j + 8] << 24) | (buf2[16*j + 9] << 16) | + (buf2[16*j + 10] << 8) | buf2[16*j + 11]; + break; + } + } + gfree(buf2); + if (j >= nTables) { + goto err2; + } + if (nameTabOffset < 0 || + nameTabOffset + 6 < 0 || + nameTabOffset + 6 > fileLength) { + goto err2; + } + fseek(f, nameTabOffset, SEEK_SET); + if (fread(buf, 1, 6, f) != 6) { + goto err2; + } + nNames = (buf[2] << 8) | buf[3]; + stringsOffset = (buf[4] << 8) | buf[5]; + if (nameTabOffset + 6 + 12 * nNames < 0 || + nameTabOffset + 6 + 12 * nNames > fileLength || + nameTabOffset + stringsOffset < 0) { + goto err2; + } + buf2 = (Guchar *)gmallocn(nNames, 12); + if ((int)fread(buf2, 1, 12 * nNames, f) != 12 * nNames) { + goto err3; + } + for (j = 0; j < nNames; ++j) { + if (buf2[12*j + 6] == 0 && // 0x0004 = full name + buf2[12*j + 7] == 4) { + break; + } + } + if (j >= nNames) { + goto err3; + } + stringPlatform = (buf2[12*j] << 8) | buf2[12*j + 1]; + // stringEncoding = (buf2[12*j + 2] << 8) | buf2[12*j + 3]; + stringUnicode = stringPlatform == 0 || stringPlatform == 3; + stringLength = (buf2[12*j + 8] << 8) | buf2[12*j + 9]; + stringOffset = nameTabOffset + stringsOffset + + ((buf2[12*j + 10] << 8) | buf2[12*j + 11]); + gfree(buf2); + if (stringOffset < 0 || + stringOffset + stringLength < 0 || + stringOffset + stringLength > fileLength) { + goto err2; + } + buf2 = (Guchar *)gmalloc(stringLength); + fseek(f, stringOffset, SEEK_SET); + if ((int)fread(buf2, 1, stringLength, f) != stringLength) { + goto err3; + } + if (stringUnicode) { + stringLength /= 2; + for (j = 0; j < stringLength; ++j) { + buf2[j] = buf2[2*j + 1]; + } + } + ret->append(new GString((char *)buf2, stringLength)); + gfree(buf2); + } + return ret; + + err3: + gfree(buf2); + err2: + deleteGList(ret, GString); + err1: + return NULL; +} + +static GList *getDfontFontList(FILE *f) { + Guchar buf[16]; + Guchar *resMap; + int fileLength, resMapOffset, resMapLength; + int resTypeListOffset, resNameListOffset, nTypes; + int refListOffset, nFonts, nameOffset, nameLen; + int offset, i; + GList *ret; + + fseek(f, 0, SEEK_END); + fileLength = (int)ftell(f); + if (fileLength < 0) { + goto err1; + } + fseek(f, 0, SEEK_SET); + if (fread((char *)buf, 1, 16, f) != 16) { + goto err1; + } + resMapOffset = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; + resMapLength = (buf[12] << 24) | (buf[13] << 16) | (buf[14] << 8) | buf[15]; + if (resMapOffset < 0 || + resMapOffset >= fileLength || + resMapLength < 0 || + resMapOffset + resMapLength > fileLength || + resMapOffset + resMapLength < 0) { + goto err1; + } + if (resMapLength > 32768) { + // sanity check - this probably isn't a dfont file + goto err1; + } + resMap = (Guchar *)gmalloc(resMapLength); + fseek(f, resMapOffset, SEEK_SET); + if ((int)fread((char *)resMap, 1, resMapLength, f) != resMapLength) { + goto err2; + } + resTypeListOffset = (resMap[24] << 8) | resMap[25]; + resNameListOffset = (resMap[26] << 8) | resMap[27]; + nTypes = ((resMap[28] << 8) | resMap[29]) + 1; + if (resTypeListOffset + 2 + nTypes * 8 > resMapLength || + resNameListOffset >= resMapLength) { + goto err2; + } + for (i = 0; i < nTypes; ++i) { + offset = resTypeListOffset + 2 + 8 * i; + if (resMap[offset] == 0x73 && // 'sfnt' + resMap[offset+1] == 0x66 && + resMap[offset+2] == 0x6e && + resMap[offset+3] == 0x74) { + nFonts = ((resMap[offset+4] << 8) | resMap[offset+5]) + 1; + refListOffset = (resMap[offset+6] << 8) | resMap[offset+7]; + break; + } + } + if (i >= nTypes) { + goto err2; + } + if (resTypeListOffset + refListOffset >= resMapLength || + resTypeListOffset + refListOffset + nFonts * 12 > resMapLength) { + goto err2; + } + ret = new GList(); + for (i = 0; i < nFonts; ++i) { + offset = resTypeListOffset + refListOffset + 12 * i; + nameOffset = (resMap[offset+2] << 8) | resMap[offset+3]; + offset = resNameListOffset + nameOffset; + if (offset >= resMapLength) { + goto err3; + } + nameLen = resMap[offset]; + if (offset + 1 + nameLen > resMapLength) { + goto err3; + } + ret->append(new GString((char *)resMap + offset + 1, nameLen)); + } + gfree(resMap); + return ret; + + err3: + deleteGList(ret, GString); + err2: + gfree(resMap); + err1: + return NULL; +} |