16ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com/* 26ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com * Copyright 2011 Google Inc. 36ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com * 46ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com * Use of this source code is governed by a BSD-style license that can be 56ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com * found in the LICENSE file. 66ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com */ 76ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 86ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com#include "SkEndian.h" 96ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com#include "SkFontStream.h" 106ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com#include "SkStream.h" 116ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 126ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.comstruct SkSFNTHeader { 136ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fVersion; 146ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint16_t fNumTables; 156ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint16_t fSearchRange; 166ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint16_t fEntrySelector; 176ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint16_t fRangeShift; 186ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com}; 196ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 206ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.comstruct SkTTCFHeader { 216ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fTag; 226ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fVersion; 236ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fNumOffsets; 246ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fOffset0; // the first of N (fNumOffsets) 256ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com}; 266ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 276ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.comunion SkSharedTTHeader { 286ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com SkSFNTHeader fSingle; 296ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com SkTTCFHeader fCollection; 306ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com}; 316ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 326ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.comstruct SkSFNTDirEntry { 336ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fTag; 346ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fChecksum; 356ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fOffset; 366ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com uint32_t fLength; 376ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com}; 386ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 3961f70b4478fea5d7d805480227536d8a8e633426reed@google.comstatic bool read(SkStream* stream, void* buffer, size_t amount) { 4061f70b4478fea5d7d805480227536d8a8e633426reed@google.com return stream->read(buffer, amount) == amount; 4161f70b4478fea5d7d805480227536d8a8e633426reed@google.com} 4261f70b4478fea5d7d805480227536d8a8e633426reed@google.com 4361f70b4478fea5d7d805480227536d8a8e633426reed@google.comstatic bool skip(SkStream* stream, size_t amount) { 4461f70b4478fea5d7d805480227536d8a8e633426reed@google.com return stream->skip(amount) == amount; 4561f70b4478fea5d7d805480227536d8a8e633426reed@google.com} 4661f70b4478fea5d7d805480227536d8a8e633426reed@google.com 476ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com/** Return the number of tables, or if this is a TTC (collection), return the 486ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com number of tables in the first element of the collection. In either case, 496ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if offsetToDir is not-null, set it to the offset to the beginning of the 506ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com table headers (SkSFNTDirEntry), relative to the start of the stream. 516ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 526ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com On an error, return 0 for number of tables, and ignore offsetToDir 536ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com */ 545bfc8396228b7a9e5be679aeb10f30860adf938freed@google.comstatic int count_tables(SkStream* stream, int ttcIndex, size_t* offsetToDir) { 555bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com SkASSERT(ttcIndex >= 0); 565bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com 5761f70b4478fea5d7d805480227536d8a8e633426reed@google.com SkAutoSMalloc<1024> storage(sizeof(SkSharedTTHeader)); 5861f70b4478fea5d7d805480227536d8a8e633426reed@google.com SkSharedTTHeader* header = (SkSharedTTHeader*)storage.get(); 5961f70b4478fea5d7d805480227536d8a8e633426reed@google.com 6061f70b4478fea5d7d805480227536d8a8e633426reed@google.com if (!read(stream, header, sizeof(SkSharedTTHeader))) { 616ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 626ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 636ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 646ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com // by default, SkSFNTHeader is at the start of the stream 656ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com size_t offset = 0; 666ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 676ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com // if we're really a collection, the first 4-bytes will be 'ttcf' 6861f70b4478fea5d7d805480227536d8a8e633426reed@google.com uint32_t tag = SkEndian_SwapBE32(header->fCollection.fTag); 696ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) { 7061f70b4478fea5d7d805480227536d8a8e633426reed@google.com unsigned count = SkEndian_SwapBE32(header->fCollection.fNumOffsets); 715bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com if ((unsigned)ttcIndex >= count) { 726ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 736ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 7464334352cc3f29f52dfa07225d65eb218d2fd830skia.committer@gmail.com 755bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com if (ttcIndex > 0) { // need to read more of the shared header 765bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com stream->rewind(); 7761f70b4478fea5d7d805480227536d8a8e633426reed@google.com size_t amount = sizeof(SkSharedTTHeader) + ttcIndex * sizeof(uint32_t); 7861f70b4478fea5d7d805480227536d8a8e633426reed@google.com header = (SkSharedTTHeader*)storage.reset(amount); 7961f70b4478fea5d7d805480227536d8a8e633426reed@google.com if (!read(stream, header, amount)) { 805bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com return 0; 815bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com } 825bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com } 835bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com // this is the offset to the local SkSFNTHeader 8461f70b4478fea5d7d805480227536d8a8e633426reed@google.com offset = SkEndian_SwapBE32((&header->fCollection.fOffset0)[ttcIndex]); 856ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com stream->rewind(); 8661f70b4478fea5d7d805480227536d8a8e633426reed@google.com if (!skip(stream, offset)) { 876ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 886ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 8961f70b4478fea5d7d805480227536d8a8e633426reed@google.com if (!read(stream, header, sizeof(SkSFNTHeader))) { 906ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 916ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 926ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 936ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 946ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (offsetToDir) { 956ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com // add the size of the header, so we will point to the DirEntries 966ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com *offsetToDir = offset + sizeof(SkSFNTHeader); 976ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 9861f70b4478fea5d7d805480227536d8a8e633426reed@google.com return SkEndian_SwapBE16(header->fSingle.fNumTables); 996ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com} 1006ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1016ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com/////////////////////////////////////////////////////////////////////////////// 1026ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1036ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.comstruct SfntHeader { 1046ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com SfntHeader() : fCount(0), fDir(NULL) {} 1056ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com ~SfntHeader() { sk_free(fDir); } 1066ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1076ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com /** If it returns true, then fCount and fDir are properly initialized. 1086ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com Note: fDir will point to the raw array of SkSFNTDirEntry values, 1096ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com meaning they will still be in the file's native endianness (BE). 1106ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1116ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com fDir will be automatically freed when this object is destroyed 1126ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com */ 1135bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com bool init(SkStream* stream, int ttcIndex) { 11490ee4488e9c6b8ec4cb1137250fed43b5919ce2creed@google.com stream->rewind(); 11590ee4488e9c6b8ec4cb1137250fed43b5919ce2creed@google.com 1166ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com size_t offsetToDir; 1175bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com fCount = count_tables(stream, ttcIndex, &offsetToDir); 1186ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (0 == fCount) { 1196ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return false; 1206ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1216ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1226ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com stream->rewind(); 123ed268bfed3205347a90557c5029f37e90cc01956reed@google.com if (!skip(stream, offsetToDir)) { 1246ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return false; 1256ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1266ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1276ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com size_t size = fCount * sizeof(SkSFNTDirEntry); 1286ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com fDir = reinterpret_cast<SkSFNTDirEntry*>(sk_malloc_throw(size)); 129ed268bfed3205347a90557c5029f37e90cc01956reed@google.com return read(stream, fDir, size); 1306ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1316ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1326ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com int fCount; 1336ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com SkSFNTDirEntry* fDir; 1346ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com}; 1356ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1366ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com/////////////////////////////////////////////////////////////////////////////// 1376ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1385bfc8396228b7a9e5be679aeb10f30860adf938freed@google.comint SkFontStream::CountTTCEntries(SkStream* stream) { 1395bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com stream->rewind(); 1405bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com 1415bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com SkSharedTTHeader shared; 142ed268bfed3205347a90557c5029f37e90cc01956reed@google.com if (!read(stream, &shared, sizeof(shared))) { 1435bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com return 0; 1445bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com } 1455bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com 1465bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com // if we're really a collection, the first 4-bytes will be 'ttcf' 1475bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag); 1485bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) { 1495bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com return SkEndian_SwapBE32(shared.fCollection.fNumOffsets); 1505bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com } else { 151ed268bfed3205347a90557c5029f37e90cc01956reed@google.com return 1; // normal 'sfnt' has 1 dir entry 15264334352cc3f29f52dfa07225d65eb218d2fd830skia.committer@gmail.com } 1535bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com} 1545bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com 1555bfc8396228b7a9e5be679aeb10f30860adf938freed@google.comint SkFontStream::GetTableTags(SkStream* stream, int ttcIndex, 1565bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com SkFontTableTag tags[]) { 1576ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com SfntHeader header; 1585bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com if (!header.init(stream, ttcIndex)) { 1596ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 1606ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1616ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1626ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (tags) { 1636ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com for (int i = 0; i < header.fCount; i++) { 1646ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com tags[i] = SkEndian_SwapBE32(header.fDir[i].fTag); 1656ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1666ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1676ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return header.fCount; 1686ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com} 1696ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1705bfc8396228b7a9e5be679aeb10f30860adf938freed@google.comsize_t SkFontStream::GetTableData(SkStream* stream, int ttcIndex, 1715bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com SkFontTableTag tag, 1726ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com size_t offset, size_t length, void* data) { 1736ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com SfntHeader header; 1745bfc8396228b7a9e5be679aeb10f30860adf938freed@google.com if (!header.init(stream, ttcIndex)) { 1756ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 1766ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1776ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com 1786ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com for (int i = 0; i < header.fCount; i++) { 1796ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) { 1806ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com size_t realOffset = SkEndian_SwapBE32(header.fDir[i].fOffset); 1816ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com size_t realLength = SkEndian_SwapBE32(header.fDir[i].fLength); 1826ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com // now sanity check the caller's offset/length 1836ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (offset >= realLength) { 1846ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 1856ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1866ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com // if the caller is trusting the length from the file, then a 1876ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com // hostile file might choose a value which would overflow offset + 1886ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com // length. 1896ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (offset + length < offset) { 1906ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 1916ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1926ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (length > realLength - offset) { 1936ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com length = realLength - offset; 1946ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 1956ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com if (data) { 1966ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com // skip the stream to the part of the table we want to copy from 1976ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com stream->rewind(); 1986ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com size_t bytesToSkip = realOffset + offset; 1998fff39804398cbf33b77ff7061391d47d6090e4freed@google.com if (!skip(stream, bytesToSkip)) { 2006ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 2016ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 202ed268bfed3205347a90557c5029f37e90cc01956reed@google.com if (!read(stream, data, length)) { 2036ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 2046ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 2056ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 2066ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return length; 2076ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 2086ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com } 2096ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com return 0; 2106ec97b6e4bb19b2f1aab4b21a41f482d46234089reed@google.com} 211