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: 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 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 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 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 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. 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. 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. 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 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. 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. 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 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 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 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 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. 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. 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 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 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 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