/src/serenity/Userland/Libraries/LibRIFF/Details.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include "Details.h" |
8 | | #include <AK/TypeCasts.h> |
9 | | #include <LibRIFF/IFF.h> |
10 | | #include <LibRIFF/RIFF.h> |
11 | | |
12 | | namespace RIFF { |
13 | | |
14 | | StringView ChunkID::as_ascii_string() const |
15 | 57.6k | { |
16 | 57.6k | return StringView { id_data.span() }; |
17 | 57.6k | } |
18 | | |
19 | | bool ChunkID::operator==(StringView other_string) const |
20 | 57.6k | { |
21 | 57.6k | return as_ascii_string() == other_string; |
22 | 57.6k | } |
23 | | |
24 | | namespace Detail { |
25 | | |
26 | | template<typename WordType> |
27 | | auto ChunkHeader<WordType>::read_from_stream(Stream& stream) -> ErrorOr<ChunkHeader> |
28 | 20.7k | { |
29 | 20.7k | auto id = TRY(stream.read_value<RIFF::ChunkID>()); |
30 | 20.6k | u32 size = TRY(stream.read_value<WordType>()); |
31 | 20.5k | return ChunkHeader { id, size }; |
32 | 20.6k | } RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> >::read_from_stream(AK::Stream&) Line | Count | Source | 28 | 20.7k | { | 29 | 20.7k | auto id = TRY(stream.read_value<RIFF::ChunkID>()); | 30 | 20.6k | u32 size = TRY(stream.read_value<WordType>()); | 31 | 20.5k | return ChunkHeader { id, size }; | 32 | 20.6k | } |
Unexecuted instantiation: RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> >::read_from_stream(AK::Stream&) |
33 | | |
34 | | template<typename HeaderType> |
35 | | auto FileHeader<HeaderType>::read_from_stream(Stream& stream) -> ErrorOr<FileHeader> |
36 | 718 | { |
37 | 718 | auto header = TRY(stream.read_value<HeaderType>()); |
38 | 718 | auto subformat = TRY(stream.read_value<RIFF::ChunkID>()); |
39 | 718 | return FileHeader { header, subformat }; |
40 | 718 | } RIFF::Detail::FileHeader<RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> > >::read_from_stream(AK::Stream&) Line | Count | Source | 36 | 718 | { | 37 | 718 | auto header = TRY(stream.read_value<HeaderType>()); | 38 | 718 | auto subformat = TRY(stream.read_value<RIFF::ChunkID>()); | 39 | 718 | return FileHeader { header, subformat }; | 40 | 718 | } |
Unexecuted instantiation: RIFF::Detail::FileHeader<RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> > >::read_from_stream(AK::Stream&) |
41 | | |
42 | | template<typename HeaderType> |
43 | | Chunk<HeaderType>::Chunk(HeaderType header, ReadonlyBytes data) |
44 | 19.7k | : m_header(header) |
45 | 19.7k | , m_data(data) |
46 | 19.7k | { |
47 | 19.7k | VERIFY(data.size() == header.size); |
48 | 19.7k | } RIFF::Detail::Chunk<RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> > >::Chunk(RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> >, AK::Span<unsigned char const>) Line | Count | Source | 44 | 19.7k | : m_header(header) | 45 | 19.7k | , m_data(data) | 46 | 19.7k | { | 47 | 19.7k | VERIFY(data.size() == header.size); | 48 | 19.7k | } |
Unexecuted instantiation: RIFF::Detail::Chunk<RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> > >::Chunk(RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> >, AK::Span<unsigned char const>) |
49 | | |
50 | | template<typename HeaderType> |
51 | | FixedMemoryStream Chunk<HeaderType>::data_stream() const |
52 | 0 | { |
53 | 0 | return FixedMemoryStream { m_data }; |
54 | 0 | } Unexecuted instantiation: RIFF::Detail::Chunk<RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> > >::data_stream() const Unexecuted instantiation: RIFF::Detail::Chunk<RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> > >::data_stream() const |
55 | | |
56 | | template<typename HeaderType> |
57 | | auto Chunk<HeaderType>::decode(ReadonlyBytes data) -> ErrorOr<Chunk> |
58 | 20.0k | { |
59 | 20.0k | auto data_stream = FixedMemoryStream { data }; |
60 | 20.0k | auto header = TRY(HeaderType::read_from_stream(data_stream)); |
61 | | |
62 | 19.8k | if (data.size() < sizeof(HeaderType) + header.size) |
63 | 123 | return Error::from_string_literal("Not enough data for IFF/RIFF chunk"); |
64 | | |
65 | 19.7k | return Chunk { header, data.slice(sizeof(HeaderType), header.size) }; |
66 | 19.8k | } RIFF::Detail::Chunk<RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> > >::decode(AK::Span<unsigned char const>) Line | Count | Source | 58 | 20.0k | { | 59 | 20.0k | auto data_stream = FixedMemoryStream { data }; | 60 | 20.0k | auto header = TRY(HeaderType::read_from_stream(data_stream)); | 61 | | | 62 | 19.8k | if (data.size() < sizeof(HeaderType) + header.size) | 63 | 123 | return Error::from_string_literal("Not enough data for IFF/RIFF chunk"); | 64 | | | 65 | 19.7k | return Chunk { header, data.slice(sizeof(HeaderType), header.size) }; | 66 | 19.8k | } |
Unexecuted instantiation: RIFF::Detail::Chunk<RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> > >::decode(AK::Span<unsigned char const>) |
67 | | |
68 | | template<typename HeaderType> |
69 | | auto Chunk<HeaderType>::decode_and_advance(ReadonlyBytes& data) -> ErrorOr<Chunk> |
70 | 20.0k | { |
71 | 20.0k | auto chunk = TRY(decode(data)); |
72 | 19.7k | data = data.slice(sizeof(HeaderType) + chunk.size()); |
73 | | // add padding if needed |
74 | 19.7k | if (chunk.size() % 2 != 0) { |
75 | 3.45k | if (data.is_empty()) |
76 | 0 | return Error::from_string_literal("Missing data for padding byte"); |
77 | 3.45k | if (*data.data() != 0) |
78 | 22 | return Error::from_string_literal("Padding byte is not 0"); |
79 | 3.43k | data = data.slice(1); |
80 | 3.43k | } |
81 | | |
82 | 19.7k | return chunk; |
83 | 19.7k | } RIFF::Detail::Chunk<RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> > >::decode_and_advance(AK::Span<unsigned char const>&) Line | Count | Source | 70 | 20.0k | { | 71 | 20.0k | auto chunk = TRY(decode(data)); | 72 | 19.7k | data = data.slice(sizeof(HeaderType) + chunk.size()); | 73 | | // add padding if needed | 74 | 19.7k | if (chunk.size() % 2 != 0) { | 75 | 3.45k | if (data.is_empty()) | 76 | 0 | return Error::from_string_literal("Missing data for padding byte"); | 77 | 3.45k | if (*data.data() != 0) | 78 | 22 | return Error::from_string_literal("Padding byte is not 0"); | 79 | 3.43k | data = data.slice(1); | 80 | 3.43k | } | 81 | | | 82 | 19.7k | return chunk; | 83 | 19.7k | } |
Unexecuted instantiation: RIFF::Detail::Chunk<RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> > >::decode_and_advance(AK::Span<unsigned char const>&) |
84 | | |
85 | | template<typename HeaderType> |
86 | | OwnedChunk<HeaderType>::OwnedChunk(HeaderType header, Buffer backing_data) |
87 | 0 | : Chunk<HeaderType>(header, backing_data.span()) |
88 | 0 | , m_backing_data(move(backing_data)) |
89 | 0 | { |
90 | 0 | } Unexecuted instantiation: RIFF::Detail::OwnedChunk<RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> > >::OwnedChunk(RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> >, AK::Detail::ByteBuffer<0ul>) Unexecuted instantiation: RIFF::Detail::OwnedChunk<RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> > >::OwnedChunk(RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> >, AK::Detail::ByteBuffer<0ul>) |
91 | | |
92 | | template<typename HeaderType> |
93 | | auto OwnedChunk<HeaderType>::read_from_stream(Stream& stream) -> ErrorOr<OwnedChunk> |
94 | 0 | { |
95 | 0 | auto header = TRY(stream.read_value<HeaderType>()); |
96 | |
|
97 | 0 | auto data = TRY(Buffer::create_uninitialized(header.size)); |
98 | 0 | TRY(stream.read_until_filled(data.span())); |
99 | | |
100 | | // RIFF chunks may have trailing padding to align to x86 "words" (i.e. 2 bytes). |
101 | 0 | if (is<SeekableStream>(stream)) { |
102 | 0 | if (!stream.is_eof()) { |
103 | 0 | auto stream_position = TRY(static_cast<SeekableStream&>(stream).tell()); |
104 | 0 | if (stream_position % 2 != 0) |
105 | 0 | TRY(static_cast<SeekableStream&>(stream).seek(1, SeekMode::FromCurrentPosition)); |
106 | 0 | } |
107 | 0 | } else { |
108 | 0 | dbgln("RIFF Warning: Cannot align stream to 2-byte boundary, next chunk may be bogus!"); |
109 | 0 | } |
110 | |
|
111 | 0 | return OwnedChunk { header, data }; |
112 | 0 | } Unexecuted instantiation: RIFF::Detail::OwnedChunk<RIFF::Detail::ChunkHeader<AK::BigEndian<unsigned int> > >::read_from_stream(AK::Stream&) Unexecuted instantiation: RIFF::Detail::OwnedChunk<RIFF::Detail::ChunkHeader<AK::LittleEndian<unsigned int> > >::read_from_stream(AK::Stream&) |
113 | | |
114 | | template class Chunk<IFF::ChunkHeader>; |
115 | | template class Chunk<RIFF::ChunkHeader>; |
116 | | template class OwnedChunk<IFF::ChunkHeader>; |
117 | | template class OwnedChunk<RIFF::ChunkHeader>; |
118 | | template struct ChunkHeader<IFF::WordType>; |
119 | | template struct ChunkHeader<RIFF::WordType>; |
120 | | template struct FileHeader<IFF::ChunkHeader>; |
121 | | template struct FileHeader<RIFF::ChunkHeader>; |
122 | | |
123 | | } |
124 | | |
125 | | } |