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