Coverage Report

Created: 2026-09-26 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}