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