blob: 6a7b00019ce8bb958041e70ba58491f8a29e12e3 [file]
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef THIRD_PARTY_CREDENTIO_FORMATS_RIFF_READER_H_
#define THIRD_PARTY_CREDENTIO_FORMATS_RIFF_READER_H_
#include <cstdint>
#include <ostream>
#include <string>
#include "absl/functional/function_ref.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "formats/riff/constants.h"
#include "riegeli/bytes/reader.h"
namespace credentio {
// Information about a chunk in a RIFF file.
struct RiffChunk {
uint64_t offset = 0;
uint64_t length = 0;
std::string id; // 4-character chunk ID.
std::string type; // 4-character form type (only for RIFF/LIST chunks).
uint64_t data_offset = 0;
uint64_t data_length = 0;
bool HasSubchunks() const {
return id == kRiffChunkIdRiff || id == kRiffChunkIdList;
}
friend bool operator==(const RiffChunk& lhs, const RiffChunk& rhs) {
return lhs.offset == rhs.offset && lhs.length == rhs.length &&
lhs.id == rhs.id && lhs.type == rhs.type &&
lhs.data_offset == rhs.data_offset &&
lhs.data_length == rhs.data_length;
}
friend std::ostream& operator<<(std::ostream& os, const RiffChunk& chunk) {
return os << absl::StrCat("RiffChunk{offset: ", chunk.offset,
", length: ", chunk.length, ", id: ", chunk.id,
", type: ", chunk.type,
", data_offset: ", chunk.data_offset,
", data_length: ", chunk.data_length, "}");
}
};
// The function signature for processing a RIFF chunk.
using RiffChunkProcessor =
absl::FunctionRef<absl::StatusOr<bool>(const RiffChunk&)>;
// Iterates over all RIFF chunks in the given reader, calling the given
// `processor` function for each chunk.
//
// The `processor` function controls the iteration by returning an
// `absl::StatusOr<bool>`:
// - Return `true` to continue iterating over subsequent chunks.
// - Return `false` to stop iterating early. `IterateOverRiffChunks` will stop
// and return `absl::OkStatus()`.
// - Return an error status to abort iteration immediately and propagate the
// error back to the caller.
//
// The processor can also affect iteration by seeking the reader:
// - For container chunks (RIFF/LIST), sub-chunk iteration will start reading
// from wherever the processor leaves the reader.
// - To skip processing sub-chunks of a container chunk, the processor can seek
// the reader to the end of the current chunk.
// - The iterator will always reset the reader position to the end of the
// current chunk before proceeding to the next sibling chunk.
absl::Status IterateOverRiffChunks(riegeli::Reader& reader,
RiffChunkProcessor processor,
int64_t end_offset = -1);
// Reads the raw data for the given chunk.
absl::StatusOr<std::string> ReadRiffChunkData(riegeli::Reader& reader,
const RiffChunk& chunk);
// Returns true if the chunk is too large to read.
bool IsRiffChunkTooLarge(const RiffChunk& chunk);
} // namespace credentio
#endif // THIRD_PARTY_CREDENTIO_FORMATS_RIFF_READER_H_