• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "webm/webm_parser.h"
9 
10 #include "gmock/gmock.h"
11 #include "gtest/gtest.h"
12 
13 #include "test_utils/mock_callback.h"
14 #include "webm/buffer_reader.h"
15 #include "webm/status.h"
16 
17 using testing::_;
18 using testing::DoDefault;
19 using testing::InSequence;
20 using testing::NotNull;
21 using testing::Return;
22 
23 using webm::BufferReader;
24 using webm::Ebml;
25 using webm::ElementMetadata;
26 using webm::Id;
27 using webm::Info;
28 using webm::kUnknownElementPosition;
29 using webm::kUnknownElementSize;
30 using webm::kUnknownHeaderSize;
31 using webm::MockCallback;
32 using webm::Status;
33 using webm::WebmParser;
34 
35 namespace {
36 
37 class WebmParserTest : public testing::Test {};
38 
TEST_F(WebmParserTest,InvalidId)39 TEST_F(WebmParserTest, InvalidId) {
40   BufferReader reader = {
41       0x00,  // IDs cannot start with 0x00.
42   };
43 
44   MockCallback callback;
45   {
46     InSequence dummy;
47 
48     EXPECT_CALL(callback, OnEbml(_, _)).Times(0);
49 
50     EXPECT_CALL(callback, OnSegmentBegin(_, NotNull())).Times(0);
51     EXPECT_CALL(callback, OnSegmentEnd(_)).Times(0);
52   }
53 
54   WebmParser parser;
55   Status status = parser.Feed(&callback, &reader);
56   EXPECT_EQ(Status::kInvalidElementId, status.code);
57 }
58 
TEST_F(WebmParserTest,InvalidSize)59 TEST_F(WebmParserTest, InvalidSize) {
60   BufferReader reader = {
61       0x1A, 0x45, 0xDF, 0xA3,  // ID = 0x1A45DFA3 (EBML).
62       0x00,  // Size must have 1+ bits set in the first byte.
63   };
64 
65   MockCallback callback;
66   {
67     InSequence dummy;
68 
69     EXPECT_CALL(callback, OnEbml(_, _)).Times(0);
70 
71     EXPECT_CALL(callback, OnSegmentBegin(_, NotNull())).Times(0);
72     EXPECT_CALL(callback, OnSegmentEnd(_)).Times(0);
73   }
74 
75   WebmParser parser;
76   Status status = parser.Feed(&callback, &reader);
77   EXPECT_EQ(Status::kInvalidElementSize, status.code);
78 }
79 
TEST_F(WebmParserTest,DefaultParse)80 TEST_F(WebmParserTest, DefaultParse) {
81   BufferReader reader = {
82       0x1A, 0x45, 0xDF, 0xA3,  // ID = 0x1A45DFA3 (EBML).
83       0x80,  // Size = 0.
84 
85       0x18, 0x53, 0x80, 0x67,  // ID = 0x18538067 (Segment).
86       0x80,  // Size = 0.
87   };
88 
89   MockCallback callback;
90   {
91     InSequence dummy;
92 
93     ElementMetadata metadata = {Id::kEbml, 5, 0, 0};
94     const Ebml ebml{};
95     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
96     EXPECT_CALL(callback, OnEbml(metadata, ebml)).Times(1);
97 
98     metadata = {Id::kSegment, 5, 0, 5};
99     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
100     EXPECT_CALL(callback, OnSegmentBegin(metadata, NotNull())).Times(1);
101     EXPECT_CALL(callback, OnSegmentEnd(metadata)).Times(1);
102   }
103 
104   WebmParser parser;
105   Status status = parser.Feed(&callback, &reader);
106   EXPECT_EQ(Status::kOkCompleted, status.code);
107 }
108 
TEST_F(WebmParserTest,DefaultActionIsRead)109 TEST_F(WebmParserTest, DefaultActionIsRead) {
110   BufferReader reader = {
111       0x1A, 0x45, 0xDF, 0xA3,  // ID = 0x1A45DFA3 (EBML).
112       0x80,  // Size = 0.
113   };
114 
115   MockCallback callback;
116   {
117     InSequence dummy;
118 
119     const ElementMetadata metadata = {Id::kEbml, 5, 0, 0};
120     const Ebml ebml{};
121 
122     // This intentionally does not set the action and relies on the parser using
123     // a default action value of kRead.
124     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull()))
125         .WillOnce(Return(Status(Status::kOkCompleted)));
126     EXPECT_CALL(callback, OnEbml(metadata, ebml)).Times(1);
127   }
128 
129   WebmParser parser;
130   Status status = parser.Feed(&callback, &reader);
131   EXPECT_EQ(Status::kOkCompleted, status.code);
132 }
133 
TEST_F(WebmParserTest,UnknownElement)134 TEST_F(WebmParserTest, UnknownElement) {
135   BufferReader reader = {
136       0x80,  // ID = 0x80.
137       0x80,  // Size = 0.
138   };
139 
140   MockCallback callback;
141   {
142     InSequence dummy;
143 
144     ElementMetadata metadata = {static_cast<Id>(0x80), 2, 0, 0};
145     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
146     EXPECT_CALL(callback, OnUnknownElement(metadata, NotNull(), NotNull()))
147         .Times(1);
148   }
149 
150   WebmParser parser;
151   Status status = parser.Feed(&callback, &reader);
152   EXPECT_EQ(Status::kOkCompleted, status.code);
153 }
154 
TEST_F(WebmParserTest,SeekEbml)155 TEST_F(WebmParserTest, SeekEbml) {
156   BufferReader reader = {
157       0x1A, 0x45, 0xDF, 0xA3,  // ID = 0x1A45DFA3 (EBML).
158       0x87,  // Size = 7.
159 
160       0x42, 0x86,  //   ID = 0x4286 (EBMLVersion).
161       0x10, 0x00, 0x00, 0x01,  //   Size = 1.
162       0x02,  //   Body (value = 2).
163   };
164   std::uint64_t num_to_skip = 5;  // Skip the starting EBML element metadata.
165   std::uint64_t num_actually_skipped = 0;
166   reader.Skip(num_to_skip, &num_actually_skipped);
167   EXPECT_EQ(num_to_skip, num_actually_skipped);
168 
169   MockCallback callback;
170   {
171     InSequence dummy;
172 
173     ElementMetadata metadata = {Id::kEbmlVersion, 6, 1, num_to_skip};
174     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
175 
176     metadata = {Id::kEbml, kUnknownHeaderSize, kUnknownElementSize,
177                 kUnknownElementPosition};
178     Ebml ebml{};
179     ebml.ebml_version.Set(2, true);
180     EXPECT_CALL(callback, OnEbml(metadata, ebml)).Times(1);
181   }
182 
183   WebmParser parser;
184   parser.DidSeek();
185   Status status = parser.Feed(&callback, &reader);
186   EXPECT_EQ(Status::kOkCompleted, status.code);
187   EXPECT_EQ(reader.size(), reader.Position());
188 }
189 
TEST_F(WebmParserTest,SeekSegment)190 TEST_F(WebmParserTest, SeekSegment) {
191   BufferReader reader = {
192       0x18, 0x53, 0x80, 0x67,  // ID = 0x18538067 (Segment).
193       0x85,  // Size = 5.
194 
195       0x15, 0x49, 0xA9, 0x66,  //   ID = 0x1549A966 (Info).
196       0x80,  //   Size = 0.
197   };
198   std::uint64_t num_to_skip = 5;  // Skip the starting Segment element metadata.
199   std::uint64_t num_actually_skipped = 0;
200   reader.Skip(num_to_skip, &num_actually_skipped);
201   EXPECT_EQ(num_to_skip, num_actually_skipped);
202 
203   MockCallback callback;
204   {
205     InSequence dummy;
206 
207     ElementMetadata metadata = {Id::kInfo, 5, 0, num_to_skip};
208     const Info info{};
209     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
210     EXPECT_CALL(callback, OnInfo(metadata, info)).Times(1);
211 
212     metadata = {Id::kSegment, kUnknownHeaderSize, kUnknownElementSize,
213                 kUnknownElementPosition};
214     EXPECT_CALL(callback, OnSegmentEnd(metadata)).Times(1);
215   }
216 
217   WebmParser parser;
218   parser.DidSeek();
219   Status status = parser.Feed(&callback, &reader);
220   EXPECT_EQ(Status::kOkCompleted, status.code);
221   EXPECT_EQ(reader.size(), reader.Position());
222 }
223 
TEST_F(WebmParserTest,SeekVoid)224 TEST_F(WebmParserTest, SeekVoid) {
225   BufferReader reader = {
226       0xEC,  // ID = 0xEC (Void).
227       0x81,  // Size = 0.
228 
229       0xEC,  // ID = 0xEC (Void).
230       0x81,  // Size = 1.
231       0x00,  // Body.
232 
233       0x1A, 0x45, 0xDF, 0xA3,  // ID = 0x1A45DFA3 (EBML).
234       0x80,  // Size = 0.
235   };
236   std::uint64_t num_to_skip = 2;  // Skip the first Void element.
237   std::uint64_t num_actually_skipped = 0;
238   reader.Skip(num_to_skip, &num_actually_skipped);
239   EXPECT_EQ(num_to_skip, num_actually_skipped);
240 
241   MockCallback callback;
242   {
243     InSequence dummy;
244 
245     ElementMetadata metadata = {Id::kVoid, 2, 1, num_to_skip};
246     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
247     EXPECT_CALL(callback, OnVoid(metadata, &reader, NotNull())).Times(1);
248 
249     metadata = {Id::kEbml, 5, 0, 5};
250     const Ebml ebml{};
251     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
252     EXPECT_CALL(callback, OnEbml(metadata, ebml)).Times(1);
253   }
254 
255   WebmParser parser;
256   parser.DidSeek();
257   Status status = parser.Feed(&callback, &reader);
258   EXPECT_EQ(Status::kOkCompleted, status.code);
259   EXPECT_EQ(reader.size(), reader.Position());
260 }
261 
TEST_F(WebmParserTest,SwapAfterFailedParse)262 TEST_F(WebmParserTest, SwapAfterFailedParse) {
263   BufferReader reader = {
264       0x00,  // Invalid ID.
265 
266       0xEC,  // ID = 0xEC (Void).
267       0x81,  // Size = 1.
268       0x00,  // Body.
269   };
270 
271   MockCallback expect_nothing;
272   EXPECT_CALL(expect_nothing, OnElementBegin(_, _)).Times(0);
273 
274   MockCallback expect_void;
275   {
276     InSequence dummy;
277 
278     ElementMetadata metadata = {Id::kVoid, 2, 1, 1};
279     EXPECT_CALL(expect_void, OnElementBegin(metadata, NotNull())).Times(1);
280     EXPECT_CALL(expect_void, OnVoid(metadata, &reader, NotNull())).Times(1);
281   }
282 
283   WebmParser parser1;
284   Status status = parser1.Feed(&expect_nothing, &reader);
285   EXPECT_EQ(Status::kInvalidElementId, status.code);
286   EXPECT_EQ(static_cast<std::uint64_t>(1), reader.Position());
287 
288   // After swapping, the parser should retain its failed state and not consume
289   // more data.
290   WebmParser parser2;
291   parser2.Swap(&parser1);
292   status = parser2.Feed(&expect_nothing, &reader);
293   EXPECT_EQ(Status::kInvalidElementId, status.code);
294   EXPECT_EQ(static_cast<std::uint64_t>(1), reader.Position());
295 
296   // parser1 should be a fresh/new parser after the swap, so parsing should
297   // succeed.
298   status = parser1.Feed(&expect_void, &reader);
299   EXPECT_EQ(Status::kOkCompleted, status.code);
300   EXPECT_EQ(reader.size(), reader.Position());
301 }
302 
TEST_F(WebmParserTest,Swap)303 TEST_F(WebmParserTest, Swap) {
304   BufferReader reader = {
305       0xEC,  // ID = 0xEC (Void).
306       0x81,  // Size = 1.
307       0x00,  // Body.
308 
309       0x1A, 0x45, 0xDF, 0xA3,  // ID = 0x1A45DFA3 (EBML).
310       0x80,  // Size = 0.
311   };
312 
313   MockCallback callback;
314   {
315     InSequence dummy;
316 
317     ElementMetadata metadata = {Id::kVoid, 2, 1, 0};
318     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
319     EXPECT_CALL(callback, OnVoid(metadata, &reader, NotNull()))
320         .WillOnce(Return(Status(Status::kOkPartial)))
321         .WillOnce(DoDefault());
322 
323     metadata = {Id::kEbml, 5, 0, 3};
324     EXPECT_CALL(callback, OnElementBegin(metadata, NotNull())).Times(1);
325     EXPECT_CALL(callback, OnEbml(metadata, Ebml{})).Times(1);
326   }
327 
328   WebmParser parser1;
329   Status status = parser1.Feed(&callback, &reader);
330   EXPECT_EQ(Status::kOkPartial, status.code);
331 
332   WebmParser parser2;
333   swap(parser1, parser2);
334   status = parser2.Feed(&callback, &reader);
335   EXPECT_EQ(Status::kOkCompleted, status.code);
336   EXPECT_EQ(reader.size(), reader.Position());
337 }
338 
339 }  // namespace
340