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