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/master_parser.h"
9
10 #include <cstdint>
11 #include <memory>
12 #include <vector>
13
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16
17 #include "src/byte_parser.h"
18 #include "test_utils/element_parser_test.h"
19 #include "webm/element.h"
20 #include "webm/id.h"
21 #include "webm/status.h"
22
23 using testing::_;
24 using testing::DoAll;
25 using testing::InSequence;
26 using testing::NotNull;
27 using testing::Return;
28 using testing::SetArgPointee;
29
30 using webm::Action;
31 using webm::BinaryParser;
32 using webm::ElementMetadata;
33 using webm::ElementParser;
34 using webm::ElementParserTest;
35 using webm::Id;
36 using webm::kUnknownElementSize;
37 using webm::LimitedReader;
38 using webm::MasterParser;
39 using webm::Status;
40
41 namespace {
42
43 // Simple helper method that just takes an Id and ElementParser* and returns
44 // them in a std::pair<Id, std::unique_ptr<ElementParser>>. Provided just for
45 // simplifying some statements.
ParserForId(Id id,ElementParser * parser)46 std::pair<Id, std::unique_ptr<ElementParser>> ParserForId(
47 Id id, ElementParser* parser) {
48 return {id, std::unique_ptr<ElementParser>(parser)};
49 }
50
51 class MasterParserTest : public ElementParserTest<MasterParser> {};
52
53 // Errors parsing an ID should be returned to the caller.
TEST_F(MasterParserTest,BadId)54 TEST_F(MasterParserTest, BadId) {
55 SetReaderData({
56 0x00, // Invalid ID.
57 0x80, // ID = 0x80 (unknown).
58 0x80, // Size = 0.
59 });
60
61 EXPECT_CALL(callback_, OnElementBegin(_, _)).Times(0);
62
63 ParseAndExpectResult(Status::kInvalidElementId);
64 }
65
66 // Errors from a child parser's Init should be returned to the caller.
TEST_F(MasterParserTest,ChildInitFails)67 TEST_F(MasterParserTest, ChildInitFails) {
68 SetReaderData({
69 0xEC, // ID = 0xEC (Void).
70 0xFF, // Size = unknown.
71 });
72
73 const ElementMetadata metadata = {Id::kVoid, 2, kUnknownElementSize, 0};
74 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
75
76 ParseAndExpectResult(Status::kInvalidElementSize);
77 }
78
79 // Indefinite unknown children should result in an error.
TEST_F(MasterParserTest,IndefiniteUnknownChild)80 TEST_F(MasterParserTest, IndefiniteUnknownChild) {
81 SetReaderData({
82 0x80, // ID = 0x80 (unknown).
83 0xFF, // Size = unknown.
84 0x00, 0x00, // Body.
85 });
86
87 EXPECT_CALL(callback_, OnElementBegin(_, _)).Times(0);
88
89 ParseAndExpectResult(Status::kIndefiniteUnknownElement);
90 }
91
92 // Child elements that overflow the master element's size should be detected.
TEST_F(MasterParserTest,ChildOverflow)93 TEST_F(MasterParserTest, ChildOverflow) {
94 SetReaderData({
95 0xEC, // ID = 0xEC (Void).
96 0x82, // Size = 2.
97 0x00, 0x00, // Body.
98 });
99
100 EXPECT_CALL(callback_, OnElementBegin(_, _)).Times(0);
101 EXPECT_CALL(callback_, OnVoid(_, _, _)).Times(0);
102
103 ParseAndExpectResult(Status::kElementOverflow, reader_.size() - 1);
104 }
105
106 // Child elements with an unknown size can't be naively checked to see if they
107 // overflow the master element's size. Make sure the overflow is still detected.
TEST_F(MasterParserTest,ChildOverflowWithUnknownSize)108 TEST_F(MasterParserTest, ChildOverflowWithUnknownSize) {
109 SetReaderData({
110 0xA1, // ID = 0xA1 (Block) (master).
111 0xFF, // Size = unknown.
112
113 0xEC, // ID = 0xEC (Void) (child).
114 0x81, // Size = 1.
115 0x12, // Body.
116 });
117
118 {
119 InSequence dummy;
120
121 ElementMetadata metadata = {Id::kBlock, 2, kUnknownElementSize, 0};
122 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
123 }
124
125 ResetParser(ParserForId(Id::kBlock, new MasterParser));
126
127 ParseAndExpectResult(Status::kElementOverflow, 4);
128 }
129
130 // An element with an unknown size should be terminated by its parents bounds.
TEST_F(MasterParserTest,ChildWithUnknownSizeBoundedByParentSize)131 TEST_F(MasterParserTest, ChildWithUnknownSizeBoundedByParentSize) {
132 SetReaderData({
133 0xA1, // ID = 0xA1 (Block) (master).
134 0xFF, // Size = unknown.
135
136 0xEC, // ID = 0xEC (Void) (child).
137 0x81, // Size = 1.
138 0x12, // Body.
139
140 0x00, // Invalid ID. This should not be read.
141 });
142
143 {
144 InSequence dummy;
145
146 ElementMetadata metadata = {Id::kBlock, 2, kUnknownElementSize, 0};
147 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
148
149 metadata = {Id::kVoid, 2, 1, 2};
150 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
151 EXPECT_CALL(callback_, OnVoid(metadata, NotNull(), NotNull())).Times(1);
152 }
153
154 ResetParser(ParserForId(Id::kBlock, new MasterParser));
155
156 ParseAndVerify(reader_.size() - 1);
157 }
158
159 // An empty master element is okay.
TEST_F(MasterParserTest,Empty)160 TEST_F(MasterParserTest, Empty) {
161 EXPECT_CALL(callback_, OnElementBegin(_, _)).Times(0);
162
163 ParseAndVerify();
164 }
165
TEST_F(MasterParserTest,DefaultActionIsRead)166 TEST_F(MasterParserTest, DefaultActionIsRead) {
167 SetReaderData({
168 0xEC, // ID = 0xEC (Void).
169 0x80, // Size = 0.
170 });
171
172 {
173 InSequence dummy;
174
175 const ElementMetadata metadata = {Id::kVoid, 2, 0, 0};
176
177 // This intentionally does not set the action and relies on the parser using
178 // a default action value of kRead.
179 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull()))
180 .WillOnce(Return(Status(Status::kOkCompleted)));
181 EXPECT_CALL(callback_, OnVoid(metadata, NotNull(), NotNull())).Times(1);
182 }
183
184 ParseAndVerify();
185 }
186
187 // Unrecognized children should be skipped over.
TEST_F(MasterParserTest,UnknownChildren)188 TEST_F(MasterParserTest, UnknownChildren) {
189 SetReaderData({
190 0x40, 0x00, // ID = 0x4000 (unknown).
191 0x80, // Size = 0.
192
193 0x80, // ID = 0x80 (unknown).
194 0x40, 0x00, // Size = 0.
195 });
196
197 EXPECT_CALL(callback_, OnVoid(_, _, _)).Times(0);
198 {
199 InSequence dummy;
200
201 ElementMetadata metadata = {static_cast<Id>(0x4000), 3, 0, 0};
202 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
203
204 metadata = {static_cast<Id>(0x80), 3, 0, 3};
205 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
206 }
207
208 ParseAndVerify();
209 }
210
211 // A master element with unknown size is terminated by the first element that is
212 // not a valid child.
TEST_F(MasterParserTest,UnknownSize)213 TEST_F(MasterParserTest, UnknownSize) {
214 SetReaderData({
215 // Void elements may appear anywhere in a master element and should not
216 // terminate the parse for a master element with an unknown size. In other
217 // words, they're always valid children.
218 0xEC, // ID = 0xEC (Void).
219 0x81, // Size = 1.
220 0x00, // Body.
221
222 // This element marks the end for the parser since this is the first
223 // unrecognized element. The ID and size should be read (which the parser
224 // uses to determine the end has been reached), but nothing more.
225 0x80, // ID = 0x80 (unknown).
226 0x81, // Size = 1.
227 0x12, // Body.
228 });
229
230 {
231 InSequence dummy;
232
233 const ElementMetadata metadata = {Id::kVoid, 2, 1, 0};
234 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
235 EXPECT_CALL(callback_, OnVoid(metadata, NotNull(), NotNull())).Times(1);
236 }
237
238 ParseAndVerify(kUnknownElementSize);
239
240 EXPECT_EQ(static_cast<std::uint64_t>(5), reader_.Position());
241 }
242
243 // Consecutive elements with unknown size should parse without issues, despite
244 // the internal parsers having to read ahead into the next (non-child) element.
TEST_F(MasterParserTest,MultipleUnknownChildSize)245 TEST_F(MasterParserTest, MultipleUnknownChildSize) {
246 SetReaderData({
247 0xA1, // ID = 0xA1 (Block) (master).
248 0xFF, // Size = unknown.
249
250 0xEC, // ID = 0xEC (Void) (child).
251 0x81, // Size = 1.
252 0x12, // Body.
253
254 0xA1, // ID = 0xA1 (Block) (master).
255 0xFF, // Size = unknown.
256
257 0xEC, // ID = 0xEC (Void) (child).
258 0x81, // Size = 1.
259 0x13, // Body.
260 });
261
262 {
263 InSequence dummy;
264
265 ElementMetadata metadata = {Id::kBlock, 2, kUnknownElementSize, 0};
266 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
267
268 metadata = {Id::kVoid, 2, 1, 2};
269 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
270 EXPECT_CALL(callback_, OnVoid(metadata, NotNull(), NotNull())).Times(1);
271
272 metadata = {Id::kBlock, 2, kUnknownElementSize, 5};
273 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
274
275 metadata = {Id::kVoid, 2, 1, 7};
276 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
277 EXPECT_CALL(callback_, OnVoid(metadata, NotNull(), NotNull())).Times(1);
278 }
279
280 ResetParser(ParserForId(Id::kBlock, new MasterParser));
281
282 ParseAndVerify();
283 }
284
285 // Reaching the end of the file while reading an element with unknown size
286 // should return Status::kOkCompleted instead of Status::kEndOfFile.
TEST_F(MasterParserTest,UnknownSizeToFileEnd)287 TEST_F(MasterParserTest, UnknownSizeToFileEnd) {
288 SetReaderData({
289 0xEC, // ID = 0xEC (Void).
290 0x81, // Size = 1.
291 0x00, // Body.
292 });
293
294 {
295 InSequence dummy;
296
297 const ElementMetadata metadata = {Id::kVoid, 2, 1, 0};
298 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
299 EXPECT_CALL(callback_, OnVoid(metadata, NotNull(), NotNull())).Times(1);
300 }
301
302 ParseAndVerify();
303 }
304
305 // Parsing one byte at a time is okay.
TEST_F(MasterParserTest,IncrementalParse)306 TEST_F(MasterParserTest, IncrementalParse) {
307 SetReaderData({
308 0x1A, 0x45, 0xDF, 0xA3, // ID = 0x1A45DFA3 (EBML).
309 0x08, 0x00, 0x00, 0x00, 0x06, // Size = 6.
310 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Body.
311 });
312
313 const ElementMetadata metadata = {Id::kEbml, 9, 6, 0};
314 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
315
316 BinaryParser* binary_parser = new BinaryParser;
317 ResetParser(ParserForId(Id::kEbml, binary_parser));
318
319 IncrementalParseAndVerify();
320
321 std::vector<std::uint8_t> expected = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
322 EXPECT_EQ(expected, binary_parser->value());
323 }
324
325 // Alternating actions between skip and read is okay. The parser should remember
326 // the requested action between repeated calls to Feed.
TEST_F(MasterParserTest,IncrementalSkipThenReadThenSkip)327 TEST_F(MasterParserTest, IncrementalSkipThenReadThenSkip) {
328 SetReaderData({
329 0xA1, // ID = 0xA1 (Block) (master).
330 0x83, // Size = 3.
331
332 0xEC, // ID = 0xEC (Void) (child).
333 0x81, // Size = 1.
334 0x12, // Body.
335
336 0xA1, // ID = 0xA1 (Block) (master).
337 0x83, // Size = 3.
338
339 0xEC, // ID = 0xEC (Void) (child).
340 0x81, // Size = 1.
341 0x13, // Body.
342
343 0xA1, // ID = 0xA1 (Block) (master).
344 0xFF, // Size = unknown.
345
346 0xEC, // ID = 0xEC (Void) (child).
347 0x81, // Size = 1.
348 0x14, // Body.
349 });
350
351 {
352 InSequence dummy;
353
354 ElementMetadata metadata = {Id::kBlock, 2, 3, 0};
355 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull()))
356 .WillOnce(Return(Status(Status::kOkPartial)))
357 .WillOnce(DoAll(SetArgPointee<1>(Action::kSkip),
358 Return(Status(Status::kOkCompleted))));
359
360 metadata = {Id::kBlock, 2, 3, 5};
361 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
362
363 metadata = {Id::kVoid, 2, 1, 7};
364 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull())).Times(1);
365
366 // Expect to get called twice because we'll cap the LimitedReader to 1-byte
367 // reads. The first attempt to read will fail because we'll have already
368 // reached the 1-byte max.
369 EXPECT_CALL(callback_, OnVoid(metadata, NotNull(), NotNull())).Times(2);
370
371 metadata = {Id::kBlock, 2, kUnknownElementSize, 10};
372 EXPECT_CALL(callback_, OnElementBegin(metadata, NotNull()))
373 .WillOnce(DoAll(SetArgPointee<1>(Action::kSkip),
374 Return(Status(Status::kOkCompleted))));
375 }
376
377 ResetParser(ParserForId(Id::kBlock, new MasterParser));
378
379 IncrementalParseAndVerify();
380 }
381
382 } // namespace
383