1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/formats/webm/cluster_builder.h"
6 #include "media/formats/webm/webm_constants.h"
7 #include "media/formats/webm/webm_parser.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 using ::testing::InSequence;
12 using ::testing::Return;
13 using ::testing::ReturnNull;
14 using ::testing::StrictMock;
15 using ::testing::_;
16
17 namespace media {
18
19 enum { kBlockCount = 5 };
20
21 class MockWebMParserClient : public WebMParserClient {
22 public:
~MockWebMParserClient()23 virtual ~MockWebMParserClient() {}
24
25 // WebMParserClient methods.
26 MOCK_METHOD1(OnListStart, WebMParserClient*(int));
27 MOCK_METHOD1(OnListEnd, bool(int));
28 MOCK_METHOD2(OnUInt, bool(int, int64));
29 MOCK_METHOD2(OnFloat, bool(int, double));
30 MOCK_METHOD3(OnBinary, bool(int, const uint8*, int));
31 MOCK_METHOD2(OnString, bool(int, const std::string&));
32 };
33
34 class WebMParserTest : public testing::Test {
35 protected:
36 StrictMock<MockWebMParserClient> client_;
37 };
38
CreateCluster(int block_count)39 static scoped_ptr<Cluster> CreateCluster(int block_count) {
40 ClusterBuilder cb;
41 cb.SetClusterTimecode(0);
42
43 for (int i = 0; i < block_count; i++) {
44 uint8 data[] = { 0x00 };
45 cb.AddSimpleBlock(0, i, 0, data, sizeof(data));
46 }
47
48 return cb.Finish();
49 }
50
CreateClusterExpectations(int block_count,bool is_complete_cluster,MockWebMParserClient * client)51 static void CreateClusterExpectations(int block_count,
52 bool is_complete_cluster,
53 MockWebMParserClient* client) {
54
55 InSequence s;
56 EXPECT_CALL(*client, OnListStart(kWebMIdCluster)).WillOnce(Return(client));
57 EXPECT_CALL(*client, OnUInt(kWebMIdTimecode, 0))
58 .WillOnce(Return(true));
59
60 for (int i = 0; i < block_count; i++) {
61 EXPECT_CALL(*client, OnBinary(kWebMIdSimpleBlock, _, _))
62 .WillOnce(Return(true));
63 }
64
65 if (is_complete_cluster)
66 EXPECT_CALL(*client, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
67 }
68
TEST_F(WebMParserTest,EmptyCluster)69 TEST_F(WebMParserTest, EmptyCluster) {
70 const uint8 kEmptyCluster[] = {
71 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0)
72 };
73 int size = sizeof(kEmptyCluster);
74
75 InSequence s;
76 EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
77 EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
78
79 WebMListParser parser(kWebMIdCluster, &client_);
80 EXPECT_EQ(size, parser.Parse(kEmptyCluster, size));
81 EXPECT_TRUE(parser.IsParsingComplete());
82 }
83
TEST_F(WebMParserTest,EmptyClusterInSegment)84 TEST_F(WebMParserTest, EmptyClusterInSegment) {
85 const uint8 kBuffer[] = {
86 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 5)
87 0x1F, 0x43, 0xB6, 0x75, 0x80, // CLUSTER (size = 0)
88 };
89 int size = sizeof(kBuffer);
90
91 InSequence s;
92 EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
93 EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
94 EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
95 EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
96
97 WebMListParser parser(kWebMIdSegment, &client_);
98 EXPECT_EQ(size, parser.Parse(kBuffer, size));
99 EXPECT_TRUE(parser.IsParsingComplete());
100 }
101
102 // Test the case where a non-list child element has a size
103 // that is beyond the end of the parent.
TEST_F(WebMParserTest,ChildNonListLargerThanParent)104 TEST_F(WebMParserTest, ChildNonListLargerThanParent) {
105 const uint8 kBuffer[] = {
106 0x1F, 0x43, 0xB6, 0x75, 0x81, // CLUSTER (size = 1)
107 0xE7, 0x81, 0x01, // Timecode (size=1, value=1)
108 };
109
110 InSequence s;
111 EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
112
113 WebMListParser parser(kWebMIdCluster, &client_);
114 EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
115 EXPECT_FALSE(parser.IsParsingComplete());
116 }
117
118 // Test the case where a list child element has a size
119 // that is beyond the end of the parent.
TEST_F(WebMParserTest,ChildListLargerThanParent)120 TEST_F(WebMParserTest, ChildListLargerThanParent) {
121 const uint8 kBuffer[] = {
122 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 5)
123 0x1F, 0x43, 0xB6, 0x75, 0x81, 0x11 // CLUSTER (size = 1)
124 };
125
126 InSequence s;
127 EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
128
129 WebMListParser parser(kWebMIdSegment, &client_);
130 EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
131 EXPECT_FALSE(parser.IsParsingComplete());
132 }
133
134 // Expecting to parse a Cluster, but get a Segment.
TEST_F(WebMParserTest,ListIdDoesNotMatch)135 TEST_F(WebMParserTest, ListIdDoesNotMatch) {
136 const uint8 kBuffer[] = {
137 0x18, 0x53, 0x80, 0x67, 0x80, // SEGMENT (size = 0)
138 };
139
140 WebMListParser parser(kWebMIdCluster, &client_);
141 EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
142 EXPECT_FALSE(parser.IsParsingComplete());
143 }
144
TEST_F(WebMParserTest,InvalidElementInList)145 TEST_F(WebMParserTest, InvalidElementInList) {
146 const uint8 kBuffer[] = {
147 0x18, 0x53, 0x80, 0x67, 0x82, // SEGMENT (size = 2)
148 0xAE, 0x80, // TrackEntry (size = 0)
149 };
150
151 InSequence s;
152 EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
153
154 WebMListParser parser(kWebMIdSegment, &client_);
155 EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
156 EXPECT_FALSE(parser.IsParsingComplete());
157 }
158
159 // Test specific case of InvalidElementInList to verify EBMLHEADER within
160 // known-sized cluster causes parse error.
TEST_F(WebMParserTest,InvalidEBMLHeaderInCluster)161 TEST_F(WebMParserTest, InvalidEBMLHeaderInCluster) {
162 const uint8 kBuffer[] = {
163 0x1F, 0x43, 0xB6, 0x75, 0x85, // CLUSTER (size = 5)
164 0x1A, 0x45, 0xDF, 0xA3, 0x80, // EBMLHEADER (size = 0)
165 };
166
167 InSequence s;
168 EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
169
170 WebMListParser parser(kWebMIdCluster, &client_);
171 EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
172 EXPECT_FALSE(parser.IsParsingComplete());
173 }
174
175 // Verify that EBMLHEADER ends a preceding "unknown"-sized CLUSTER.
TEST_F(WebMParserTest,UnknownSizeClusterFollowedByEBMLHeader)176 TEST_F(WebMParserTest, UnknownSizeClusterFollowedByEBMLHeader) {
177 const uint8 kBuffer[] = {
178 0x1F, 0x43, 0xB6, 0x75, 0xFF, // CLUSTER (size = unknown; really 0 due to:)
179 0x1A, 0x45, 0xDF, 0xA3, 0x80, // EBMLHEADER (size = 0)
180 };
181
182 InSequence s;
183 EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
184 EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
185
186 WebMListParser parser(kWebMIdCluster, &client_);
187
188 // List parse should consume the CLUSTER but not the EBMLHEADER.
189 EXPECT_EQ(5, parser.Parse(kBuffer, sizeof(kBuffer)));
190 EXPECT_TRUE(parser.IsParsingComplete());
191 }
192
TEST_F(WebMParserTest,VoidAndCRC32InList)193 TEST_F(WebMParserTest, VoidAndCRC32InList) {
194 const uint8 kBuffer[] = {
195 0x18, 0x53, 0x80, 0x67, 0x99, // SEGMENT (size = 25)
196 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
197 0xBF, 0x83, 0x00, 0x00, 0x00, // CRC32 (size = 3)
198 0x1F, 0x43, 0xB6, 0x75, 0x8A, // CLUSTER (size = 10)
199 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
200 0xBF, 0x83, 0x00, 0x00, 0x00, // CRC32 (size = 3)
201 };
202 int size = sizeof(kBuffer);
203
204 InSequence s;
205 EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
206 EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
207 EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
208 EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
209
210 WebMListParser parser(kWebMIdSegment, &client_);
211 EXPECT_EQ(size, parser.Parse(kBuffer, size));
212 EXPECT_TRUE(parser.IsParsingComplete());
213 }
214
215
TEST_F(WebMParserTest,ParseListElementWithSingleCall)216 TEST_F(WebMParserTest, ParseListElementWithSingleCall) {
217 scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
218 CreateClusterExpectations(kBlockCount, true, &client_);
219
220 WebMListParser parser(kWebMIdCluster, &client_);
221 EXPECT_EQ(cluster->size(), parser.Parse(cluster->data(), cluster->size()));
222 EXPECT_TRUE(parser.IsParsingComplete());
223 }
224
TEST_F(WebMParserTest,ParseListElementWithMultipleCalls)225 TEST_F(WebMParserTest, ParseListElementWithMultipleCalls) {
226 scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
227 CreateClusterExpectations(kBlockCount, true, &client_);
228
229 const uint8* data = cluster->data();
230 int size = cluster->size();
231 int default_parse_size = 3;
232 WebMListParser parser(kWebMIdCluster, &client_);
233 int parse_size = std::min(default_parse_size, size);
234
235 while (size > 0) {
236 int result = parser.Parse(data, parse_size);
237 ASSERT_GE(result, 0);
238 ASSERT_LE(result, parse_size);
239
240 if (result == 0) {
241 // The parser needs more data so increase the parse_size a little.
242 EXPECT_FALSE(parser.IsParsingComplete());
243 parse_size += default_parse_size;
244 parse_size = std::min(parse_size, size);
245 continue;
246 }
247
248 parse_size = default_parse_size;
249
250 data += result;
251 size -= result;
252
253 EXPECT_EQ((size == 0), parser.IsParsingComplete());
254 }
255 EXPECT_TRUE(parser.IsParsingComplete());
256 }
257
TEST_F(WebMParserTest,Reset)258 TEST_F(WebMParserTest, Reset) {
259 InSequence s;
260 scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
261
262 // First expect all but the last block.
263 CreateClusterExpectations(kBlockCount - 1, false, &client_);
264
265 // Now expect all blocks.
266 CreateClusterExpectations(kBlockCount, true, &client_);
267
268 WebMListParser parser(kWebMIdCluster, &client_);
269
270 // Send slightly less than the full cluster so all but the last block is
271 // parsed.
272 int result = parser.Parse(cluster->data(), cluster->size() - 1);
273 EXPECT_GT(result, 0);
274 EXPECT_LT(result, cluster->size());
275 EXPECT_FALSE(parser.IsParsingComplete());
276
277 parser.Reset();
278
279 // Now parse a whole cluster to verify that all the blocks will get parsed.
280 EXPECT_EQ(cluster->size(), parser.Parse(cluster->data(), cluster->size()));
281 EXPECT_TRUE(parser.IsParsingComplete());
282 }
283
284 // Test the case where multiple clients are used for different lists.
TEST_F(WebMParserTest,MultipleClients)285 TEST_F(WebMParserTest, MultipleClients) {
286 const uint8 kBuffer[] = {
287 0x18, 0x53, 0x80, 0x67, 0x94, // SEGMENT (size = 20)
288 0x16, 0x54, 0xAE, 0x6B, 0x85, // TRACKS (size = 5)
289 0xAE, 0x83, // TRACKENTRY (size = 3)
290 0xD7, 0x81, 0x01, // TRACKNUMBER (size = 1)
291 0x1F, 0x43, 0xB6, 0x75, 0x85, // CLUSTER (size = 5)
292 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
293 };
294 int size = sizeof(kBuffer);
295
296 StrictMock<MockWebMParserClient> c1_;
297 StrictMock<MockWebMParserClient> c2_;
298 StrictMock<MockWebMParserClient> c3_;
299
300 InSequence s;
301 EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&c1_));
302 EXPECT_CALL(c1_, OnListStart(kWebMIdTracks)).WillOnce(Return(&c2_));
303 EXPECT_CALL(c2_, OnListStart(kWebMIdTrackEntry)).WillOnce(Return(&c3_));
304 EXPECT_CALL(c3_, OnUInt(kWebMIdTrackNumber, 1)).WillOnce(Return(true));
305 EXPECT_CALL(c2_, OnListEnd(kWebMIdTrackEntry)).WillOnce(Return(true));
306 EXPECT_CALL(c1_, OnListEnd(kWebMIdTracks)).WillOnce(Return(true));
307 EXPECT_CALL(c1_, OnListStart(kWebMIdCluster)).WillOnce(Return(&c2_));
308 EXPECT_CALL(c1_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
309 EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
310
311 WebMListParser parser(kWebMIdSegment, &client_);
312 EXPECT_EQ(size, parser.Parse(kBuffer, size));
313 EXPECT_TRUE(parser.IsParsingComplete());
314 }
315
316 // Test the case where multiple clients are used for different lists.
TEST_F(WebMParserTest,InvalidClient)317 TEST_F(WebMParserTest, InvalidClient) {
318 const uint8 kBuffer[] = {
319 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 20)
320 0x16, 0x54, 0xAE, 0x6B, 0x80, // TRACKS (size = 5)
321 };
322
323 InSequence s;
324 EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(ReturnNull());
325
326 WebMListParser parser(kWebMIdSegment, &client_);
327 EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
328 EXPECT_FALSE(parser.IsParsingComplete());
329 }
330
TEST_F(WebMParserTest,ReservedIds)331 TEST_F(WebMParserTest, ReservedIds) {
332 const uint8 k1ByteReservedId[] = { 0xFF, 0x81 };
333 const uint8 k2ByteReservedId[] = { 0x7F, 0xFF, 0x81 };
334 const uint8 k3ByteReservedId[] = { 0x3F, 0xFF, 0xFF, 0x81 };
335 const uint8 k4ByteReservedId[] = { 0x1F, 0xFF, 0xFF, 0xFF, 0x81 };
336 const uint8* kBuffers[] = {
337 k1ByteReservedId,
338 k2ByteReservedId,
339 k3ByteReservedId,
340 k4ByteReservedId
341 };
342
343 for (size_t i = 0; i < arraysize(kBuffers); i++) {
344 int id;
345 int64 element_size;
346 int buffer_size = 2 + i;
347 EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
348 &id, &element_size));
349 EXPECT_EQ(id, kWebMReservedId);
350 EXPECT_EQ(element_size, 1);
351 }
352 }
353
TEST_F(WebMParserTest,ReservedSizes)354 TEST_F(WebMParserTest, ReservedSizes) {
355 const uint8 k1ByteReservedSize[] = { 0xA3, 0xFF };
356 const uint8 k2ByteReservedSize[] = { 0xA3, 0x7F, 0xFF };
357 const uint8 k3ByteReservedSize[] = { 0xA3, 0x3F, 0xFF, 0xFF };
358 const uint8 k4ByteReservedSize[] = { 0xA3, 0x1F, 0xFF, 0xFF, 0xFF };
359 const uint8 k5ByteReservedSize[] = { 0xA3, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF };
360 const uint8 k6ByteReservedSize[] = { 0xA3, 0x07, 0xFF, 0xFF, 0xFF, 0xFF,
361 0xFF };
362 const uint8 k7ByteReservedSize[] = { 0xA3, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
363 0xFF };
364 const uint8 k8ByteReservedSize[] = { 0xA3, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
365 0xFF, 0xFF };
366 const uint8* kBuffers[] = {
367 k1ByteReservedSize,
368 k2ByteReservedSize,
369 k3ByteReservedSize,
370 k4ByteReservedSize,
371 k5ByteReservedSize,
372 k6ByteReservedSize,
373 k7ByteReservedSize,
374 k8ByteReservedSize
375 };
376
377 for (size_t i = 0; i < arraysize(kBuffers); i++) {
378 int id;
379 int64 element_size;
380 int buffer_size = 2 + i;
381 EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
382 &id, &element_size));
383 EXPECT_EQ(id, 0xA3);
384 EXPECT_EQ(element_size, kWebMUnknownSize);
385 }
386 }
387
TEST_F(WebMParserTest,ZeroPaddedStrings)388 TEST_F(WebMParserTest, ZeroPaddedStrings) {
389 const uint8 kBuffer[] = {
390 0x1A, 0x45, 0xDF, 0xA3, 0x91, // EBMLHEADER (size = 17)
391 0x42, 0x82, 0x80, // DocType (size = 0)
392 0x42, 0x82, 0x81, 0x00, // DocType (size = 1) ""
393 0x42, 0x82, 0x81, 'a', // DocType (size = 1) "a"
394 0x42, 0x82, 0x83, 'a', 0x00, 0x00 // DocType (size = 3) "a"
395 };
396 int size = sizeof(kBuffer);
397
398 InSequence s;
399 EXPECT_CALL(client_, OnListStart(kWebMIdEBMLHeader))
400 .WillOnce(Return(&client_));
401 EXPECT_CALL(client_, OnString(kWebMIdDocType, "")).WillOnce(Return(true));
402 EXPECT_CALL(client_, OnString(kWebMIdDocType, "")).WillOnce(Return(true));
403 EXPECT_CALL(client_, OnString(kWebMIdDocType, "a")).WillOnce(Return(true));
404 EXPECT_CALL(client_, OnString(kWebMIdDocType, "a")).WillOnce(Return(true));
405 EXPECT_CALL(client_, OnListEnd(kWebMIdEBMLHeader)).WillOnce(Return(true));
406
407 WebMListParser parser(kWebMIdEBMLHeader, &client_);
408 EXPECT_EQ(size, parser.Parse(kBuffer, size));
409 EXPECT_TRUE(parser.IsParsingComplete());
410 }
411
412 } // namespace media
413