1096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger/*
2096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * Copyright 2011 Google Inc.
3096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger *
4096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
5096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * found in the LICENSE file.
6096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger */
7096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
8096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkEndian.h"
9096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkFontStream.h"
10096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkStream.h"
11096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
12096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstruct SkSFNTHeader {
13096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fVersion;
14096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint16_t    fNumTables;
15096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint16_t    fSearchRange;
16096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint16_t    fEntrySelector;
17096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint16_t    fRangeShift;
18096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger};
19096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
20096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstruct SkTTCFHeader {
21096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fTag;
22096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fVersion;
23096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fNumOffsets;
24096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fOffset0;   // the first of N (fNumOffsets)
25096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger};
26096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
27096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerunion SkSharedTTHeader {
28096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkSFNTHeader    fSingle;
29096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkTTCFHeader    fCollection;
30096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger};
31096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
32096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstruct SkSFNTDirEntry {
33096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fTag;
34096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fChecksum;
35096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fOffset;
36096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t    fLength;
37096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger};
38096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
39096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstatic bool read(SkStream* stream, void* buffer, size_t amount) {
40096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return stream->read(buffer, amount) == amount;
41096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
42096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
43096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstatic bool skip(SkStream* stream, size_t amount) {
44096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return stream->skip(amount) == amount;
45096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
46096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
47096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger/** Return the number of tables, or if this is a TTC (collection), return the
48096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    number of tables in the first element of the collection. In either case,
49096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if offsetToDir is not-null, set it to the offset to the beginning of the
50096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    table headers (SkSFNTDirEntry), relative to the start of the stream.
51096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
52096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    On an error, return 0 for number of tables, and ignore offsetToDir
53096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger */
54096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstatic int count_tables(SkStream* stream, int ttcIndex, size_t* offsetToDir) {
55096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(ttcIndex >= 0);
56096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
57096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkAutoSMalloc<1024> storage(sizeof(SkSharedTTHeader));
58096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkSharedTTHeader* header = (SkSharedTTHeader*)storage.get();
59096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
60096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (!read(stream, header, sizeof(SkSharedTTHeader))) {
61096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return 0;
62096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
63096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
64096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // by default, SkSFNTHeader is at the start of the stream
65096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    size_t offset = 0;
66096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
67096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // if we're really a collection, the first 4-bytes will be 'ttcf'
68096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t tag = SkEndian_SwapBE32(header->fCollection.fTag);
69096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) {
70096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        unsigned count = SkEndian_SwapBE32(header->fCollection.fNumOffsets);
71096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if ((unsigned)ttcIndex >= count) {
72096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return 0;
73096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
74096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
75096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (ttcIndex > 0) { // need to read more of the shared header
76096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            stream->rewind();
77096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            size_t amount = sizeof(SkSharedTTHeader) + ttcIndex * sizeof(uint32_t);
78096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            header = (SkSharedTTHeader*)storage.reset(amount);
79096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            if (!read(stream, header, amount)) {
80096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                return 0;
81096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            }
82096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
83096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // this is the offset to the local SkSFNTHeader
84096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        offset = SkEndian_SwapBE32((&header->fCollection.fOffset0)[ttcIndex]);
85096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        stream->rewind();
86096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (!skip(stream, offset)) {
87096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return 0;
88096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
89096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (!read(stream, header, sizeof(SkSFNTHeader))) {
90096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return 0;
91096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
92096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
93096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
94096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (offsetToDir) {
95096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // add the size of the header, so we will point to the DirEntries
96096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        *offsetToDir = offset + sizeof(SkSFNTHeader);
97096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
98096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return SkEndian_SwapBE16(header->fSingle.fNumTables);
99096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
100096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
101096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
102096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
103096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstruct SfntHeader {
104096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SfntHeader() : fCount(0), fDir(NULL) {}
105096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    ~SfntHeader() { sk_free(fDir); }
106096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
107096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    /** If it returns true, then fCount and fDir are properly initialized.
108096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        Note: fDir will point to the raw array of SkSFNTDirEntry values,
109096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        meaning they will still be in the file's native endianness (BE).
110096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
111096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fDir will be automatically freed when this object is destroyed
112096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger     */
113096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    bool init(SkStream* stream, int ttcIndex) {
114096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        stream->rewind();
115096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
116096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        size_t offsetToDir;
117096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fCount = count_tables(stream, ttcIndex, &offsetToDir);
118096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (0 == fCount) {
119096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return false;
120096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
121096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
122096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        stream->rewind();
123096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (!skip(stream, offsetToDir)) {
124096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return false;
125096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
126096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
127096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        size_t size = fCount * sizeof(SkSFNTDirEntry);
128096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fDir = reinterpret_cast<SkSFNTDirEntry*>(sk_malloc_throw(size));
129096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return read(stream, fDir, size);
130096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
131096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
132096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    int             fCount;
133096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkSFNTDirEntry* fDir;
134096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger};
135096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
136096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
137096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
138096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerint SkFontStream::CountTTCEntries(SkStream* stream) {
139096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    stream->rewind();
140096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
141096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkSharedTTHeader shared;
142096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (!read(stream, &shared, sizeof(shared))) {
143096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return 0;
144096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
145096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
146096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // if we're really a collection, the first 4-bytes will be 'ttcf'
147096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag);
148096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) {
149096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return SkEndian_SwapBE32(shared.fCollection.fNumOffsets);
150096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    } else {
151096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return 1;   // normal 'sfnt' has 1 dir entry
152096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
153096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
154096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
155096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerint SkFontStream::GetTableTags(SkStream* stream, int ttcIndex,
156096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                               SkFontTableTag tags[]) {
157096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SfntHeader  header;
158096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (!header.init(stream, ttcIndex)) {
159096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return 0;
160096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
161096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
162096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (tags) {
163096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        for (int i = 0; i < header.fCount; i++) {
164096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            tags[i] = SkEndian_SwapBE32(header.fDir[i].fTag);
165096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
166096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
167096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return header.fCount;
168096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
169096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
170096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergersize_t SkFontStream::GetTableData(SkStream* stream, int ttcIndex,
171096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                                  SkFontTableTag tag,
172096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                                  size_t offset, size_t length, void* data) {
173096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SfntHeader  header;
174096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (!header.init(stream, ttcIndex)) {
175096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return 0;
176096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
177096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
178096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    for (int i = 0; i < header.fCount; i++) {
179096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) {
180096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            size_t realOffset = SkEndian_SwapBE32(header.fDir[i].fOffset);
181096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            size_t realLength = SkEndian_SwapBE32(header.fDir[i].fLength);
182096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // now sanity check the caller's offset/length
183096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            if (offset >= realLength) {
184096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                return 0;
185096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            }
186096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // if the caller is trusting the length from the file, then a
187096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // hostile file might choose a value which would overflow offset +
188096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // length.
189096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            if (offset + length < offset) {
190096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                return 0;
191096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            }
192096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            if (length > realLength - offset) {
193096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                length = realLength - offset;
194096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            }
195096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            if (data) {
196096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                // skip the stream to the part of the table we want to copy from
197096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                stream->rewind();
198096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                size_t bytesToSkip = realOffset + offset;
199096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                if (!skip(stream, bytesToSkip)) {
200096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                    return 0;
201096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                }
202096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                if (!read(stream, data, length)) {
203096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                    return 0;
204096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                }
205096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            }
206096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return length;
207096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
208096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
209096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return 0;
210096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
211