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