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