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