in riegeli/snappy/framed/framed_snappy_reader.cc [91:220]
bool FramedSnappyReaderBase::PullBehindScratch() {
RIEGELI_ASSERT_EQ(available(), 0u)
<< "Failed precondition of PullableReader::PullBehindScratch(): "
"some data available, use Pull() instead";
RIEGELI_ASSERT(!scratch_used())
<< "Failed precondition of PullableReader::PullBehindScratch(): "
"scratch used";
if (ABSL_PREDICT_FALSE(!healthy())) return false;
Reader& src = *src_reader();
truncated_ = false;
while (src.Pull(sizeof(uint32_t))) {
const uint32_t chunk_header = ReadLittleEndian32(src.cursor());
const uint8_t chunk_type = static_cast<uint8_t>(chunk_header);
const size_t chunk_length = IntCast<size_t>(chunk_header >> 8);
if (ABSL_PREDICT_FALSE(!src.Pull(sizeof(uint32_t) + chunk_length))) {
set_buffer();
if (ABSL_PREDICT_FALSE(!src.healthy())) {
return FailWithoutAnnotation(AnnotateOverSrc(src.status()));
}
truncated_ = true;
return false;
}
if (ABSL_PREDICT_FALSE(src.pos() == 0 &&
chunk_type != 0xff /* Stream identifier */)) {
set_buffer();
return FailInvalidStream("missing stream identifier");
}
switch (chunk_type) {
case 0x00: { // Compressed data.
if (ABSL_PREDICT_FALSE(chunk_length < sizeof(uint32_t))) {
set_buffer();
return FailInvalidStream("compressed data too short");
}
const uint32_t checksum =
ReadLittleEndian32(src.cursor() + sizeof(uint32_t));
const char* const compressed_data = src.cursor() + 2 * sizeof(uint32_t);
const size_t compressed_length = chunk_length - sizeof(uint32_t);
size_t uncompressed_length;
if (ABSL_PREDICT_FALSE(!snappy::GetUncompressedLength(
compressed_data, compressed_length, &uncompressed_length))) {
set_buffer();
return FailInvalidStream("invalid uncompressed length");
}
if (ABSL_PREDICT_FALSE(uncompressed_length > snappy::kBlockSize)) {
set_buffer();
return FailInvalidStream("uncompressed length too large");
}
uncompressed_.Reset(uncompressed_length);
if (ABSL_PREDICT_FALSE(!snappy::RawUncompress(
compressed_data, compressed_length, uncompressed_.data()))) {
set_buffer();
return FailInvalidStream("invalid compressed data");
}
if (ABSL_PREDICT_FALSE(
MaskChecksum(crc32c::Crc32c(
uncompressed_.data(), uncompressed_length)) != checksum)) {
set_buffer();
return FailInvalidStream(
"Invalid FramedSnappy-compressed stream: wrong checksum");
}
src.move_cursor(sizeof(uint32_t) + chunk_length);
if (ABSL_PREDICT_FALSE(uncompressed_length == 0)) continue;
if (ABSL_PREDICT_FALSE(uncompressed_length >
std::numeric_limits<Position>::max() -
limit_pos())) {
set_buffer(uncompressed_.data());
return FailOverflow();
}
set_buffer(uncompressed_.data(), uncompressed_length);
move_limit_pos(available());
return true;
}
case 0x01: { // Uncompressed data.
if (ABSL_PREDICT_FALSE(chunk_length < sizeof(uint32_t))) {
set_buffer();
return FailInvalidStream("uncompressed data too short");
}
const uint32_t checksum =
ReadLittleEndian32(src.cursor() + sizeof(uint32_t));
const char* const uncompressed_data =
src.cursor() + 2 * sizeof(uint32_t);
const size_t uncompressed_length = chunk_length - sizeof(uint32_t);
if (ABSL_PREDICT_FALSE(uncompressed_length > snappy::kBlockSize)) {
set_buffer();
return FailInvalidStream("uncompressed length too large");
}
if (ABSL_PREDICT_FALSE(MaskChecksum(crc32c::Crc32c(
uncompressed_data, uncompressed_length)) !=
checksum)) {
set_buffer();
return FailInvalidStream("wrong checksum");
}
src.move_cursor(sizeof(uint32_t) + chunk_length);
if (ABSL_PREDICT_FALSE(uncompressed_length == 0)) continue;
if (ABSL_PREDICT_FALSE(uncompressed_length >
std::numeric_limits<Position>::max() -
limit_pos())) {
set_buffer();
return FailOverflow();
}
set_buffer(uncompressed_data, uncompressed_length);
move_limit_pos(available());
return true;
}
case 0xff: // Stream identifier.
if (ABSL_PREDICT_FALSE(
absl::string_view(src.cursor() + sizeof(uint32_t),
chunk_length) !=
absl::string_view("sNaPpY", 6))) {
set_buffer();
return FailInvalidStream("invalid stream identifier");
}
src.move_cursor(sizeof(uint32_t) + chunk_length);
continue;
default:
if (ABSL_PREDICT_FALSE(chunk_type < 0x80)) {
set_buffer();
return FailInvalidStream("reserved unskippable chunk");
}
src.move_cursor(sizeof(uint32_t) + chunk_length);
continue;
}
}
set_buffer();
if (ABSL_PREDICT_FALSE(!src.healthy())) {
return FailWithoutAnnotation(AnnotateOverSrc(src.status()));
}
if (ABSL_PREDICT_FALSE(src.available() > 0)) truncated_ = true;
return false;
}