/* * Copyright (c) 2023, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ #include "Details.h" #include #include #include namespace RIFF { StringView ChunkID::as_ascii_string() const { return StringView { id_data.span() }; } bool ChunkID::operator==(StringView other_string) const { return as_ascii_string() == other_string; } namespace Detail { template auto ChunkHeader::read_from_stream(Stream& stream) -> ErrorOr { auto id = TRY(stream.read_value()); u32 size = TRY(stream.read_value()); return ChunkHeader { id, size }; } template auto FileHeader::read_from_stream(Stream& stream) -> ErrorOr { auto header = TRY(stream.read_value()); auto subformat = TRY(stream.read_value()); return FileHeader { header, subformat }; } template Chunk::Chunk(HeaderType header, ReadonlyBytes data) : m_header(header) , m_data(data) { VERIFY(data.size() == header.size); } template FixedMemoryStream Chunk::data_stream() const { return FixedMemoryStream { m_data }; } template auto Chunk::decode(ReadonlyBytes data) -> ErrorOr { auto data_stream = FixedMemoryStream { data }; auto header = TRY(HeaderType::read_from_stream(data_stream)); if (data.size() < sizeof(HeaderType) + header.size) return Error::from_string_literal("Not enough data for IFF/RIFF chunk"); return Chunk { header, data.slice(sizeof(HeaderType), header.size) }; } template auto Chunk::decode_and_advance(ReadonlyBytes& data) -> ErrorOr { auto chunk = TRY(decode(data)); data = data.slice(sizeof(HeaderType) + chunk.size()); // add padding if needed if (chunk.size() % 2 != 0) { if (data.is_empty()) return Error::from_string_literal("Missing data for padding byte"); if (*data.data() != 0) return Error::from_string_literal("Padding byte is not 0"); data = data.slice(1); } return chunk; } template OwnedChunk::OwnedChunk(HeaderType header, Buffer backing_data) : Chunk(header, backing_data.span()) , m_backing_data(move(backing_data)) { } template auto OwnedChunk::read_from_stream(Stream& stream) -> ErrorOr { auto header = TRY(stream.read_value()); auto data = TRY(Buffer::create_uninitialized(header.size)); TRY(stream.read_until_filled(data.span())); // RIFF chunks may have trailing padding to align to x86 "words" (i.e. 2 bytes). if (is(stream)) { if (!stream.is_eof()) { auto stream_position = TRY(static_cast(stream).tell()); if (stream_position % 2 != 0) TRY(static_cast(stream).seek(1, SeekMode::FromCurrentPosition)); } } else { dbgln("RIFF Warning: Cannot align stream to 2-byte boundary, next chunk may be bogus!"); } return OwnedChunk { header, data }; } template class Chunk; template class Chunk; template class OwnedChunk; template class OwnedChunk; template struct ChunkHeader; template struct ChunkHeader; template struct FileHeader; template struct FileHeader; } }