Bug 1396026 - Update OTS to accept Awami Nastaliq. r=froydnj,jfkthame

MozReview-Commit-ID: EvF3YDhuwNn

--HG--
extra : rebase_source : 20046aa4f2695f923574bf00207f06a113d1f246
This commit is contained in:
Kevin Hsieh 2017-09-07 10:40:59 -07:00
Родитель 9a59011a99
Коммит a0a376f2f1
8 изменённых файлов: 186 добавлений и 107 удалений

Просмотреть файл

@ -2,7 +2,7 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
Our reference repository is https://github.com/khaledhosny/ots/.
Current revision: e2d4b5daba24e746a48d240e90d92fe09a20b681 (5.2.0)
Current revision: f87b4556191e4132ef5c47365762eb88ace97fc3 (6.0.0)
Upstream files included: LICENSE, src/, include/, tests/*.cc

Просмотреть файл

@ -10,25 +10,23 @@ diff --git a/gfx/ots/src/glat.cc b/gfx/ots/src/glat.cc
#include <list>
namespace ots {
@@ -201,13 +201,15 @@ bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
@@ -201,14 +201,15 @@ bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
return DropGraphite("Illegal nested compression");
}
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE, 0);
- int ret = LZ4_decompress_safe(
- reinterpret_cast<const char*>(data + table.offset()),
- reinterpret_cast<char*>(decompressed.data()),
- table.remaining(),
- decompressed.size());
- if (ret < 0) {
- return DropGraphite("Decompression failed with error code %d", ret);
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
- int ret = LZ4_decompress_safe_partial(
+ size_t outputSize = 0;
+ if (!mozilla::Compression::LZ4::decompress(
+ reinterpret_cast<const char*>(data + table.offset()),
+ table.remaining(),
+ reinterpret_cast<char*>(decompressed.data()),
+ decompressed.size(),
+ &outputSize) ||
+ outputSize != (this->compHead & FULL_SIZE)) {
+ bool ret = mozilla::Compression::LZ4::decompressPartial(
reinterpret_cast<const char*>(data + table.offset()),
- reinterpret_cast<char*>(decompressed.data()),
table.remaining(), // input buffer size (input size + padding)
+ reinterpret_cast<char*>(decompressed.data()),
decompressed.size(), // target output size
- decompressed.size()); // output buffer size
- if (ret != decompressed.size()) {
- return DropGraphite("Decompression failed with error code %d", ret);
+ &outputSize); // return output size
+ if (!ret || outputSize != decompressed.size()) {
+ return DropGraphite("Decompression failed");
}
return this->Parse(decompressed.data(), decompressed.size(), true);
@ -45,25 +43,23 @@ diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
#include <cmath>
namespace ots {
@@ -39,13 +39,15 @@ bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
@@ -39,14 +39,15 @@ bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
return DropGraphite("Illegal nested compression");
}
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE, 0);
- int ret = LZ4_decompress_safe(
- reinterpret_cast<const char*>(data + table.offset()),
- reinterpret_cast<char*>(decompressed.data()),
- table.remaining(),
- decompressed.size());
- if (ret < 0) {
- return DropGraphite("Decompression failed with error code %d", ret);
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
- int ret = LZ4_decompress_safe_partial(
+ size_t outputSize = 0;
+ if (!mozilla::Compression::LZ4::decompress(
+ reinterpret_cast<const char*>(data + table.offset()),
+ table.remaining(),
+ reinterpret_cast<char*>(decompressed.data()),
+ decompressed.size(),
+ &outputSize) ||
+ outputSize != (this->compHead & FULL_SIZE)) {
+ bool ret = mozilla::Compression::LZ4::decompressPartial(
reinterpret_cast<const char*>(data + table.offset()),
- reinterpret_cast<char*>(decompressed.data()),
table.remaining(), // input buffer size (input size + padding)
+ reinterpret_cast<char*>(decompressed.data()),
decompressed.size(), // target output size
- decompressed.size()); // output buffer size
- if (ret != decompressed.size()) {
- return DropGraphite("Decompression failed with error code %d", ret);
+ &outputSize); // return output size
+ if (!ret || outputSize != decompressed.size()) {
+ return DropGraphite("Decompression failed");
}
return this->Parse(decompressed.data(), decompressed.size(), true);

Просмотреть файл

@ -200,15 +200,15 @@ bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
if (prevent_decompression) {
return DropGraphite("Illegal nested compression");
}
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE, 0);
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
size_t outputSize = 0;
if (!mozilla::Compression::LZ4::decompress(
reinterpret_cast<const char*>(data + table.offset()),
table.remaining(),
reinterpret_cast<char*>(decompressed.data()),
decompressed.size(),
&outputSize) ||
outputSize != (this->compHead & FULL_SIZE)) {
bool ret = mozilla::Compression::LZ4::decompressPartial(
reinterpret_cast<const char*>(data + table.offset()),
table.remaining(), // input buffer size (input size + padding)
reinterpret_cast<char*>(decompressed.data()),
decompressed.size(), // target output size
&outputSize); // return output size
if (!ret || outputSize != decompressed.size()) {
return DropGraphite("Decompression failed");
}
return this->Parse(decompressed.data(), decompressed.size(), true);
@ -388,7 +388,7 @@ GlatEntry::ParsePart(Buffer& table) {
}
//this->attributes.resize(this->num);
for (unsigned i = 0; i < this->num; ++i) {
for (int i = 0; i < this->num; ++i) {
this->attributes.emplace_back();
if (!table.ReadS16(&this->attributes[i])) {
return parent->Error("GlatEntry: Failed to read attribute %u", i);

Просмотреть файл

@ -311,15 +311,15 @@ bool ParseClassDefFormat2(const ots::Font *font,
// Skip format field.
if (!subtable.Skip(2)) {
return OTS_FAILURE_MSG("Failed to skip format of class defintion header");
return OTS_FAILURE_MSG("Failed to read class definition format");
}
uint16_t range_count = 0;
if (!subtable.ReadU16(&range_count)) {
return OTS_FAILURE_MSG("Failed to read range count in class definition");
return OTS_FAILURE_MSG("Failed to read classRangeCount");
}
if (range_count > num_glyphs) {
return OTS_FAILURE_MSG("bad range count: %u", range_count);
return OTS_FAILURE_MSG("classRangeCount > glyph count: %u > %u", range_count, num_glyphs);
}
uint16_t last_end = 0;
@ -330,13 +330,16 @@ bool ParseClassDefFormat2(const ots::Font *font,
if (!subtable.ReadU16(&start) ||
!subtable.ReadU16(&end) ||
!subtable.ReadU16(&class_value)) {
return OTS_FAILURE_MSG("Failed to read class definition reange %d", i);
return OTS_FAILURE_MSG("Failed to read ClassRangeRecord %d", i);
}
if (start > end || (last_end && start <= last_end)) {
return OTS_FAILURE_MSG("glyph range is overlapping.in range %d", i);
if (start > end) {
return OTS_FAILURE_MSG("ClassRangeRecord %d, start > end: %u > %u", i, start, end);
}
if (last_end && start <= last_end) {
return OTS_FAILURE_MSG("ClassRangeRecord %d start overlaps with end of the previous one: %u <= %u", i, start, last_end);
}
if (class_value > num_classes) {
return OTS_FAILURE_MSG("bad class value: %u", class_value);
return OTS_FAILURE_MSG("ClassRangeRecord %d class > number of classes: %u > %u", i, class_value, num_classes);
}
last_end = end;
}

Просмотреть файл

@ -38,15 +38,15 @@ bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
if (prevent_decompression) {
return DropGraphite("Illegal nested compression");
}
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE, 0);
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
size_t outputSize = 0;
if (!mozilla::Compression::LZ4::decompress(
reinterpret_cast<const char*>(data + table.offset()),
table.remaining(),
reinterpret_cast<char*>(decompressed.data()),
decompressed.size(),
&outputSize) ||
outputSize != (this->compHead & FULL_SIZE)) {
bool ret = mozilla::Compression::LZ4::decompressPartial(
reinterpret_cast<const char*>(data + table.offset()),
table.remaining(), // input buffer size (input size + padding)
reinterpret_cast<char*>(decompressed.data()),
decompressed.size(), // target output size
&outputSize); // return output size
if (!ret || outputSize != decompressed.size()) {
return DropGraphite("Decompression failed");
}
return this->Parse(decompressed.data(), decompressed.size(), true);
@ -255,8 +255,13 @@ bool OpenTypeSILF::SILSub::ParsePart(Buffer& table) {
}
}
if (!table.ReadU16(&this->lbGID) || this->lbGID > this->maxGlyphID) {
return parent->Error("SILSub: Failed to read valid lbGID");
if (!table.ReadU16(&this->lbGID)) {
return parent->Error("SILSub: Failed to read lbGID");
}
if (this->lbGID > this->maxGlyphID) {
parent->Warning("SILSub: lbGID %u outside range 0..%u, replaced with 0",
this->lbGID, this->maxGlyphID);
this->lbGID = 0;
}
if (parent->version >> 16 >= 3 &&
@ -280,19 +285,27 @@ bool OpenTypeSILF::SILSub::ParsePart(Buffer& table) {
if (!table.ReadU16(&this->numPseudo)) {
return parent->Error("SILSub: Failed to read numPseudo");
}
if (!table.ReadU16(&this->searchPseudo) || this->searchPseudo !=
(this->numPseudo == 0 ? 0 : // protect against log2(0)
(unsigned)std::pow(2, std::floor(std::log2(this->numPseudo))))) {
return parent->Error("SILSub: Failed to read valid searchPseudo");
// The following three fields are deprecated and ignored. We fix them up here
// just for internal consistency, but the Graphite engine doesn't care.
if (!table.ReadU16(&this->searchPseudo) ||
!table.ReadU16(&this->pseudoSelector) ||
!table.ReadU16(&this->pseudoShift)) {
return parent->Error("SILSub: Failed to read searchPseudo..pseudoShift");
}
if (!table.ReadU16(&this->pseudoSelector) || this->pseudoSelector !=
(this->numPseudo == 0 ? 0 : // protect against log2(0)
(unsigned)std::floor(std::log2(this->numPseudo)))) {
return parent->Error("SILSub: Failed to read valid pseudoSelector");
}
if (!table.ReadU16(&this->pseudoShift) ||
this->pseudoShift != this->numPseudo - this->searchPseudo) {
return parent->Error("SILSub: Failed to read valid pseudoShift");
if (this->numPseudo == 0) {
if (this->searchPseudo != 0 || this->pseudoSelector != 0 || this->pseudoShift != 0) {
this->searchPseudo = this->pseudoSelector = this->pseudoShift = 0;
}
} else {
unsigned floorLog2 = std::floor(std::log2(this->numPseudo));
if (this->searchPseudo != 6 * (unsigned)std::pow(2, floorLog2) ||
this->pseudoSelector != floorLog2 ||
this->pseudoShift != 6 * this->numPseudo - this->searchPseudo) {
this->searchPseudo = 6 * (unsigned)std::pow(2, floorLog2);
this->pseudoSelector = floorLog2;
this->pseudoShift = 6 * this->numPseudo - this->searchPseudo;
}
}
//this->pMaps.resize(this->numPseudo, parent);
@ -541,19 +554,26 @@ LookupClass::ParsePart(Buffer& table) {
if (!table.ReadU16(&this->numIDs)) {
return parent->Error("LookupClass: Failed to read numIDs");
}
if (!table.ReadU16(&this->searchRange) || this->searchRange !=
(this->numIDs == 0 ? 0 : // protect against log2(0)
(unsigned)std::pow(2, std::floor(std::log2(this->numIDs))))) {
return parent->Error("LookupClass: Failed to read valid searchRange");
if (!table.ReadU16(&this->searchRange) ||
!table.ReadU16(&this->entrySelector) ||
!table.ReadU16(&this->rangeShift)) {
return parent->Error("LookupClass: Failed to read searchRange..rangeShift");
}
if (!table.ReadU16(&this->entrySelector) || this->entrySelector !=
(this->numIDs == 0 ? 0 : // protect against log2(0)
(unsigned)std::floor(std::log2(this->numIDs)))) {
return parent->Error("LookupClass: Failed to read valid entrySelector");
}
if (!table.ReadU16(&this->rangeShift) ||
this->rangeShift != this->numIDs - this->searchRange) {
return parent->Error("LookupClass: Failed to read valid rangeShift");
if (this->numIDs == 0) {
if (this->searchRange != 0 || this->entrySelector != 0 || this->rangeShift != 0) {
parent->Warning("LookupClass: Correcting binary-search header for zero-length LookupPair list");
this->searchRange = this->entrySelector = this->rangeShift = 0;
}
} else {
unsigned floorLog2 = std::floor(std::log2(this->numIDs));
if (this->searchRange != (unsigned)std::pow(2, floorLog2) ||
this->entrySelector != floorLog2 ||
this->rangeShift != this->numIDs - this->searchRange) {
parent->Warning("LookupClass: Correcting binary-search header for LookupPair list");
this->searchRange = (unsigned)std::pow(2, floorLog2);
this->entrySelector = floorLog2;
this->rangeShift = this->numIDs - this->searchRange;
}
}
//this->lookups.resize(this->numIDs, parent);
@ -661,19 +681,27 @@ SILPass::ParsePart(Buffer& table, const size_t SILSub_init_offset,
if (!table.ReadU16(&this->numRange)) {
return parent->Error("SILPass: Failed to read numRange");
}
if (!table.ReadU16(&this->searchRange) || this->searchRange !=
(this->numRange == 0 ? 0 : // protect against log2(0)
(unsigned)std::pow(2, std::floor(std::log2(this->numRange))))) {
return parent->Error("SILPass: Failed to read valid searchRange");
// The following three fields are deprecated and ignored. We fix them up here
// just for internal consistency, but the Graphite engine doesn't care.
if (!table.ReadU16(&this->searchRange) ||
!table.ReadU16(&this->entrySelector) ||
!table.ReadU16(&this->rangeShift)) {
return parent->Error("SILPass: Failed to read searchRange..rangeShift");
}
if (!table.ReadU16(&this->entrySelector) || this->entrySelector !=
(this->numRange == 0 ? 0 : // protect against log2(0)
(unsigned)std::floor(std::log2(this->numRange)))) {
return parent->Error("SILPass: Failed to read valid entrySelector");
}
if (!table.ReadU16(&this->rangeShift) ||
this->rangeShift != this->numRange - this->searchRange) {
return parent->Error("SILPass: Failed to read valid rangeShift");
if (this->numRange == 0) {
if (this->searchRange != 0 || this->entrySelector != 0 || this->rangeShift != 0) {
this->searchRange = this->entrySelector = this->rangeShift = 0;
}
} else {
unsigned floorLog2 = std::floor(std::log2(this->numRange));
if (this->searchRange != 6 * (unsigned)std::pow(2, floorLog2) ||
this->entrySelector != floorLog2 ||
this->rangeShift != 6 * this->numRange - this->searchRange) {
this->searchRange = 6 * (unsigned)std::pow(2, floorLog2);
this->entrySelector = floorLog2;
this->rangeShift = 6 * this->numRange - this->searchRange;
}
}
//this->ranges.resize(this->numRange, parent);

Просмотреть файл

@ -22,19 +22,27 @@ bool OpenTypeSILL::Parse(const uint8_t* data, size_t length) {
if (!table.ReadU16(&this->numLangs)) {
return Drop("Failed to read numLangs");
}
if (!table.ReadU16(&this->searchRange) || this->searchRange !=
(this->numLangs == 0 ? 0 : // protect against log2(0)
(unsigned)std::pow(2, std::floor(std::log2(this->numLangs))))) {
return Drop("Failed to read valid searchRange");
// The following three fields are deprecated and ignored. We fix them up here
// just for internal consistency, but the Graphite engine doesn't care.
if (!table.ReadU16(&this->searchRange) ||
!table.ReadU16(&this->entrySelector) ||
!table.ReadU16(&this->rangeShift)) {
return Drop("Failed to read searchRange..rangeShift");
}
if (!table.ReadU16(&this->entrySelector) || this->entrySelector !=
(this->numLangs == 0 ? 0 : // protect against log2(0)
(unsigned)std::floor(std::log2(this->numLangs)))) {
return Drop("Failed to read valid entrySelector");
}
if (!table.ReadU16(&this->rangeShift) ||
this->rangeShift != this->numLangs - this->searchRange) {
return Drop("Failed to read valid rangeShift");
if (this->numLangs == 0) {
if (this->searchRange != 0 || this->entrySelector != 0 || this->rangeShift != 0) {
this->searchRange = this->entrySelector = this->rangeShift = 0;
}
} else {
unsigned floorLog2 = std::floor(std::log2(this->numLangs));
if (this->searchRange != (unsigned)std::pow(2, floorLog2) ||
this->entrySelector != floorLog2 ||
this->rangeShift != this->numLangs - this->searchRange) {
this->searchRange = (unsigned)std::pow(2, floorLog2);
this->entrySelector = floorLog2;
this->rangeShift = this->numLangs - this->searchRange;
}
}
std::unordered_set<size_t> unverified;

Просмотреть файл

@ -81,3 +81,24 @@ LZ4::decompress(const char* aSource, size_t aInputSize, char* aDest,
return false;
}
bool
LZ4::decompressPartial(const char* aSource, size_t aInputSize, char* aDest,
size_t aMaxOutputSize, size_t* aOutputSize)
{
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
MOZ_ASSERT(maxOutputSizeChecked.isValid());
CheckedInt<int> inputSizeChecked = aInputSize;
MOZ_ASSERT(inputSizeChecked.isValid());
int ret = LZ4_decompress_safe_partial(aSource, aDest,
inputSizeChecked.value(),
maxOutputSizeChecked.value(),
maxOutputSizeChecked.value());
if (ret >= 0) {
*aOutputSize = ret;
return true;
}
*aOutputSize = 0;
return false;
}

Просмотреть файл

@ -96,6 +96,29 @@ public:
decompress(const char* aSource, size_t aInputSize, char* aDest,
size_t aMaxOutputSize, size_t* aOutputSize);
/**
* If the source stream is malformed, the function will stop decoding
* and return false.
*
* This function never writes beyond aDest + aMaxOutputSize, and is
* therefore protected against malicious data packets. It also ignores
* unconsumed input upon reaching aMaxOutputSize and can therefore be used
* for partial decompression.
*
* Note: Destination buffer must be already allocated. This version is
* slightly slower than the decompress without the aMaxOutputSize.
*
* @param aInputSize is the length of the input compressed data
* @param aMaxOutputSize is the size of the destination buffer (which must be
* already allocated)
* @param aOutputSize the actual number of bytes decoded in the destination
* buffer (necessarily <= aMaxOutputSize)
* @return true on success, false on failure
*/
static MFBT_API MOZ_MUST_USE bool
decompressPartial(const char* aSource, size_t aInputSize, char* aDest,
size_t aMaxOutputSize, size_t* aOutputSize);
/*
* Provides the maximum size that LZ4 may output in a "worst case"
* scenario (input data not compressible) primarily useful for memory