Skip to content
28 changes: 26 additions & 2 deletions iaa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ int CompressIAA(uint8_t* input, uint32_t* input_length, uint8_t* output,

int UncompressIAA(uint8_t* input, uint32_t* input_length, uint8_t* output,
uint32_t* output_length, qpl_path_t execution_path,
int window_bits, bool* end_of_stream, bool detect_gzip_ext) {
int window_bits, bool* end_of_stream, bool detect_gzip_ext,
bool* window_too_large) {
Log(LogLevel::LOG_INFO, "UncompressIAA() Line ", __LINE__, " input_length ",
*input_length, "\n");

Expand Down Expand Up @@ -235,6 +236,14 @@ int UncompressIAA(uint8_t* input, uint32_t* input_length, uint8_t* output,

qpl_status status = qpl_execute_job(job);
if (status != QPL_STS_OK && status != QPL_STS_MORE_OUTPUT_NEEDED) {
// QPL_STS_BAD_DIST_ERR means the stream referenced a match further back
// than IAA's 4 kB history buffer. Unlike the other failures this one is not
// about this call: it says the producer used a larger window, and every
// remaining block of the same stream will be rejected for the same reason.
// Report it separately so the caller can stop submitting.
if (status == QPL_STS_BAD_DIST_ERR && window_too_large != nullptr) {
*window_too_large = true;
}
Log(LogLevel::LOG_ERROR, "UncompressIAA() Line ", __LINE__,
" qpl_execute_job status ", status, "\n");
return 1;
Expand Down Expand Up @@ -276,7 +285,7 @@ bool IsIAADecompressible(uint8_t* input, uint32_t input_length,
CompressedFormat format = GetCompressedFormat(window_bits);
if (format == CompressedFormat::ZLIB) {
int window = GetWindowSizeFromZlibHeader(input, input_length);
return window <= 12;
return window <= IAA_MAX_HISTORY_WINDOW_BITS;
}
// For raw deflate and gzip formats, QPL always reports total_in ==
// available_in regardless of where BFINAL=1 falls in the stream. This is
Expand All @@ -298,4 +307,19 @@ bool IsIAADecompressible(uint8_t* input, uint32_t input_length,
return input_length > kZipInputStreamBufferSize;
}

bool DeclaresIAACompatibleWindow(int window_bits) {
switch (GetCompressedFormat(window_bits)) {
case CompressedFormat::DEFLATE_RAW:
return -window_bits <= IAA_MAX_HISTORY_WINDOW_BITS;
case CompressedFormat::ZLIB:
return window_bits <= IAA_MAX_HISTORY_WINDOW_BITS;
case CompressedFormat::GZIP:
// 16 is the offset zlib adds to select the gzip wrapper; what is left is
// the window.
return window_bits - 16 <= IAA_MAX_HISTORY_WINDOW_BITS;
default:
return false;
}
}

#endif // USE_IAA
27 changes: 23 additions & 4 deletions iaa.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
inline constexpr unsigned int PREPENDED_BLOCK_LENGTH = 5;
inline constexpr unsigned int MAX_BUFFER_SIZE = (2 << 20);

// IAA's decompressor has a fixed 4 kB history buffer, so it can only follow a
// stream whose match distances stay inside a 2^12-byte window.
inline constexpr int IAA_MAX_HISTORY_WINDOW_BITS = 12;

class IAAJob {
public:
IAAJob() : jobs_(3) {}
Expand Down Expand Up @@ -55,10 +59,18 @@ int CompressIAA(uint8_t* input, uint32_t* input_length, uint8_t* output,
int window_bits, uint32_t max_compressed_size = 0,
bool gzip_ext = false);

int UncompressIAA(uint8_t* input, uint32_t* input_length, uint8_t* output,
uint32_t* output_length, qpl_path_t execution_path,
int window_bits, bool* end_of_stream,
bool detect_gzip_ext = false);
// window_too_large, when non-null, is set to true if the job was rejected
// because the stream references match distances beyond IAA's fixed 4 kB history
// buffer (QPL_STS_BAD_DIST_ERR). That is a property of whichever compressor
// produced the stream, not of the individual block, so a caller that sees it
// can stop offering the rest of that stream to IAA. It is never set to false;
// the caller owns initialisation.
VISIBLE_FOR_TESTING int UncompressIAA(uint8_t* input, uint32_t* input_length,
uint8_t* output, uint32_t* output_length,
qpl_path_t execution_path,
int window_bits, bool* end_of_stream,
bool detect_gzip_ext = false,
bool* window_too_large = nullptr);

VISIBLE_FOR_TESTING bool SupportedOptionsIAA(int window_bits,
uint32_t input_length,
Expand All @@ -68,4 +80,11 @@ VISIBLE_FOR_TESTING bool IsIAADecompressible(uint8_t* input,
uint32_t input_length,
int window_bits);

// True if window_bits declares a maximum window IAA's history buffer can
// follow, whatever the format's own header says. inflateReset2() takes such a
// declaration from the caller, and it is a stronger statement than a remembered
// rejection: a stream that referenced further back than this would be refused
// by zlib too.
VISIBLE_FOR_TESTING bool DeclaresIAACompatibleWindow(int window_bits);

#endif // USE_IAA
Loading
Loading