Bug 1396026 - Update OTS to accept Awami Nastaliq. r?jfkthame,froydnj
MozReview-Commit-ID: EvF3YDhuwNn
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,12 +1,12 @@
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
Additional files: README.mozilla, src/moz.build
Additional patch: ots-visibility.patch (bug 711079).
Additional patch: ots-lz4.patch
--- a/gfx/ots/ots-lz4.patch
+++ b/gfx/ots/ots-lz4.patch
@@ -5,66 +5,62 @@ diff --git a/gfx/ots/src/glat.cc b/gfx/o
#include "glat.h"
#include "gloc.h"
-#include "lz4.h"
+#include "mozilla/Compression.h"
#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()),
+ std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
+- int ret = LZ4_decompress_safe_partial(
++ size_t outputSize = 0;
++ bool ret = mozilla::Compression::LZ4::decompressPartial(
+ reinterpret_cast<const char*>(data + table.offset()),
- reinterpret_cast<char*>(decompressed.data()),
-- table.remaining(),
-- decompressed.size());
-- if (ret < 0) {
+ 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);
-+ 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)) {
++ &outputSize); // return output size
++ if (!ret || outputSize != decompressed.size()) {
+ return DropGraphite("Decompression failed");
}
return this->Parse(decompressed.data(), decompressed.size(), true);
}
diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
--- a/gfx/ots/src/silf.cc
+++ b/gfx/ots/src/silf.cc
@@ -5,7 +5,7 @@
#include "silf.h"
#include "name.h"
-#include "lz4.h"
+#include "mozilla/Compression.h"
#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()),
+ std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
+- int ret = LZ4_decompress_safe_partial(
++ size_t outputSize = 0;
++ bool ret = mozilla::Compression::LZ4::decompressPartial(
+ reinterpret_cast<const char*>(data + table.offset()),
- reinterpret_cast<char*>(decompressed.data()),
-- table.remaining(),
-- decompressed.size());
-- if (ret < 0) {
+ 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);
-+ 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)) {
++ &outputSize); // return output size
++ if (!ret || outputSize != decompressed.size()) {
+ return DropGraphite("Decompression failed");
}
return this->Parse(decompressed.data(), decompressed.size(), true);
}
--- a/gfx/ots/src/glat.cc
+++ b/gfx/ots/src/glat.cc
@@ -195,25 +195,25 @@ bool OpenTypeGLAT_v3::Parse(const uint8_
}
switch ((this->compHead & SCHEME) >> 27) {
case 0: // uncompressed
break;
case 1: { // lz4
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);
}
default:
return DropGraphite("Unknown compression scheme");
}
if (this->compHead & RESERVED) {
@@ -383,17 +383,17 @@ GlatEntry::ParsePart(Buffer& table) {
if (!table.ReadS16(&this->attNum)) {
return parent->Error("GlatEntry: Failed to read attNum");
}
if (!table.ReadS16(&this->num) || this->num < 0) {
return parent->Error("GlatEntry: Failed to read valid num");
}
//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);
}
}
return true;
}
--- a/gfx/ots/src/layout.cc
+++ b/gfx/ots/src/layout.cc
@@ -306,42 +306,45 @@ bool ParseClassDefFormat1(const ots::Fon
bool ParseClassDefFormat2(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t num_classes) {
ots::Buffer subtable(data, length);
// 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;
for (unsigned i = 0; i < range_count; ++i) {
uint16_t start = 0;
uint16_t end = 0;
uint16_t class_value = 0;
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;
}
return true;
}
bool ParseCoverageFormat1(const ots::Font *font,
--- a/gfx/ots/src/silf.cc
+++ b/gfx/ots/src/silf.cc
@@ -33,25 +33,25 @@ bool OpenTypeSILF::Parse(const uint8_t*
if (this->version >> 16 >= 5) {
switch ((this->compHead & SCHEME) >> 27) {
case 0: // uncompressed
break;
case 1: { // lz4
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);
}
default:
return DropGraphite("Unknown compression scheme");
}
}
@@ -250,18 +250,23 @@ bool OpenTypeSILF::SILSub::ParsePart(Buf
//this->scriptTag.resize(this->numScriptTag);
for (unsigned i = 0; i < this->numScriptTag; ++i) {
this->scriptTag.emplace_back();
if (!table.ReadU32(&this->scriptTag[i])) {
return parent->Error("SILSub: Failed to read scriptTag[%u]", i);
}
}
- 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 &&
table.offset() != init_offset + this->passOffset) {
return parent->Error("SILSub: passOffset check failed");
}
unsigned long last_oPass = 0;
//this->oPasses.resize(static_cast<unsigned>(this->numPasses) + 1);
@@ -275,29 +280,37 @@ bool OpenTypeSILF::SILSub::ParsePart(Buf
if (parent->version >> 16 >= 3 &&
table.offset() != init_offset + this->pseudosOffset) {
return parent->Error("SILSub: pseudosOffset check failed");
}
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);
for (unsigned i = 0; i < numPseudo; i++) {
this->pMaps.emplace_back(parent);
if (!this->pMaps[i].ParsePart(table)) {
return parent->Error("SILSub: Failed to read pMaps[%u]", i);
}
@@ -536,29 +549,36 @@ ClassMap::SerializePart(OTSStream* out)
return true;
}
bool OpenTypeSILF::SILSub::ClassMap::
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);
for (unsigned i = 0; i < numIDs; ++i) {
this->lookups.emplace_back(parent);
if (!this->lookups[i].ParsePart(table)) {
return parent->Error("LookupClass: Failed to read lookups[%u]", i);
}
@@ -656,29 +676,37 @@ SILPass::ParsePart(Buffer& table, const
return parent->Error("SILPass: Failed to read numSuccess");
}
if (!table.ReadU16(&this->numColumns)) {
return parent->Error("SILPass: Failed to read numColumns");
}
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);
for (unsigned i = 0 ; i < this->numRange; ++i) {
this->ranges.emplace_back(parent);
if (!this->ranges[i].ParsePart(table)) {
return parent->Error("SILPass: Failed to read ranges[%u]", i);
}
--- a/gfx/ots/src/sill.cc
+++ b/gfx/ots/src/sill.cc
@@ -17,29 +17,37 @@ bool OpenTypeSILL::Parse(const uint8_t*
Buffer table(data, length);
if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
return Drop("Failed to read valid version");
}
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;
//this->entries.resize(static_cast<unsigned long>(this->numLangs) + 1, this);
for (unsigned long i = 0; i <= this->numLangs; ++i) {
this->entries.emplace_back(this);
LanguageEntry& entry = this->entries[i];
if (!entry.ParsePart(table)) {
--- a/mfbt/Compression.cpp
+++ b/mfbt/Compression.cpp
@@ -75,8 +75,29 @@ LZ4::decompress(const char* aSource, siz
*aOutputSize = ret;
return true;
}
*aOutputSize = 0;
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;
+}
--- a/mfbt/Compression.h
+++ b/mfbt/Compression.h
@@ -91,16 +91,39 @@ public:
* @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
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
* allocation of output buffer.
* note : this function is limited by "int" range (2^31-1)
*
* @param aInputSize is the input size. Max supported value is ~1.9GB
* @return maximum output size in a "worst case" scenario