OLD | NEW |
| (Empty) |
1 #include "SkEndian.h" | |
2 #include "SkFontHost.h" | |
3 #include "SkStream.h" | |
4 | |
5 struct SkSFNTHeader { | |
6 uint32_t fVersion; | |
7 uint16_t fNumTables; | |
8 uint16_t fSearchRange; | |
9 uint16_t fEntrySelector; | |
10 uint16_t fRangeShift; | |
11 }; | |
12 | |
13 struct SkTTCFHeader { | |
14 uint32_t fTag; | |
15 uint32_t fVersion; | |
16 uint32_t fNumOffsets; | |
17 uint32_t fOffset0; // the first of N (fNumOffsets) | |
18 }; | |
19 | |
20 union SkSharedTTHeader { | |
21 SkSFNTHeader fSingle; | |
22 SkTTCFHeader fCollection; | |
23 }; | |
24 | |
25 struct SkSFNTDirEntry { | |
26 uint32_t fTag; | |
27 uint32_t fChecksum; | |
28 uint32_t fOffset; | |
29 uint32_t fLength; | |
30 }; | |
31 | |
32 static int count_tables(SkStream* stream, size_t* offsetToDir = NULL) { | |
33 SkSharedTTHeader shared; | |
34 if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { | |
35 return 0; | |
36 } | |
37 | |
38 uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag); | |
39 if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) { | |
40 if (shared.fCollection.fNumOffsets == 0) { | |
41 return 0; | |
42 } | |
43 size_t offset = SkEndian_SwapBE32(shared.fCollection.fOffset0); | |
44 stream->rewind(); | |
45 if (stream->skip(offset) != offset) { | |
46 return 0; | |
47 } | |
48 if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { | |
49 return 0; | |
50 } | |
51 if (offsetToDir) { | |
52 *offsetToDir = offset; | |
53 } | |
54 } else { | |
55 *offsetToDir = 0; | |
56 } | |
57 | |
58 return SkEndian_SwapBE16(shared.fSingle.fNumTables); | |
59 } | |
60 | |
61 /////////////////////////////////////////////////////////////////////////////// | |
62 | |
63 struct SfntHeader { | |
64 SfntHeader() : fCount(0), fDir(NULL) {} | |
65 ~SfntHeader() { sk_free(fDir); } | |
66 | |
67 bool init(SkStream* stream) { | |
68 size_t offsetToDir; | |
69 fCount = count_tables(stream, &offsetToDir); | |
70 if (0 == fCount) { | |
71 return false; | |
72 } | |
73 | |
74 stream->rewind(); | |
75 const size_t tableRecordOffset = offsetToDir + sizeof(SkSFNTHeader); | |
76 if (stream->skip(tableRecordOffset) != tableRecordOffset) { | |
77 return false; | |
78 } | |
79 | |
80 size_t size = fCount * sizeof(SkSFNTDirEntry); | |
81 fDir = reinterpret_cast<SkSFNTDirEntry*>(sk_malloc_throw(size)); | |
82 return stream->read(fDir, size) == size; | |
83 } | |
84 | |
85 int fCount; | |
86 SkSFNTDirEntry* fDir; | |
87 }; | |
88 | |
89 /////////////////////////////////////////////////////////////////////////////// | |
90 | |
91 int SkFontHost::CountTables(SkFontID fontID) { | |
92 SkStream* stream = SkFontHost::OpenStream(fontID); | |
93 if (NULL == stream) { | |
94 return 0; | |
95 } | |
96 | |
97 SkAutoUnref au(stream); | |
98 return count_tables(stream); | |
99 } | |
100 | |
101 int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) { | |
102 SkStream* stream = SkFontHost::OpenStream(fontID); | |
103 if (NULL == stream) { | |
104 return 0; | |
105 } | |
106 | |
107 SkAutoUnref au(stream); | |
108 SfntHeader header; | |
109 if (!header.init(stream)) { | |
110 return 0; | |
111 } | |
112 | |
113 for (int i = 0; i < header.fCount; i++) { | |
114 tags[i] = SkEndian_SwapBE32(header.fDir[i].fTag); | |
115 } | |
116 return header.fCount; | |
117 } | |
118 | |
119 size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) { | |
120 SkStream* stream = SkFontHost::OpenStream(fontID); | |
121 if (NULL == stream) { | |
122 return 0; | |
123 } | |
124 | |
125 SkAutoUnref au(stream); | |
126 SfntHeader header; | |
127 if (!header.init(stream)) { | |
128 return 0; | |
129 } | |
130 | |
131 for (int i = 0; i < header.fCount; i++) { | |
132 if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) { | |
133 return SkEndian_SwapBE32(header.fDir[i].fLength); | |
134 } | |
135 } | |
136 return 0; | |
137 } | |
138 | |
139 size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag, | |
140 size_t offset, size_t length, void* data) { | |
141 SkStream* stream = SkFontHost::OpenStream(fontID); | |
142 if (NULL == stream) { | |
143 return 0; | |
144 } | |
145 | |
146 SkAutoUnref au(stream); | |
147 SfntHeader header; | |
148 if (!header.init(stream)) { | |
149 return 0; | |
150 } | |
151 | |
152 for (int i = 0; i < header.fCount; i++) { | |
153 if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) { | |
154 size_t realOffset = SkEndian_SwapBE32(header.fDir[i].fOffset); | |
155 size_t realLength = SkEndian_SwapBE32(header.fDir[i].fLength); | |
156 // now sanity check the caller's offset/length | |
157 if (offset >= realLength) { | |
158 return 0; | |
159 } | |
160 // if the caller is trusting the length from the file, then a | |
161 // hostile file might choose a value which would overflow offset + | |
162 // length. | |
163 if (offset + length < offset) { | |
164 return 0; | |
165 } | |
166 if (offset + length > realLength) { | |
167 length = realLength - offset; | |
168 } | |
169 // skip the stream to the part of the table we want to copy from | |
170 stream->rewind(); | |
171 size_t bytesToSkip = realOffset + offset; | |
172 if (stream->skip(bytesToSkip) != bytesToSkip) { | |
173 return 0; | |
174 } | |
175 if (stream->read(data, length) != length) { | |
176 return 0; | |
177 } | |
178 return length; | |
179 } | |
180 } | |
181 return 0; | |
182 } | |
183 | |
OLD | NEW |