1*103e46e4SHarish Mahendrakar // Copyright (c) 2022 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS. All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar #include <cstddef>
9*103e46e4SHarish Mahendrakar #include <cstdint>
10*103e46e4SHarish Mahendrakar #include <cstdlib>
11*103e46e4SHarish Mahendrakar #include <cstring>
12*103e46e4SHarish Mahendrakar #include <functional>
13*103e46e4SHarish Mahendrakar #include <memory>
14*103e46e4SHarish Mahendrakar #include <new>
15*103e46e4SHarish Mahendrakar
16*103e46e4SHarish Mahendrakar #include "mkvparser/mkvparser.h"
17*103e46e4SHarish Mahendrakar #include "mkvparser/mkvreader.h"
18*103e46e4SHarish Mahendrakar
19*103e46e4SHarish Mahendrakar namespace {
20*103e46e4SHarish Mahendrakar
21*103e46e4SHarish Mahendrakar class MemoryReader : public mkvparser::IMkvReader {
22*103e46e4SHarish Mahendrakar public:
MemoryReader(const uint8_t * data,size_t size)23*103e46e4SHarish Mahendrakar MemoryReader(const uint8_t* data, size_t size) : data_(data), size_(size) {}
24*103e46e4SHarish Mahendrakar
Read(long long pos,long len,unsigned char * buf)25*103e46e4SHarish Mahendrakar int Read(long long pos, long len, unsigned char* buf) override {
26*103e46e4SHarish Mahendrakar if (pos < 0 || len < 0) {
27*103e46e4SHarish Mahendrakar abort();
28*103e46e4SHarish Mahendrakar }
29*103e46e4SHarish Mahendrakar if (pos >= size_ || size_ - pos < len) {
30*103e46e4SHarish Mahendrakar return -1;
31*103e46e4SHarish Mahendrakar }
32*103e46e4SHarish Mahendrakar memcpy(buf, data_ + pos, len);
33*103e46e4SHarish Mahendrakar return 0;
34*103e46e4SHarish Mahendrakar }
35*103e46e4SHarish Mahendrakar
Length(long long * total,long long * available)36*103e46e4SHarish Mahendrakar int Length(long long* total, long long* available) override {
37*103e46e4SHarish Mahendrakar if (total != nullptr) {
38*103e46e4SHarish Mahendrakar *total = size_;
39*103e46e4SHarish Mahendrakar }
40*103e46e4SHarish Mahendrakar if (available != nullptr) {
41*103e46e4SHarish Mahendrakar *available = size_;
42*103e46e4SHarish Mahendrakar }
43*103e46e4SHarish Mahendrakar return 0;
44*103e46e4SHarish Mahendrakar }
45*103e46e4SHarish Mahendrakar
46*103e46e4SHarish Mahendrakar private:
47*103e46e4SHarish Mahendrakar const uint8_t* data_;
48*103e46e4SHarish Mahendrakar size_t size_;
49*103e46e4SHarish Mahendrakar };
50*103e46e4SHarish Mahendrakar
ParseCues(const mkvparser::Segment & segment)51*103e46e4SHarish Mahendrakar void ParseCues(const mkvparser::Segment& segment) {
52*103e46e4SHarish Mahendrakar const mkvparser::Cues* const cues = segment.GetCues();
53*103e46e4SHarish Mahendrakar if (cues == nullptr) {
54*103e46e4SHarish Mahendrakar return;
55*103e46e4SHarish Mahendrakar }
56*103e46e4SHarish Mahendrakar
57*103e46e4SHarish Mahendrakar while (!cues->DoneParsing()) {
58*103e46e4SHarish Mahendrakar cues->LoadCuePoint();
59*103e46e4SHarish Mahendrakar }
60*103e46e4SHarish Mahendrakar }
61*103e46e4SHarish Mahendrakar
GetBlockEntryFromCues(const void * ctx,const mkvparser::CuePoint * cue,const mkvparser::CuePoint::TrackPosition * track_pos)62*103e46e4SHarish Mahendrakar const mkvparser::BlockEntry* GetBlockEntryFromCues(
63*103e46e4SHarish Mahendrakar const void* ctx, const mkvparser::CuePoint* cue,
64*103e46e4SHarish Mahendrakar const mkvparser::CuePoint::TrackPosition* track_pos) {
65*103e46e4SHarish Mahendrakar const auto* const cues = static_cast<const mkvparser::Cues*>(ctx);
66*103e46e4SHarish Mahendrakar return cues->GetBlock(cue, track_pos);
67*103e46e4SHarish Mahendrakar }
68*103e46e4SHarish Mahendrakar
GetBlockEntryFromCluster(const void * ctx,const mkvparser::CuePoint * cue,const mkvparser::CuePoint::TrackPosition * track_pos)69*103e46e4SHarish Mahendrakar const mkvparser::BlockEntry* GetBlockEntryFromCluster(
70*103e46e4SHarish Mahendrakar const void* ctx, const mkvparser::CuePoint* cue,
71*103e46e4SHarish Mahendrakar const mkvparser::CuePoint::TrackPosition* track_pos) {
72*103e46e4SHarish Mahendrakar if (track_pos == nullptr) {
73*103e46e4SHarish Mahendrakar return nullptr;
74*103e46e4SHarish Mahendrakar }
75*103e46e4SHarish Mahendrakar const auto* const cluster = static_cast<const mkvparser::Cluster*>(ctx);
76*103e46e4SHarish Mahendrakar const mkvparser::BlockEntry* block_entry =
77*103e46e4SHarish Mahendrakar cluster->GetEntry(*cue, *track_pos);
78*103e46e4SHarish Mahendrakar return block_entry;
79*103e46e4SHarish Mahendrakar }
80*103e46e4SHarish Mahendrakar
WalkCues(const mkvparser::Segment & segment,std::function<const mkvparser::BlockEntry * (const void *,const mkvparser::CuePoint *,const mkvparser::CuePoint::TrackPosition *)> get_block_entry,const void * ctx)81*103e46e4SHarish Mahendrakar void WalkCues(const mkvparser::Segment& segment,
82*103e46e4SHarish Mahendrakar std::function<const mkvparser::BlockEntry*(
83*103e46e4SHarish Mahendrakar const void*, const mkvparser::CuePoint*,
84*103e46e4SHarish Mahendrakar const mkvparser::CuePoint::TrackPosition*)>
85*103e46e4SHarish Mahendrakar get_block_entry,
86*103e46e4SHarish Mahendrakar const void* ctx) {
87*103e46e4SHarish Mahendrakar const mkvparser::Cues* const cues = segment.GetCues();
88*103e46e4SHarish Mahendrakar const mkvparser::Tracks* tracks = segment.GetTracks();
89*103e46e4SHarish Mahendrakar if (cues == nullptr || tracks == nullptr) {
90*103e46e4SHarish Mahendrakar return;
91*103e46e4SHarish Mahendrakar }
92*103e46e4SHarish Mahendrakar const unsigned long num_tracks = tracks->GetTracksCount();
93*103e46e4SHarish Mahendrakar
94*103e46e4SHarish Mahendrakar for (const mkvparser::CuePoint* cue = cues->GetFirst(); cue != nullptr;
95*103e46e4SHarish Mahendrakar cue = cues->GetNext(cue)) {
96*103e46e4SHarish Mahendrakar for (unsigned long track_num = 0; track_num < num_tracks; ++track_num) {
97*103e46e4SHarish Mahendrakar const mkvparser::Track* const track = tracks->GetTrackByIndex(track_num);
98*103e46e4SHarish Mahendrakar const mkvparser::CuePoint::TrackPosition* const track_pos =
99*103e46e4SHarish Mahendrakar cue->Find(track);
100*103e46e4SHarish Mahendrakar const mkvparser::BlockEntry* block_entry =
101*103e46e4SHarish Mahendrakar get_block_entry(ctx, cue, track_pos);
102*103e46e4SHarish Mahendrakar static_cast<void>(block_entry);
103*103e46e4SHarish Mahendrakar }
104*103e46e4SHarish Mahendrakar }
105*103e46e4SHarish Mahendrakar }
106*103e46e4SHarish Mahendrakar
ParseCluster(const mkvparser::Cluster & cluster)107*103e46e4SHarish Mahendrakar void ParseCluster(const mkvparser::Cluster& cluster) {
108*103e46e4SHarish Mahendrakar const mkvparser::BlockEntry* block_entry;
109*103e46e4SHarish Mahendrakar long status = cluster.GetFirst(block_entry);
110*103e46e4SHarish Mahendrakar if (status != 0) {
111*103e46e4SHarish Mahendrakar return;
112*103e46e4SHarish Mahendrakar }
113*103e46e4SHarish Mahendrakar
114*103e46e4SHarish Mahendrakar while (block_entry != nullptr && !block_entry->EOS()) {
115*103e46e4SHarish Mahendrakar const mkvparser::Block* const block = block_entry->GetBlock();
116*103e46e4SHarish Mahendrakar if (block == nullptr) {
117*103e46e4SHarish Mahendrakar return;
118*103e46e4SHarish Mahendrakar }
119*103e46e4SHarish Mahendrakar
120*103e46e4SHarish Mahendrakar status = cluster.GetNext(block_entry, block_entry);
121*103e46e4SHarish Mahendrakar if (status != 0) {
122*103e46e4SHarish Mahendrakar return;
123*103e46e4SHarish Mahendrakar }
124*103e46e4SHarish Mahendrakar }
125*103e46e4SHarish Mahendrakar }
126*103e46e4SHarish Mahendrakar
127*103e46e4SHarish Mahendrakar } // namespace
128*103e46e4SHarish Mahendrakar
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)129*103e46e4SHarish Mahendrakar extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
130*103e46e4SHarish Mahendrakar MemoryReader reader(data, size);
131*103e46e4SHarish Mahendrakar
132*103e46e4SHarish Mahendrakar long long int pos = 0;
133*103e46e4SHarish Mahendrakar std::unique_ptr<mkvparser::EBMLHeader> ebml_header(
134*103e46e4SHarish Mahendrakar new (std::nothrow) mkvparser::EBMLHeader()); // NOLINT
135*103e46e4SHarish Mahendrakar if (ebml_header->Parse(&reader, pos) < 0) {
136*103e46e4SHarish Mahendrakar return 0;
137*103e46e4SHarish Mahendrakar }
138*103e46e4SHarish Mahendrakar
139*103e46e4SHarish Mahendrakar mkvparser::Segment* temp_segment;
140*103e46e4SHarish Mahendrakar if (mkvparser::Segment::CreateInstance(&reader, pos, temp_segment) != 0) {
141*103e46e4SHarish Mahendrakar return 0;
142*103e46e4SHarish Mahendrakar }
143*103e46e4SHarish Mahendrakar std::unique_ptr<mkvparser::Segment> segment(temp_segment);
144*103e46e4SHarish Mahendrakar
145*103e46e4SHarish Mahendrakar if (segment->Load() < 0) {
146*103e46e4SHarish Mahendrakar return 0;
147*103e46e4SHarish Mahendrakar }
148*103e46e4SHarish Mahendrakar
149*103e46e4SHarish Mahendrakar ParseCues(*segment);
150*103e46e4SHarish Mahendrakar WalkCues(*segment, GetBlockEntryFromCues, segment->GetCues());
151*103e46e4SHarish Mahendrakar
152*103e46e4SHarish Mahendrakar const mkvparser::Cluster* cluster = segment->GetFirst();
153*103e46e4SHarish Mahendrakar while (cluster != nullptr && !cluster->EOS()) {
154*103e46e4SHarish Mahendrakar ParseCluster(*cluster);
155*103e46e4SHarish Mahendrakar WalkCues(*segment, GetBlockEntryFromCluster, cluster);
156*103e46e4SHarish Mahendrakar cluster = segment->GetNext(cluster);
157*103e46e4SHarish Mahendrakar }
158*103e46e4SHarish Mahendrakar
159*103e46e4SHarish Mahendrakar return 0;
160*103e46e4SHarish Mahendrakar }
161