summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gui/text/qfontengine.cpp212
-rw-r--r--src/gui/text/qfontengine_p.h2
-rw-r--r--src/gui/text/qfontengine_qpf2.cpp10
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp16
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.h1
5 files changed, 176 insertions, 65 deletions
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index b360ed5c85..f973abc8e4 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -74,6 +74,16 @@ static inline bool qtransform_equals_no_translate(const QTransform &a, const QTr
}
}
+template<typename T>
+static inline bool qSafeFromBigEndian(const uchar *source, const uchar *end, T *output)
+{
+ if (source + sizeof(T) > end)
+ return false;
+
+ *output = qFromBigEndian<T>(source);
+ return true;
+}
+
// Harfbuzz helper functions
#ifdef QT_ENABLE_HARFBUZZ_NG
@@ -1044,26 +1054,38 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
return;
const uchar *table = reinterpret_cast<const uchar *>(tab.constData());
+ const uchar *end = table + tab.size();
+
+ quint16 version;
+ if (!qSafeFromBigEndian(table, end, &version))
+ return;
- unsigned short version = qFromBigEndian<quint16>(table);
if (version != 0) {
// qDebug("wrong version");
return;
}
- unsigned short numTables = qFromBigEndian<quint16>(table + 2);
+ quint16 numTables;
+ if (!qSafeFromBigEndian(table + 2, end, &numTables))
+ return;
+
{
int offset = 4;
for(int i = 0; i < numTables; ++i) {
- if (offset + 6 > tab.size()) {
-// qDebug("offset out of bounds");
- goto end;
- }
const uchar *header = table + offset;
- ushort version = qFromBigEndian<quint16>(header);
- ushort length = qFromBigEndian<quint16>(header+2);
- ushort coverage = qFromBigEndian<quint16>(header+4);
+ quint16 version;
+ if (!qSafeFromBigEndian(header, end, &version))
+ goto end;
+
+ quint16 length;
+ if (!qSafeFromBigEndian(header + 2, end, &length))
+ goto end;
+
+ quint16 coverage;
+ if (!qSafeFromBigEndian(header + 4, end, &coverage))
+ goto end;
+
// qDebug("subtable: version=%d, coverage=%x",version, coverage);
if(version == 0 && coverage == 0x0001) {
if (offset + length > tab.size()) {
@@ -1072,7 +1094,10 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
}
const uchar *data = table + offset + 6;
- ushort nPairs = qFromBigEndian<quint16>(data);
+ quint16 nPairs;
+ if (!qSafeFromBigEndian(data, end, &nPairs))
+ goto end;
+
if(nPairs * 6 + 8 > length - 6) {
// qDebug("corrupt table!");
// corrupt table
@@ -1082,8 +1107,21 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
int off = 8;
for(int i = 0; i < nPairs; ++i) {
QFontEngine::KernPair p;
- p.left_right = (((uint)qFromBigEndian<quint16>(data+off)) << 16) + qFromBigEndian<quint16>(data+off+2);
- p.adjust = QFixed(((int)(short)qFromBigEndian<quint16>(data+off+4))) / scalingFactor;
+
+ quint16 tmp;
+ if (!qSafeFromBigEndian(data + off, end, &tmp))
+ goto end;
+
+ p.left_right = uint(tmp) << 16;
+ if (!qSafeFromBigEndian(data + off + 2, end, &tmp))
+ goto end;
+
+ p.left_right |= tmp;
+
+ if (!qSafeFromBigEndian(data + off + 4, end, &tmp))
+ goto end;
+
+ p.adjust = QFixed(int(short(tmp))) / scalingFactor;
kerning_pairs.append(p);
off += 6;
}
@@ -1103,26 +1141,31 @@ int QFontEngine::glyphCount() const
QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
if (maxpTable.size() < 6)
return 0;
- return qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(maxpTable.constData() + 4));
+
+ const uchar *source = reinterpret_cast<const uchar *>(maxpTable.constData() + 4);
+ const uchar *end = source + maxpTable.size();
+
+ quint16 count = 0;
+ qSafeFromBigEndian(source, end, &count);
+ return count;
}
const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
{
const uchar *header = table;
- if (tableSize < 4)
- return 0;
-
const uchar *endPtr = table + tableSize;
// version check
- if (qFromBigEndian<quint16>(header) != 0)
+ quint16 version;
+ if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0)
return 0;
- unsigned short numTables = qFromBigEndian<quint16>(header + 2);
- const uchar *maps = table + 4;
- if (maps + 8 * numTables > endPtr)
+ quint16 numTables;
+ if (!qSafeFromBigEndian(header + 2, endPtr, &numTables))
return 0;
+ const uchar *maps = table + 4;
+
enum {
Invalid,
AppleRoman,
@@ -1137,8 +1180,14 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
int tableToUse = -1;
int score = Invalid;
for (int n = 0; n < numTables; ++n) {
- const quint16 platformId = qFromBigEndian<quint16>(maps + 8 * n);
- const quint16 platformSpecificId = qFromBigEndian<quint16>(maps + 8 * n + 2);
+ quint16 platformId;
+ if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
+ return 0;
+
+ quint16 platformSpecificId;
+ if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId))
+ return 0;
+
switch (platformId) {
case 0: // Unicode
if (score < Unicode &&
@@ -1192,20 +1241,30 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
resolveTable:
*isSymbolFont = (symbolTable > -1);
- unsigned int unicode_table = qFromBigEndian<quint32>(maps + 8*tableToUse + 4);
+ quint32 unicode_table;
+ if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table))
+ return 0;
- if (!unicode_table || unicode_table + 8 > tableSize)
+ if (!unicode_table)
return 0;
// get the header of the unicode table
header = table + unicode_table;
- unsigned short format = qFromBigEndian<quint16>(header);
- unsigned int length;
- if(format < 8)
- length = qFromBigEndian<quint16>(header + 2);
- else
- length = qFromBigEndian<quint32>(header + 4);
+ quint16 format;
+ if (!qSafeFromBigEndian(header, endPtr, &format))
+ return 0;
+
+ quint32 length;
+ if (format < 8) {
+ quint16 tmp;
+ if (!qSafeFromBigEndian(header + 2, endPtr, &tmp))
+ return 0;
+ length = tmp;
+ } else {
+ if (!qSafeFromBigEndian(header + 4, endPtr, &length))
+ return 0;
+ }
if (table + unicode_table + length > endPtr)
return 0;
@@ -1220,7 +1279,7 @@ resolveTable:
// Check that none of the latin1 range are in the unicode table
bool unicodeTableHasLatin1 = false;
for (int uc=0x00; uc<0x100; ++uc) {
- if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) {
+ if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
unicodeTableHasLatin1 = true;
break;
}
@@ -1230,7 +1289,7 @@ resolveTable:
bool unicodeTableHasSymbols = false;
if (!unicodeTableHasLatin1) {
for (int uc=0xf000; uc<0xf100; ++uc) {
- if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) {
+ if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
unicodeTableHasSymbols = true;
break;
}
@@ -1248,12 +1307,17 @@ resolveTable:
return table + unicode_table;
}
-quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
+quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
{
- unsigned short format = qFromBigEndian<quint16>(cmap);
+ const uchar *end = cmap + cmapSize;
+ quint16 format;
+ if (!qSafeFromBigEndian(cmap, end, &format))
+ return 0;
+
if (format == 0) {
- if (unicode < 256)
- return (int) *(cmap+6+unicode);
+ const uchar *ptr = cmap + 6 + unicode;
+ if (unicode < 256 && ptr < end)
+ return quint32(*ptr);
} else if (format == 4) {
/* some fonts come with invalid cmap tables, where the last segment
specified end = start = rangeoffset = 0xffff, delta = 0x0001
@@ -1262,25 +1326,49 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
*/
if(unicode >= 0xffff)
return 0;
- quint16 segCountX2 = qFromBigEndian<quint16>(cmap + 6);
+
+ quint16 segCountX2;
+ if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))
+ return 0;
+
const unsigned char *ends = cmap + 14;
+
int i = 0;
- for (; i < segCountX2/2 && qFromBigEndian<quint16>(ends + 2*i) < unicode; i++) {}
+ for (; i < segCountX2/2; ++i) {
+ quint16 codePoint;
+ if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))
+ return 0;
+ if (codePoint >= unicode)
+ break;
+ }
const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
- quint16 startIndex = qFromBigEndian<quint16>(idx);
+ quint16 startIndex;
+ if (!qSafeFromBigEndian(idx, end, &startIndex))
+ return 0;
if (startIndex > unicode)
return 0;
idx += segCountX2;
- qint16 idDelta = (qint16)qFromBigEndian<quint16>(idx);
+
+ quint16 tmp;
+ if (!qSafeFromBigEndian(idx, end, &tmp))
+ return 0;
+ qint16 idDelta = qint16(tmp);
+
idx += segCountX2;
- quint16 idRangeoffset_t = (quint16)qFromBigEndian<quint16>(idx);
+
+ quint16 idRangeoffset_t;
+ if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))
+ return 0;
quint16 glyphIndex;
if (idRangeoffset_t) {
- quint16 id = qFromBigEndian<quint16>(idRangeoffset_t + 2*(unicode - startIndex) + idx);
+ quint16 id;
+ if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))
+ return 0;
+
if (id)
glyphIndex = (idDelta + id) % 0x10000;
else
@@ -1290,13 +1378,19 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
}
return glyphIndex;
} else if (format == 6) {
- quint16 tableSize = qFromBigEndian<quint16>(cmap + 2);
+ quint16 tableSize;
+ if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))
+ return 0;
- quint16 firstCode6 = qFromBigEndian<quint16>(cmap + 6);
+ quint16 firstCode6;
+ if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))
+ return 0;
if (unicode < firstCode6)
return 0;
- quint16 entryCount6 = qFromBigEndian<quint16>(cmap + 8);
+ quint16 entryCount6;
+ if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))
+ return 0;
if (entryCount6 * 2 + 10 > tableSize)
return 0;
@@ -1305,9 +1399,14 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
return 0;
quint16 entryIndex6 = unicode - firstCode6;
- return qFromBigEndian<quint16>(cmap + 10 + (entryIndex6 * 2));
+
+ quint16 index = 0;
+ qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);
+ return index;
} else if (format == 12) {
- quint32 nGroups = qFromBigEndian<quint32>(cmap + 12);
+ quint32 nGroups;
+ if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))
+ return 0;
cmap += 16; // move to start of groups
@@ -1315,13 +1414,24 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
while (left <= right) {
int middle = left + ( ( right - left ) >> 1 );
- quint32 startCharCode = qFromBigEndian<quint32>(cmap + 12*middle);
+ quint32 startCharCode;
+ if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))
+ return 0;
+
if(unicode < startCharCode)
right = middle - 1;
else {
- quint32 endCharCode = qFromBigEndian<quint32>(cmap + 12*middle + 4);
- if(unicode <= endCharCode)
- return qFromBigEndian<quint32>(cmap + 12*middle + 8) + unicode - startCharCode;
+ quint32 endCharCode;
+ if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))
+ return 0;
+
+ if (unicode <= endCharCode) {
+ quint32 index;
+ if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))
+ return 0;
+
+ return index + unicode - startCharCode;
+ }
left = middle + 1;
}
}
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 9364b82bed..423b9413ed 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -243,7 +243,7 @@ public:
QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform) const;
static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize);
- static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode);
+ static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode);
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily);
diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp
index 4785902c99..4bb27c4d51 100644
--- a/src/gui/text/qfontengine_qpf2.cpp
+++ b/src/gui/text/qfontengine_qpf2.cpp
@@ -322,9 +322,9 @@ bool QFontEngineQPF2::getSfntTableData(uint tag, uchar *buffer, uint *length) co
glyph_t QFontEngineQPF2::glyphIndex(uint ucs4) const
{
- glyph_t glyph = getTrueTypeGlyphIndex(cmap, ucs4);
+ glyph_t glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
if (glyph == 0 && symbol && ucs4 < 0x100)
- glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000);
+ glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
if (!findGlyph(glyph))
glyph = 0;
@@ -348,16 +348,16 @@ bool QFontEngineQPF2::stringToCMap(const QChar *str, int len, QGlyphLayout *glyp
QStringIterator it(str, str + len);
while (it.hasNext()) {
const uint uc = it.next();
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
++glyph_pos;
}
} else {
QStringIterator it(str, str + len);
while (it.hasNext()) {
const uint uc = it.next();
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
#if 0 && defined(DEBUG_FONTENGINE)
QChar c(uc);
if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index e45ff5d744..afb134d014 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -181,9 +181,8 @@ void QWindowsFontEngine::getCMap()
bool symb = false;
if (ttf) {
cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
- int size = 0;
cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
- cmapTable.size(), &symb, &size);
+ cmapTable.size(), &symb, &cmapSize);
}
if (!cmap) {
ttf = false;
@@ -218,16 +217,16 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
QStringIterator it(str, str + numChars);
while (it.hasNext()) {
const uint uc = it.next();
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
++glyph_pos;
}
} else if (ttf) {
QStringIterator it(str, str + numChars);
while (it.hasNext()) {
const uint uc = it.next();
- glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
++glyph_pos;
}
} else {
@@ -276,6 +275,7 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name,
hasOutline(0),
lw(0),
cmap(0),
+ cmapSize(0),
lbearing(SHRT_MIN),
rbearing(SHRT_MIN),
x_height(-1),
@@ -343,11 +343,11 @@ glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const
#if !defined(Q_OS_WINCE)
if (symbol) {
- glyph = getTrueTypeGlyphIndex(cmap, ucs4);
+ glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
if (glyph == 0 && ucs4 < 0x100)
- glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000);
+ glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
} else if (ttf) {
- glyph = getTrueTypeGlyphIndex(cmap, ucs4);
+ glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
#else
if (tm.tmFirstChar > 60000) {
glyph = ucs4;
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h
index 02bc4008d1..c0dda6efca 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.h
+++ b/src/plugins/platforms/windows/qwindowsfontengine.h
@@ -147,6 +147,7 @@ private:
TEXTMETRIC tm;
int lw;
const unsigned char *cmap;
+ int cmapSize;
QByteArray cmapTable;
mutable qreal lbearing;
mutable qreal rbearing;