Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Unified Diff: third_party/ots/src/woff2.cc

Issue 966703002: Updating OTS with new fixes for Color table from github (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing file permissions Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/ots/src/woff2.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/ots/src/woff2.cc
diff --git a/third_party/ots/src/woff2.cc b/third_party/ots/src/woff2.cc
index 54ab6259bbbc6099dc2947303d7321883ba733d7..b244aeca323fe8f866d0cf9d1dfc5c6b998f73bc 100644
--- a/third_party/ots/src/woff2.cc
+++ b/third_party/ots/src/woff2.cc
@@ -45,6 +45,7 @@ const size_t kCompositeGlyphBegin = 10;
// Note that the byte order is big-endian, not the same as ots.cc
#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
+#define CHR(t) (t >> 24), (t >> 16), (t >> 8), (t >> 0)
const unsigned int kWoff2FlagsTransform = 1 << 5;
@@ -135,6 +136,10 @@ struct Table {
transform_length(0),
dst_offset(0),
dst_length(0) {}
+
+ bool operator<(const Table& other) const {
+ return tag < other.tag;
+ }
};
// Based on section 6.1.1 of MicroType Express draft spec
@@ -509,35 +514,38 @@ bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
}
// Reconstruct entire glyf table based on transformed original
-bool ReconstructGlyf(const uint8_t* data, size_t data_size,
+bool ReconstructGlyf(ots::OpenTypeFile* file,
+ const uint8_t* data, size_t data_size,
uint8_t* dst, size_t dst_size,
uint8_t* loca_buf, size_t loca_size) {
static const int kNumSubStreams = 7;
- ots::Buffer file(data, data_size);
+ ots::Buffer buffer(data, data_size);
uint32_t version;
std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
- if (!file.ReadU32(&version)) {
- return OTS_FAILURE();
+ if (!buffer.ReadU32(&version)) {
+ return OTS_FAILURE_MSG("Failed to read 'version' of transformed 'glyf' table");
}
uint16_t num_glyphs;
+ if (!buffer.ReadU16(&num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to read 'numGlyphs' from transformed 'glyf' table");
+ }
uint16_t index_format;
- if (!file.ReadU16(&num_glyphs) ||
- !file.ReadU16(&index_format)) {
- return OTS_FAILURE();
+ if (!buffer.ReadU16(&index_format)) {
+ return OTS_FAILURE_MSG("Failed to read 'indexFormat' from transformed 'glyf' table");
}
unsigned int offset = (2 + kNumSubStreams) * 4;
if (offset > data_size) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Size of transformed 'glyf' table is too small to fit its data");
}
// Invariant from here on: data_size >= offset
for (int i = 0; i < kNumSubStreams; ++i) {
uint32_t substream_size;
- if (!file.ReadU32(&substream_size)) {
- return OTS_FAILURE();
+ if (!buffer.ReadU32(&substream_size)) {
+ return OTS_FAILURE_MSG("Failed to read substream size %d of transformed 'glyf' table", i);
}
if (substream_size > data_size - offset) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Size of substream %d of transformed 'glyf' table does not fit in table size");
}
substreams.at(i) = std::make_pair(data + offset, substream_size);
offset += substream_size;
@@ -560,7 +568,7 @@ bool ReconstructGlyf(const uint8_t* data, size_t data_size,
size_t glyph_size = 0;
uint16_t n_contours = 0;
if (!n_contour_stream.ReadU16(&n_contours)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to read 'numberOfContours' of glyph %d from transformed 'glyf' table", i);
}
uint8_t* glyf_dst = dst + loca_offset;
size_t glyf_dst_size = dst_size - loca_offset;
@@ -570,20 +578,20 @@ bool ReconstructGlyf(const uint8_t* data, size_t data_size,
uint16_t instruction_size = 0;
if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
&glyph_size, &have_instructions)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to process composite glyph %d from transformed 'glyf' table", i);
}
if (have_instructions) {
if (!Read255UShort(&glyph_stream, &instruction_size)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Failed to read 'instructionLength' of glyph %d from transformed 'glyf' table", i);
}
// No integer overflow here (instruction_size < 2^16).
if (instruction_size + 2U > glyf_dst_size - glyph_size) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("'instructionLength' of glyph %d from transformed 'glyf' table does not fit in the destination glyph size", i);
}
StoreU16(glyf_dst, glyph_size, instruction_size);
if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
instruction_size)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to read instructions of glyph %d from transformed 'glyf' table", i);
}
glyph_size += instruction_size + 2;
}
@@ -595,11 +603,11 @@ bool ReconstructGlyf(const uint8_t* data, size_t data_size,
uint16_t n_points_contour;
for (uint32_t j = 0; j < n_contours; ++j) {
if (!Read255UShort(&n_points_stream, &n_points_contour)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to read number of points of contour %d of glyph %d from transformed 'glyf' table", j, i);
}
n_points_vec.push_back(n_points_contour);
if (total_n_points + n_points_contour < total_n_points) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Negative number of points of contour %d of glyph %d from transformed 'glyf' table", j, i);
}
total_n_points += n_points_contour;
}
@@ -654,7 +662,7 @@ bool ReconstructGlyf(const uint8_t* data, size_t data_size,
}
if (!StorePoints(points, n_contours, instruction_size,
glyf_dst, glyf_dst_size, &glyph_size)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Failed to store points of glyph %d from the transformed 'glyf' table", i);
}
} else {
glyph_size = 0;
@@ -675,7 +683,7 @@ bool ReconstructGlyf(const uint8_t* data, size_t data_size,
assert(loca_values.size() == static_cast<size_t>(num_glyphs + 1));
if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values,
dst, dst_size)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to process 'bboxStream' from the transformed 'glyf' table");
}
return StoreLoca(loca_values, index_format, loca_buf, loca_size);
}
@@ -693,7 +701,8 @@ const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
return NULL;
}
-bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
+bool ReconstructTransformed(ots::OpenTypeFile* file,
+ const std::vector<Table>& tables, uint32_t tag,
const uint8_t* transformed_buf, size_t transformed_size,
uint8_t* dst, size_t dst_length) {
if (tag == TAG('g', 'l', 'y', 'f')) {
@@ -710,7 +719,7 @@ bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
dst_length) {
return OTS_FAILURE();
}
- return ReconstructGlyf(transformed_buf, transformed_size,
+ return ReconstructGlyf(file, transformed_buf, transformed_size,
dst + glyf_table->dst_offset, glyf_table->dst_length,
dst + loca_table->dst_offset, loca_table->dst_length);
} else if (tag == TAG('l', 'o', 'c', 'a')) {
@@ -803,18 +812,18 @@ bool ReadTableDirectory(ots::OpenTypeFile* file,
}
uint32_t dst_length;
if (!ReadBase128(buffer, &dst_length)) {
- return OTS_FAILURE_MSG("Failed to read \"origLength\" for table %4.4s", (char*)&tag);
+ return OTS_FAILURE_MSG("Failed to read 'origLength' for table '%c%c%c%c'", CHR(tag));
}
uint32_t transform_length = dst_length;
if ((flags & kWoff2FlagsTransform) != 0) {
if (!ReadBase128(buffer, &transform_length)) {
- return OTS_FAILURE_MSG("Failed to read \"transformLength\" for table %4.4s", (char*)&tag);
+ return OTS_FAILURE_MSG("Failed to read 'transformLength' for table '%c%c%c%c'", CHR(tag));
}
}
// Disallow huge numbers (> 1GB) for sanity.
if (transform_length > 1024 * 1024 * 1024 ||
dst_length > 1024 * 1024 * 1024) {
- return OTS_FAILURE_MSG("\"origLength\" or \"transformLength\" > 1GB");
+ return OTS_FAILURE_MSG("'origLength' or 'transformLength' > 1GB");
}
table->tag = tag;
table->flags = flags;
@@ -839,9 +848,9 @@ size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
return total_length;
}
-bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
- uint8_t* result, size_t result_length,
- const uint8_t* data, size_t length) {
+bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
+ uint8_t* result, size_t result_length,
+ const uint8_t* data, size_t length) {
static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2"
ots::Buffer buffer(data, length);
@@ -849,30 +858,35 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
uint32_t flavor = 0;
if (!buffer.ReadU32(&signature) || signature != kWoff2Signature ||
!buffer.ReadU32(&flavor)) {
- return OTS_FAILURE_MSG("Failed to read \"signature\" or \"flavor\", or not WOFF2 signature");
+ return OTS_FAILURE_MSG("Failed to read 'signature' or 'flavor', or not WOFF2 signature");
}
if (!IsValidVersionTag(ntohl(flavor))) {
- return OTS_FAILURE_MSG("Invalid \"flavor\"");
+ return OTS_FAILURE_MSG("Invalid 'flavor'");
}
uint32_t reported_length;
if (!buffer.ReadU32(&reported_length) || length != reported_length) {
- return OTS_FAILURE_MSG("Failed to read \"length\" or it does not match the actual file size");
+ return OTS_FAILURE_MSG("Failed to read 'length' or it does not match the actual file size");
}
uint16_t num_tables;
if (!buffer.ReadU16(&num_tables) || !num_tables) {
- return OTS_FAILURE_MSG("Failed to read \"numTables\"");
+ return OTS_FAILURE_MSG("Failed to read 'numTables'");
+ }
+
+ uint16_t reserved_value;
+ if (!buffer.ReadU16(&reserved_value)) {
+ return OTS_FAILURE_MSG("Failed to read 'reserved' field");
}
+
// We don't care about these fields of the header:
- // uint16_t reserved
- // uint32_t total_sfnt_size
- if (!buffer.Skip(6)) {
- return OTS_FAILURE_MSG("Failed to read \"reserve\" or \"totalSfntSize\"");
+ // uint32_t total_sfnt_size, the caller already passes it as result_length
+ if (!buffer.Skip(4)) {
+ return OTS_FAILURE_MSG("Failed to read 'totalSfntSize'");
}
uint32_t compressed_length;
if (!buffer.ReadU32(&compressed_length)) {
- return OTS_FAILURE_MSG("Failed to read \"totalCompressedSize\"");
+ return OTS_FAILURE_MSG("Failed to read 'totalCompressedSize'");
}
if (compressed_length > std::numeric_limits<uint32_t>::max()) {
return OTS_FAILURE();
@@ -880,11 +894,38 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
// We don't care about these fields of the header:
// uint16_t major_version, minor_version
- // uint32_t meta_offset, meta_length, meta_orig_length
- // uint32_t priv_offset, priv_length
- if (!buffer.Skip(24)) {
- return OTS_FAILURE();
+ if (!buffer.Skip(2 * 2)) {
+ return OTS_FAILURE_MSG("Failed to read 'majorVersion' or 'minorVersion'");
}
+
+ // Checks metadata block size.
+ uint32_t meta_offset;
+ uint32_t meta_length;
+ uint32_t meta_length_orig;
+ if (!buffer.ReadU32(&meta_offset) ||
+ !buffer.ReadU32(&meta_length) ||
+ !buffer.ReadU32(&meta_length_orig)) {
+ return OTS_FAILURE_MSG("Failed to read header metadata block fields");
+ }
+ if (meta_offset) {
+ if (meta_offset >= length || length - meta_offset < meta_length) {
+ return OTS_FAILURE_MSG("Invalid metadata block offset or length");
+ }
+ }
+
+ // Checks private data block size.
+ uint32_t priv_offset;
+ uint32_t priv_length;
+ if (!buffer.ReadU32(&priv_offset) ||
+ !buffer.ReadU32(&priv_length)) {
+ return OTS_FAILURE_MSG("Failed to read header private block fields");
+ }
+ if (priv_offset) {
+ if (priv_offset >= length || length - priv_offset < priv_length) {
+ return OTS_FAILURE_MSG("Invalid private block offset or length");
+ }
+ }
+
std::vector<Table> tables(num_tables);
if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) {
return OTS_FAILURE_MSG("Failed to read table directory");
@@ -904,8 +945,10 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
}
dst_offset = ots::Round4(dst_offset);
}
- if (ots::Round4(compressed_offset + compressed_length) > length || dst_offset > result_length) {
- return OTS_FAILURE();
+
+ uint64_t block_end = ots::Round4(compressed_offset + compressed_length);
+ if (block_end > length || dst_offset != result_length) {
+ return OTS_FAILURE_MSG("Uncompressed sfnt size mismatch");
}
const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables;
@@ -913,6 +956,32 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
return OTS_FAILURE();
}
+ if (meta_offset) {
+ if (block_end != meta_offset) {
+ return OTS_FAILURE_MSG("Invalid metadata block offset");
+ }
+ block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
+ static_cast<uint64_t>(meta_length));
+ if (block_end > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE_MSG("Invalid metadata block length");
+ }
+ }
+
+ if (priv_offset) {
+ if (block_end != priv_offset) {
+ return OTS_FAILURE_MSG("Invalid private block offset");
+ }
+ block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
+ static_cast<uint64_t>(priv_length));
+ if (block_end > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE_MSG("Invalid private block length");
+ }
+ }
+
+ if (block_end != ots::Round4(length)) {
+ return OTS_FAILURE_MSG("File length mismatch (trailing junk?)");
+ }
+
// Start building the font
size_t offset = 0;
offset = StoreU32(result, offset, flavor);
@@ -925,8 +994,13 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
offset = StoreU16(result, offset, output_search_range);
offset = StoreU16(result, offset, max_pow2);
offset = StoreU16(result, offset, (num_tables << 4) - output_search_range);
+
+ // sort tags in the table directory in ascending alphabetical order
+ std::vector<Table> sorted_tables(tables);
+ std::sort(sorted_tables.begin(), sorted_tables.end());
+
for (uint16_t i = 0; i < num_tables; ++i) {
- const Table* table = &tables.at(i);
+ const Table* table = &sorted_tables.at(i);
offset = StoreU32(result, offset, table->tag);
offset = StoreU32(result, offset, 0); // checksum, to fill in later
offset = StoreU32(result, offset, table->dst_offset);
@@ -951,7 +1025,7 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
const uint8_t* src_buf = data + compressed_offset;
if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t,
src_buf, compressed_length)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Failed to uncompress font data");
}
transform_buf = &uncompressed_buf[0];
@@ -971,9 +1045,9 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
std::memcpy(result + table->dst_offset, transform_buf,
transform_length);
} else {
- if (!ReconstructTransformed(tables, table->tag,
+ if (!ReconstructTransformed(file, tables, table->tag,
transform_buf, transform_length, result, result_length)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", CHR(table->tag));
}
}
@@ -983,7 +1057,7 @@ bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
}
}
- return FixChecksums(tables, result);
+ return FixChecksums(sorted_tables, result);
}
} // namespace ots
« no previous file with comments | « third_party/ots/src/woff2.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698