1 // Copyright (c) 2016 The WebM project authors. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 #include "src/block_parser.h"
9
10 #include <cassert>
11 #include <cstdint>
12 #include <numeric>
13 #include <type_traits>
14 #include <vector>
15
16 #include "src/parser_utils.h"
17 #include "webm/element.h"
18
19 namespace webm {
20
21 namespace {
22
23 // The ParseBasicBlockFlags functions parse extra flag bits into the block,
24 // depending on the type of block that is being parsed.
ParseBasicBlockFlags(std::uint8_t,Block *)25 void ParseBasicBlockFlags(std::uint8_t /* flags */, Block* /* block */) {
26 // Block has no extra flags that aren't already handled.
27 }
28
ParseBasicBlockFlags(std::uint8_t flags,SimpleBlock * block)29 void ParseBasicBlockFlags(std::uint8_t flags, SimpleBlock* block) {
30 block->is_key_frame = (0x80 & flags) != 0;
31 block->is_discardable = (0x01 & flags) != 0;
32 }
33
34 // The BasicBlockBegin functions call the Callback event handler and get the
35 // correct action for the parser, depending on the type of block that is being
36 // parsed.
BasicBlockBegin(const ElementMetadata & metadata,const Block & block,Callback * callback,Action * action)37 Status BasicBlockBegin(const ElementMetadata& metadata, const Block& block,
38 Callback* callback, Action* action) {
39 return callback->OnBlockBegin(metadata, block, action);
40 }
41
BasicBlockBegin(const ElementMetadata & metadata,const SimpleBlock & block,Callback * callback,Action * action)42 Status BasicBlockBegin(const ElementMetadata& metadata,
43 const SimpleBlock& block, Callback* callback,
44 Action* action) {
45 return callback->OnSimpleBlockBegin(metadata, block, action);
46 }
47
48 // The BasicBlockEnd functions call the Callback event handler depending on the
49 // type of block that is being parsed.
BasicBlockEnd(const ElementMetadata & metadata,const Block & block,Callback * callback)50 Status BasicBlockEnd(const ElementMetadata& metadata, const Block& block,
51 Callback* callback) {
52 return callback->OnBlockEnd(metadata, block);
53 }
54
BasicBlockEnd(const ElementMetadata & metadata,const SimpleBlock & block,Callback * callback)55 Status BasicBlockEnd(const ElementMetadata& metadata, const SimpleBlock& block,
56 Callback* callback) {
57 return callback->OnSimpleBlockEnd(metadata, block);
58 }
59
60 } // namespace
61
62 template <typename T>
Init(const ElementMetadata & metadata,std::uint64_t max_size)63 Status BasicBlockParser<T>::Init(const ElementMetadata& metadata,
64 std::uint64_t max_size) {
65 assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
66
67 if (metadata.size == kUnknownElementSize || metadata.size < 5) {
68 return Status(Status::kInvalidElementSize);
69 }
70
71 *this = {};
72 frame_metadata_.parent_element = metadata;
73
74 return Status(Status::kOkCompleted);
75 }
76
77 template <typename T>
Feed(Callback * callback,Reader * reader,std::uint64_t * num_bytes_read)78 Status BasicBlockParser<T>::Feed(Callback* callback, Reader* reader,
79 std::uint64_t* num_bytes_read) {
80 assert(callback != nullptr);
81 assert(reader != nullptr);
82 assert(num_bytes_read != nullptr);
83
84 *num_bytes_read = 0;
85
86 Status status;
87 std::uint64_t local_num_bytes_read;
88
89 while (true) {
90 switch (state_) {
91 case State::kReadingHeader: {
92 status = header_parser_.Feed(callback, reader, &local_num_bytes_read);
93 *num_bytes_read += local_num_bytes_read;
94 header_bytes_read_ += local_num_bytes_read;
95 if (!status.completed_ok()) {
96 return status;
97 }
98 value_.track_number = header_parser_.value().track_number;
99 value_.timecode = header_parser_.value().timecode;
100
101 std::uint8_t flags = header_parser_.value().flags;
102 value_.is_visible = (0x08 & flags) == 0;
103 value_.lacing = static_cast<Lacing>(flags & 0x06);
104 ParseBasicBlockFlags(flags, &value_);
105
106 if (value_.lacing == Lacing::kNone) {
107 value_.num_frames = 1;
108 state_ = State::kGettingAction;
109 } else {
110 state_ = State::kReadingLaceCount;
111 }
112 continue;
113 }
114
115 case State::kReadingLaceCount: {
116 assert(lace_sizes_.empty());
117 std::uint8_t lace_count;
118 status = ReadByte(reader, &lace_count);
119 if (!status.completed_ok()) {
120 return status;
121 }
122 ++*num_bytes_read;
123 ++header_bytes_read_;
124 // Lace count is stored as (count - 1).
125 value_.num_frames = lace_count + 1;
126 state_ = State::kGettingAction;
127 continue;
128 }
129
130 case State::kGettingAction: {
131 Action action = Action::kRead;
132 status = BasicBlockBegin(frame_metadata_.parent_element, value_,
133 callback, &action);
134 if (!status.completed_ok()) {
135 return status;
136 }
137 if (action == Action::kSkip) {
138 state_ = State::kSkipping;
139 } else if (value_.lacing == Lacing::kNone || value_.num_frames == 1) {
140 state_ = State::kValidatingSize;
141 } else if (value_.lacing == Lacing::kXiph) {
142 state_ = State::kReadingXiphLaceSizes;
143 } else if (value_.lacing == Lacing::kEbml) {
144 state_ = State::kReadingFirstEbmlLaceSize;
145 } else {
146 state_ = State::kCalculatingFixedLaceSizes;
147 }
148 continue;
149 }
150
151 case State::kReadingXiphLaceSizes:
152 assert(value_.num_frames > 0);
153 while (static_cast<int>(lace_sizes_.size()) < value_.num_frames - 1) {
154 std::uint8_t byte;
155 do {
156 status = ReadByte(reader, &byte);
157 if (!status.completed_ok()) {
158 return status;
159 }
160 ++*num_bytes_read;
161 ++header_bytes_read_;
162 xiph_lace_size_ += byte;
163 } while (byte == 255);
164
165 lace_sizes_.push_back(xiph_lace_size_);
166 xiph_lace_size_ = 0;
167 }
168 state_ = State::kValidatingSize;
169 continue;
170
171 case State::kReadingFirstEbmlLaceSize:
172 assert(value_.num_frames > 0);
173 assert(lace_sizes_.empty());
174 status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
175 *num_bytes_read += local_num_bytes_read;
176 header_bytes_read_ += local_num_bytes_read;
177 if (!status.completed_ok()) {
178 return status;
179 }
180 lace_sizes_.push_back(uint_parser_.value());
181 uint_parser_ = {};
182 state_ = State::kReadingEbmlLaceSizes;
183 continue;
184
185 case State::kReadingEbmlLaceSizes:
186 assert(value_.num_frames > 0);
187 assert(!lace_sizes_.empty());
188 while (static_cast<int>(lace_sizes_.size()) < value_.num_frames - 1) {
189 status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
190 *num_bytes_read += local_num_bytes_read;
191 header_bytes_read_ += local_num_bytes_read;
192 if (!status.completed_ok()) {
193 return status;
194 }
195 constexpr std::uint64_t one = 1; // Prettier than a static_cast.
196 std::uint64_t offset =
197 (one << (uint_parser_.encoded_length() * 7 - 1)) - 1;
198 lace_sizes_.push_back(lace_sizes_.back() + uint_parser_.value() -
199 offset);
200 uint_parser_ = {};
201 }
202 state_ = State::kValidatingSize;
203 continue;
204
205 case State::kCalculatingFixedLaceSizes: {
206 assert(value_.num_frames > 0);
207 assert(lace_sizes_.empty());
208 if (header_bytes_read_ >= frame_metadata_.parent_element.size) {
209 return Status(Status::kInvalidElementValue);
210 }
211 std::uint64_t laced_data_size =
212 frame_metadata_.parent_element.size - header_bytes_read_;
213 std::uint64_t frame_size = laced_data_size / value_.num_frames;
214 if (laced_data_size % value_.num_frames != 0) {
215 return Status(Status::kInvalidElementValue);
216 }
217 lace_sizes_.resize(value_.num_frames, frame_size);
218 frame_metadata_.position =
219 frame_metadata_.parent_element.position + header_bytes_read_;
220 frame_metadata_.size = frame_size;
221 state_ = State::kReadingFrames;
222 continue;
223 }
224
225 case State::kValidatingSize: {
226 std::uint64_t sum = std::accumulate(
227 lace_sizes_.begin(), lace_sizes_.end(), header_bytes_read_);
228 if (sum >= frame_metadata_.parent_element.size) {
229 return Status(Status::kInvalidElementValue);
230 }
231 lace_sizes_.push_back(frame_metadata_.parent_element.size - sum);
232 frame_metadata_.position = frame_metadata_.parent_element.position +
233 frame_metadata_.parent_element.header_size +
234 header_bytes_read_;
235 frame_metadata_.size = lace_sizes_[0];
236 state_ = State::kReadingFrames;
237 continue;
238 }
239
240 case State::kSkipping:
241 do {
242 // Skip the remaining part of the header and all of the frames.
243 status = reader->Skip(
244 frame_metadata_.parent_element.size - header_bytes_read_,
245 &local_num_bytes_read);
246 *num_bytes_read += local_num_bytes_read;
247 header_bytes_read_ += local_num_bytes_read;
248 } while (status.code == Status::kOkPartial);
249 return status;
250
251 case State::kReadingFrames:
252 assert(value_.num_frames > 0);
253 assert(static_cast<int>(lace_sizes_.size()) == value_.num_frames);
254 for (; current_lace_ < lace_sizes_.size(); ++current_lace_) {
255 const std::uint64_t original = lace_sizes_[current_lace_];
256 status = callback->OnFrame(frame_metadata_, reader,
257 &lace_sizes_[current_lace_]);
258 *num_bytes_read += original - lace_sizes_[current_lace_];
259 if (!status.completed_ok()) {
260 return status;
261 }
262 assert(lace_sizes_[current_lace_] == 0);
263 if (current_lace_ + 1 < lace_sizes_.size()) {
264 frame_metadata_.position += frame_metadata_.size;
265 frame_metadata_.size = lace_sizes_[current_lace_ + 1];
266 }
267 }
268 state_ = State::kDone;
269 continue;
270
271 case State::kDone:
272 return BasicBlockEnd(frame_metadata_.parent_element, value_, callback);
273 }
274 }
275 }
276
277 template <typename T>
WasSkipped() const278 bool BasicBlockParser<T>::WasSkipped() const {
279 return state_ == State::kSkipping;
280 }
281
282 template class BasicBlockParser<Block>;
283 template class BasicBlockParser<SimpleBlock>;
284
285 } // namespace webm
286