1 // Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "mozilla/Compression.h"
14 // -----------------------------------------------------------------------------
16 // -----------------------------------------------------------------------------
18 bool OpenTypeGLAT_v1::Parse(const uint8_t* data
, size_t length
) {
19 Buffer
table(data
, length
);
20 OpenTypeGLOC
* gloc
= static_cast<OpenTypeGLOC
*>(
21 GetFont()->GetTypedTable(OTS_TAG_GLOC
));
23 return DropGraphite("Required Gloc table is missing");
26 if (!table
.ReadU32(&this->version
) || this->version
>> 16 != 1) {
27 return DropGraphite("Failed to read version");
30 const std::vector
<uint32_t>& locations
= gloc
->GetLocations();
31 if (locations
.empty()) {
32 return DropGraphite("No locations from Gloc table");
34 std::list
<uint32_t> unverified(locations
.begin(), locations
.end());
35 while (table
.remaining()) {
36 GlatEntry
entry(this);
37 if (table
.offset() > unverified
.front()) {
38 return DropGraphite("Offset check failed for a GlatEntry");
40 if (table
.offset() == unverified
.front()) {
41 unverified
.pop_front();
43 if (unverified
.empty()) {
44 return DropGraphite("Expected more locations");
46 if (!entry
.ParsePart(table
)) {
47 return DropGraphite("Failed to read a GlatEntry");
49 this->entries
.push_back(entry
);
52 if (unverified
.size() != 1 || unverified
.front() != table
.offset()) {
53 return DropGraphite("%zu location(s) could not be verified", unverified
.size());
55 if (table
.remaining()) {
56 return Warning("%zu bytes unparsed", table
.remaining());
61 bool OpenTypeGLAT_v1::Serialize(OTSStream
* out
) {
62 assert(ShouldSerialize());
63 if (!out
->WriteU32(this->version
) ||
64 !SerializeParts(this->entries
, out
)) {
65 return Error("Failed to write table");
70 bool OpenTypeGLAT_v1::GlatEntry::ParsePart(Buffer
& table
) {
71 if (!table
.ReadU8(&this->attNum
)) {
72 return parent
->Error("GlatEntry: Failed to read attNum");
74 if (!table
.ReadU8(&this->num
)) {
75 return parent
->Error("GlatEntry: Failed to read num");
78 //this->attributes.resize(this->num);
79 for (int i
= 0; i
< this->num
; ++i
) {
80 this->attributes
.emplace_back();
81 if (!table
.ReadS16(&this->attributes
[i
])) {
82 return parent
->Error("GlatEntry: Failed to read attribute %u", i
);
88 bool OpenTypeGLAT_v1::GlatEntry::SerializePart(OTSStream
* out
) const {
89 if (!out
->WriteU8(this->attNum
) ||
90 !out
->WriteU8(this->num
) ||
91 !SerializeParts(this->attributes
, out
)) {
92 return parent
->Error("GlatEntry: Failed to write");
97 // -----------------------------------------------------------------------------
99 // -----------------------------------------------------------------------------
101 bool OpenTypeGLAT_v2::Parse(const uint8_t* data
, size_t length
) {
102 Buffer
table(data
, length
);
103 OpenTypeGLOC
* gloc
= static_cast<OpenTypeGLOC
*>(
104 GetFont()->GetTypedTable(OTS_TAG_GLOC
));
106 return DropGraphite("Required Gloc table is missing");
109 if (!table
.ReadU32(&this->version
) || this->version
>> 16 != 1) {
110 return DropGraphite("Failed to read version");
113 const std::vector
<uint32_t>& locations
= gloc
->GetLocations();
114 if (locations
.empty()) {
115 return DropGraphite("No locations from Gloc table");
117 std::list
<uint32_t> unverified(locations
.begin(), locations
.end());
118 while (table
.remaining()) {
119 GlatEntry
entry(this);
120 if (table
.offset() > unverified
.front()) {
121 return DropGraphite("Offset check failed for a GlatEntry");
123 if (table
.offset() == unverified
.front()) {
124 unverified
.pop_front();
126 if (unverified
.empty()) {
127 return DropGraphite("Expected more locations");
129 if (!entry
.ParsePart(table
)) {
130 return DropGraphite("Failed to read a GlatEntry");
132 this->entries
.push_back(entry
);
135 if (unverified
.size() != 1 || unverified
.front() != table
.offset()) {
136 return DropGraphite("%zu location(s) could not be verified", unverified
.size());
138 if (table
.remaining()) {
139 return Warning("%zu bytes unparsed", table
.remaining());
144 bool OpenTypeGLAT_v2::Serialize(OTSStream
* out
) {
145 assert(ShouldSerialize());
146 if (!out
->WriteU32(this->version
) ||
147 !SerializeParts(this->entries
, out
)) {
148 return Error("Failed to write table");
153 bool OpenTypeGLAT_v2::GlatEntry::ParsePart(Buffer
& table
) {
154 if (!table
.ReadS16(&this->attNum
)) {
155 return parent
->Error("GlatEntry: Failed to read attNum");
157 if (!table
.ReadS16(&this->num
) || this->num
< 0) {
158 return parent
->Error("GlatEntry: Failed to read valid num");
161 //this->attributes.resize(this->num);
162 for (int i
= 0; i
< this->num
; ++i
) {
163 this->attributes
.emplace_back();
164 if (!table
.ReadS16(&this->attributes
[i
])) {
165 return parent
->Error("GlatEntry: Failed to read attribute %u", i
);
171 bool OpenTypeGLAT_v2::GlatEntry::SerializePart(OTSStream
* out
) const {
172 if (!out
->WriteS16(this->attNum
) ||
173 !out
->WriteS16(this->num
) ||
174 !SerializeParts(this->attributes
, out
)) {
175 return parent
->Error("GlatEntry: Failed to write");
180 // -----------------------------------------------------------------------------
182 // -----------------------------------------------------------------------------
184 bool OpenTypeGLAT_v3::Parse(const uint8_t* data
, size_t length
,
185 bool prevent_decompression
) {
186 Buffer
table(data
, length
);
187 OpenTypeGLOC
* gloc
= static_cast<OpenTypeGLOC
*>(
188 GetFont()->GetTypedTable(OTS_TAG_GLOC
));
190 return DropGraphite("Required Gloc table is missing");
193 if (!table
.ReadU32(&this->version
) || this->version
>> 16 != 3) {
194 return DropGraphite("Failed to read version");
196 if (!table
.ReadU32(&this->compHead
)) {
197 return DropGraphite("Failed to read compression header");
199 switch ((this->compHead
& SCHEME
) >> 27) {
200 case 0: // uncompressed
203 if (prevent_decompression
) {
204 return DropGraphite("Illegal nested compression");
206 size_t decompressed_size
= this->compHead
& FULL_SIZE
;
207 if (decompressed_size
< length
) {
208 return DropGraphite("Decompressed size is less than compressed size");
210 if (decompressed_size
== 0) {
211 return DropGraphite("Decompressed size is set to 0");
213 // decompressed table must be <= OTS_MAX_DECOMPRESSED_TABLE_SIZE
214 if (decompressed_size
> OTS_MAX_DECOMPRESSED_TABLE_SIZE
) {
215 return DropGraphite("Decompressed size exceeds %gMB: %gMB",
216 OTS_MAX_DECOMPRESSED_TABLE_SIZE
/ (1024.0 * 1024.0),
217 decompressed_size
/ (1024.0 * 1024.0));
219 std::unique_ptr
<uint8_t> decompressed(new uint8_t[decompressed_size
]());
220 size_t outputSize
= 0;
221 bool ret
= mozilla::Compression::LZ4::decompressPartial(
222 reinterpret_cast<const char*>(data
+ table
.offset()),
223 table
.remaining(), // input buffer size (input size + padding)
224 reinterpret_cast<char*>(decompressed
.get()),
225 decompressed_size
, // target output size
226 &outputSize
); // return output size
227 if (!ret
|| outputSize
!= decompressed_size
) {
228 return DropGraphite("Decompression failed");
230 return this->Parse(decompressed
.get(), decompressed_size
, true);
233 return DropGraphite("Unknown compression scheme");
235 if (this->compHead
& RESERVED
) {
236 Warning("Nonzero reserved");
239 const std::vector
<uint32_t>& locations
= gloc
->GetLocations();
240 if (locations
.empty()) {
241 return DropGraphite("No locations from Gloc table");
243 std::list
<uint32_t> unverified(locations
.begin(), locations
.end());
244 //this->entries.resize(locations.size() - 1, this);
245 for (size_t i
= 0; i
< locations
.size() - 1; ++i
) {
246 this->entries
.emplace_back(this);
247 if (table
.offset() != unverified
.front()) {
248 return DropGraphite("Offset check failed for a GlyphAttrs");
250 unverified
.pop_front();
251 if (!this->entries
[i
].ParsePart(table
,
252 unverified
.front() - table
.offset())) {
253 // unverified.front() is guaranteed to exist because of the number of
254 // iterations of this loop
255 return DropGraphite("Failed to read a GlyphAttrs");
259 if (unverified
.size() != 1 || unverified
.front() != table
.offset()) {
260 return DropGraphite("%zu location(s) could not be verified", unverified
.size());
262 if (table
.remaining()) {
263 return Warning("%zu bytes unparsed", table
.remaining());
268 bool OpenTypeGLAT_v3::Serialize(OTSStream
* out
) {
269 assert(ShouldSerialize());
270 if (!out
->WriteU32(this->version
) ||
271 !out
->WriteU32(this->compHead
) ||
272 !SerializeParts(this->entries
, out
)) {
273 return Error("Failed to write table");
278 bool OpenTypeGLAT_v3::GlyphAttrs::ParsePart(Buffer
& table
, const size_t size
) {
279 size_t init_offset
= table
.offset();
280 if (parent
->compHead
& OCTABOXES
&& !octabox
.ParsePart(table
)) {
281 // parent->flags & 0b1: octaboxes are present flag
282 return parent
->Error("GlyphAttrs: Failed to read octabox");
285 while (table
.offset() < init_offset
+ size
) {
286 GlatEntry
entry(parent
);
287 if (!entry
.ParsePart(table
)) {
288 return parent
->Error("GlyphAttrs: Failed to read a GlatEntry");
290 this->entries
.push_back(entry
);
295 bool OpenTypeGLAT_v3::GlyphAttrs::SerializePart(OTSStream
* out
) const {
296 if ((parent
->compHead
& OCTABOXES
&& !octabox
.SerializePart(out
)) ||
297 !SerializeParts(this->entries
, out
)) {
298 return parent
->Error("GlyphAttrs: Failed to write");
303 bool OpenTypeGLAT_v3::GlyphAttrs::
304 OctaboxMetrics::ParsePart(Buffer
& table
) {
305 if (!table
.ReadU16(&this->subbox_bitmap
)) {
306 return parent
->Error("OctaboxMetrics: Failed to read subbox_bitmap");
308 if (!table
.ReadU8(&this->diag_neg_min
)) {
309 return parent
->Error("OctaboxMetrics: Failed to read diag_neg_min");
311 if (!table
.ReadU8(&this->diag_neg_max
) ||
312 this->diag_neg_max
< this->diag_neg_min
) {
313 return parent
->Error("OctaboxMetrics: Failed to read valid diag_neg_max");
315 if (!table
.ReadU8(&this->diag_pos_min
)) {
316 return parent
->Error("OctaboxMetrics: Failed to read diag_pos_min");
318 if (!table
.ReadU8(&this->diag_pos_max
) ||
319 this->diag_pos_max
< this->diag_pos_min
) {
320 return parent
->Error("OctaboxMetrics: Failed to read valid diag_pos_max");
323 unsigned subboxes_len
= 0; // count of 1's in this->subbox_bitmap
324 for (uint16_t i
= this->subbox_bitmap
; i
; i
>>= 1) {
329 //this->subboxes.resize(subboxes_len, parent);
330 for (unsigned i
= 0; i
< subboxes_len
; i
++) {
331 this->subboxes
.emplace_back(parent
);
332 if (!this->subboxes
[i
].ParsePart(table
)) {
333 return parent
->Error("OctaboxMetrics: Failed to read subbox[%u]", i
);
339 bool OpenTypeGLAT_v3::GlyphAttrs::
340 OctaboxMetrics::SerializePart(OTSStream
* out
) const {
341 if (!out
->WriteU16(this->subbox_bitmap
) ||
342 !out
->WriteU8(this->diag_neg_min
) ||
343 !out
->WriteU8(this->diag_neg_max
) ||
344 !out
->WriteU8(this->diag_pos_min
) ||
345 !out
->WriteU8(this->diag_pos_max
) ||
346 !SerializeParts(this->subboxes
, out
)) {
347 return parent
->Error("OctaboxMetrics: Failed to write");
352 bool OpenTypeGLAT_v3::GlyphAttrs::OctaboxMetrics::
353 SubboxEntry::ParsePart(Buffer
& table
) {
354 if (!table
.ReadU8(&this->left
)) {
355 return parent
->Error("SubboxEntry: Failed to read left");
357 if (!table
.ReadU8(&this->right
) || this->right
< this->left
) {
358 return parent
->Error("SubboxEntry: Failed to read valid right");
360 if (!table
.ReadU8(&this->bottom
)) {
361 return parent
->Error("SubboxEntry: Failed to read bottom");
363 if (!table
.ReadU8(&this->top
) || this->top
< this->bottom
) {
364 return parent
->Error("SubboxEntry: Failed to read valid top");
366 if (!table
.ReadU8(&this->diag_pos_min
)) {
367 return parent
->Error("SubboxEntry: Failed to read diag_pos_min");
369 if (!table
.ReadU8(&this->diag_pos_max
) ||
370 this->diag_pos_max
< this->diag_pos_min
) {
371 return parent
->Error("SubboxEntry: Failed to read valid diag_pos_max");
373 if (!table
.ReadU8(&this->diag_neg_min
)) {
374 return parent
->Error("SubboxEntry: Failed to read diag_neg_min");
376 if (!table
.ReadU8(&this->diag_neg_max
) ||
377 this->diag_neg_max
< this->diag_neg_min
) {
378 return parent
->Error("SubboxEntry: Failed to read valid diag_neg_max");
383 bool OpenTypeGLAT_v3::GlyphAttrs::OctaboxMetrics::
384 SubboxEntry::SerializePart(OTSStream
* out
) const {
385 if (!out
->WriteU8(this->left
) ||
386 !out
->WriteU8(this->right
) ||
387 !out
->WriteU8(this->bottom
) ||
388 !out
->WriteU8(this->top
) ||
389 !out
->WriteU8(this->diag_pos_min
) ||
390 !out
->WriteU8(this->diag_pos_max
) ||
391 !out
->WriteU8(this->diag_neg_min
) ||
392 !out
->WriteU8(this->diag_neg_max
)) {
393 return parent
->Error("SubboxEntry: Failed to write");
398 bool OpenTypeGLAT_v3::GlyphAttrs::
399 GlatEntry::ParsePart(Buffer
& table
) {
400 if (!table
.ReadS16(&this->attNum
)) {
401 return parent
->Error("GlatEntry: Failed to read attNum");
403 if (!table
.ReadS16(&this->num
) || this->num
< 0) {
404 return parent
->Error("GlatEntry: Failed to read valid num");
407 //this->attributes.resize(this->num);
408 for (int i
= 0; i
< this->num
; ++i
) {
409 this->attributes
.emplace_back();
410 if (!table
.ReadS16(&this->attributes
[i
])) {
411 return parent
->Error("GlatEntry: Failed to read attribute %u", i
);
417 bool OpenTypeGLAT_v3::GlyphAttrs::
418 GlatEntry::SerializePart(OTSStream
* out
) const {
419 if (!out
->WriteS16(this->attNum
) ||
420 !out
->WriteS16(this->num
) ||
421 !SerializeParts(this->attributes
, out
)) {
422 return parent
->Error("GlatEntry: Failed to write");
427 // -----------------------------------------------------------------------------
429 // -----------------------------------------------------------------------------
431 bool OpenTypeGLAT::Parse(const uint8_t* data
, size_t length
) {
432 Buffer
table(data
, length
);
434 if (!table
.ReadU32(&version
)) {
435 return DropGraphite("Failed to read version");
437 switch (version
>> 16) {
439 this->handler
= new OpenTypeGLAT_v1(this->font
, this->tag
);
442 this->handler
= new OpenTypeGLAT_v2(this->font
, this->tag
);
445 this->handler
= new OpenTypeGLAT_v3(this->font
, this->tag
);
449 return DropGraphite("Unsupported table version: %u", version
>> 16);
451 return this->handler
->Parse(data
, length
);
454 bool OpenTypeGLAT::Serialize(OTSStream
* out
) {
455 if (!this->handler
) {
456 return Error("No Glat table parsed");
458 return this->handler
->Serialize(out
);