SkFontHost_tables.cpp revision dab163f0b2658c2dba48839e72f81d3d8ee0ae8b
1f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed#include "SkEndian.h"
2f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed#include "SkFontHost.h"
3f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed#include "SkStream.h"
4f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
5f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedstruct SkSFNTHeader {
6f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fVersion;
7f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint16_t    fNumTables;
8f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint16_t    fSearchRange;
9f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint16_t    fEntrySelector;
10f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint16_t    fRangeShift;
11f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed};
12f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
13f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedstruct SkTTCFHeader {
14f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fTag;
15f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fVersion;
16f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fNumOffsets;
17f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fOffset0;   // the first of N (fNumOffsets)
18f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed};
19f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
20f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedunion SkSharedTTHeader {
21f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkSFNTHeader    fSingle;
22f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkTTCFHeader    fCollection;
23f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed};
24f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
25f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedstruct SkSFNTDirEntry {
26f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fTag;
27f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fChecksum;
28f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fOffset;
29f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t    fLength;
30f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed};
31f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
32f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed/** Return the number of tables, or if this is a TTC (collection), return the
33f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    number of tables in the first element of the collection. In either case,
34f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if offsetToDir is not-null, set it to the offset to the beginning of the
35f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    table headers (SkSFNTDirEntry), relative to the start of the stream.
36f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
37f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    On an error, return 0 for number of tables, and ignore offsetToDir
38f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed */
39f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedstatic int count_tables(SkStream* stream, size_t* offsetToDir = NULL) {
40f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkSharedTTHeader shared;
41f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) {
42f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return 0;
43f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
44f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
45f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    // by default, SkSFNTHeader is at the start of the stream
46f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    size_t offset = 0;
47f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
48f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    // if we're really a collection, the first 4-bytes will be 'ttcf'
49f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag);
50f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) {
51f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        if (shared.fCollection.fNumOffsets == 0) {
52f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            return 0;
53f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        }
54f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        // this is the offset to the first local SkSFNTHeader
55f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        offset = SkEndian_SwapBE32(shared.fCollection.fOffset0);
56f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        stream->rewind();
57f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        if (stream->skip(offset) != offset) {
58f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            return 0;
59f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        }
60f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) {
61f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            return 0;
62f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        }
63f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
64f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
65f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (offsetToDir) {
66f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        // add the size of the header, so we will point to the DirEntries
67dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed        *offsetToDir = offset + sizeof(SkSFNTHeader);
68f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
69f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    return SkEndian_SwapBE16(shared.fSingle.fNumTables);
70f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed}
71f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
72f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed///////////////////////////////////////////////////////////////////////////////
73f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
74f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedstruct SfntHeader {
75f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SfntHeader() : fCount(0), fDir(NULL) {}
76f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    ~SfntHeader() { sk_free(fDir); }
77f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
78f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    /** If it returns true, then fCount and fDir are properly initialized.
79f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        Note: fDir will point to the raw array of SkSFNTDirEntry values,
80f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        meaning they will still be in the file's native endianness (BE).
81f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
82f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        fDir will be automatically freed when this object is destroyed
83f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed     */
84f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    bool init(SkStream* stream) {
85f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        size_t offsetToDir;
86f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        fCount = count_tables(stream, &offsetToDir);
87f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        if (0 == fCount) {
88f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            return false;
89f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        }
90f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
91f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        stream->rewind();
92f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        if (stream->skip(offsetToDir) != offsetToDir) {
93f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            return false;
94f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        }
95f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
96f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        size_t size = fCount * sizeof(SkSFNTDirEntry);
97f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        fDir = reinterpret_cast<SkSFNTDirEntry*>(sk_malloc_throw(size));
98f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return stream->read(fDir, size) == size;
99f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
100f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
101f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    int             fCount;
102f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkSFNTDirEntry* fDir;
103f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed};
104f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
105f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed///////////////////////////////////////////////////////////////////////////////
106f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
107f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedint SkFontHost::CountTables(SkFontID fontID) {
108f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkStream* stream = SkFontHost::OpenStream(fontID);
109f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (NULL == stream) {
110f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return 0;
111f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
112f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
113f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkAutoUnref au(stream);
114f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    return count_tables(stream);
115f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed}
116f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
117f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedint SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) {
118f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkStream* stream = SkFontHost::OpenStream(fontID);
119f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (NULL == stream) {
120f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return 0;
121f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
122f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
123f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkAutoUnref au(stream);
124f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SfntHeader  header;
125f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (!header.init(stream)) {
126f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return 0;
127f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
128f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
129f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    for (int i = 0; i < header.fCount; i++) {
130f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        tags[i] = SkEndian_SwapBE32(header.fDir[i].fTag);
131f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
132f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    return header.fCount;
133f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed}
134f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
135f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedsize_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) {
136f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkStream* stream = SkFontHost::OpenStream(fontID);
137f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (NULL == stream) {
138f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return 0;
139f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
140f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
141f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkAutoUnref au(stream);
142f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SfntHeader  header;
143f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (!header.init(stream)) {
144f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return 0;
145f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
146f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
147f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    for (int i = 0; i < header.fCount; i++) {
148f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) {
149f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            return SkEndian_SwapBE32(header.fDir[i].fLength);
150f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        }
151f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
152f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    return 0;
153f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed}
154f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
155f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reedsize_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag,
156f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed                                size_t offset, size_t length, void* data) {
157f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkStream* stream = SkFontHost::OpenStream(fontID);
158f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (NULL == stream) {
159f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return 0;
160f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
161f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
162f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SkAutoUnref au(stream);
163f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    SfntHeader  header;
164f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    if (!header.init(stream)) {
165f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        return 0;
166f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
167f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
168f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    for (int i = 0; i < header.fCount; i++) {
169f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) {
170f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            size_t realOffset = SkEndian_SwapBE32(header.fDir[i].fOffset);
171f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            size_t realLength = SkEndian_SwapBE32(header.fDir[i].fLength);
172f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            // now sanity check the caller's offset/length
173f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            if (offset >= realLength) {
174f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed                return 0;
175f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            }
176f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            // if the caller is trusting the length from the file, then a
177f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            // hostile file might choose a value which would overflow offset +
178f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            // length.
179f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            if (offset + length < offset) {
180f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed                return 0;
181f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            }
182f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            if (offset + length > realLength) {
183f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed                length = realLength - offset;
184f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            }
185f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            // skip the stream to the part of the table we want to copy from
186f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            stream->rewind();
187f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            size_t bytesToSkip = realOffset + offset;
188f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            if (stream->skip(bytesToSkip) != bytesToSkip) {
189f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed                return 0;
190f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            }
191f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            if (stream->read(data, length) != length) {
192f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed                return 0;
193f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            }
194f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed            return length;
195f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed        }
196f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    }
197f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed    return 0;
198f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed}
199f95abb54afa5469c53d3ac899ecbce8a386471c1Mike Reed
200