bool FramedSnappyReaderBase::PullBehindScratch()

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;
}