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