1 // Copyright (c) 2012 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/webm/webm_content_encodings_client.h" 6 7 #include "base/logging.h" 8 #include "base/stl_util.h" 9 #include "media/webm/webm_constants.h" 10 11 namespace media { 12 13 WebMContentEncodingsClient::WebMContentEncodingsClient(const LogCB& log_cb) 14 : log_cb_(log_cb), 15 content_encryption_encountered_(false), 16 content_encodings_ready_(false) { 17 } 18 19 WebMContentEncodingsClient::~WebMContentEncodingsClient() { 20 STLDeleteElements(&content_encodings_); 21 } 22 23 const ContentEncodings& WebMContentEncodingsClient::content_encodings() const { 24 DCHECK(content_encodings_ready_); 25 return content_encodings_; 26 } 27 28 WebMParserClient* WebMContentEncodingsClient::OnListStart(int id) { 29 if (id == kWebMIdContentEncodings) { 30 DCHECK(!cur_content_encoding_.get()); 31 DCHECK(!content_encryption_encountered_); 32 STLDeleteElements(&content_encodings_); 33 content_encodings_ready_ = false; 34 return this; 35 } 36 37 if (id == kWebMIdContentEncoding) { 38 DCHECK(!cur_content_encoding_.get()); 39 DCHECK(!content_encryption_encountered_); 40 cur_content_encoding_.reset(new ContentEncoding()); 41 return this; 42 } 43 44 if (id == kWebMIdContentEncryption) { 45 DCHECK(cur_content_encoding_.get()); 46 if (content_encryption_encountered_) { 47 MEDIA_LOG(log_cb_) << "Unexpected multiple ContentEncryption."; 48 return NULL; 49 } 50 content_encryption_encountered_ = true; 51 return this; 52 } 53 54 if (id == kWebMIdContentEncAESSettings) { 55 DCHECK(cur_content_encoding_.get()); 56 return this; 57 } 58 59 // This should not happen if WebMListParser is working properly. 60 DCHECK(false); 61 return NULL; 62 } 63 64 // Mandatory occurrence restriction is checked in this function. Multiple 65 // occurrence restriction is checked in OnUInt and OnBinary. 66 bool WebMContentEncodingsClient::OnListEnd(int id) { 67 if (id == kWebMIdContentEncodings) { 68 // ContentEncoding element is mandatory. Check this! 69 if (content_encodings_.empty()) { 70 MEDIA_LOG(log_cb_) << "Missing ContentEncoding."; 71 return false; 72 } 73 content_encodings_ready_ = true; 74 return true; 75 } 76 77 if (id == kWebMIdContentEncoding) { 78 DCHECK(cur_content_encoding_.get()); 79 80 // 81 // Specify default values to missing mandatory elements. 82 // 83 84 if (cur_content_encoding_->order() == ContentEncoding::kOrderInvalid) { 85 // Default value of encoding order is 0, which should only be used on the 86 // first ContentEncoding. 87 if (!content_encodings_.empty()) { 88 MEDIA_LOG(log_cb_) << "Missing ContentEncodingOrder."; 89 return false; 90 } 91 cur_content_encoding_->set_order(0); 92 } 93 94 if (cur_content_encoding_->scope() == ContentEncoding::kScopeInvalid) 95 cur_content_encoding_->set_scope(ContentEncoding::kScopeAllFrameContents); 96 97 if (cur_content_encoding_->type() == ContentEncoding::kTypeInvalid) 98 cur_content_encoding_->set_type(ContentEncoding::kTypeCompression); 99 100 // Check for elements valid in spec but not supported for now. 101 if (cur_content_encoding_->type() == ContentEncoding::kTypeCompression) { 102 MEDIA_LOG(log_cb_) << "ContentCompression not supported."; 103 return false; 104 } 105 106 // Enforce mandatory elements without default values. 107 DCHECK(cur_content_encoding_->type() == ContentEncoding::kTypeEncryption); 108 if (!content_encryption_encountered_) { 109 MEDIA_LOG(log_cb_) << "ContentEncodingType is encryption but" 110 << " ContentEncryption is missing."; 111 return false; 112 } 113 114 content_encodings_.push_back(cur_content_encoding_.release()); 115 content_encryption_encountered_ = false; 116 return true; 117 } 118 119 if (id == kWebMIdContentEncryption) { 120 DCHECK(cur_content_encoding_.get()); 121 // Specify default value for elements that are not present. 122 if (cur_content_encoding_->encryption_algo() == 123 ContentEncoding::kEncAlgoInvalid) { 124 cur_content_encoding_->set_encryption_algo( 125 ContentEncoding::kEncAlgoNotEncrypted); 126 } 127 return true; 128 } 129 130 if (id == kWebMIdContentEncAESSettings) { 131 if (cur_content_encoding_->cipher_mode() == 132 ContentEncoding::kCipherModeInvalid) 133 cur_content_encoding_->set_cipher_mode(ContentEncoding::kCipherModeCtr); 134 return true; 135 } 136 137 // This should not happen if WebMListParser is working properly. 138 DCHECK(false); 139 return false; 140 } 141 142 // Multiple occurrence restriction and range are checked in this function. 143 // Mandatory occurrence restriction is checked in OnListEnd. 144 bool WebMContentEncodingsClient::OnUInt(int id, int64 val) { 145 DCHECK(cur_content_encoding_.get()); 146 147 if (id == kWebMIdContentEncodingOrder) { 148 if (cur_content_encoding_->order() != ContentEncoding::kOrderInvalid) { 149 MEDIA_LOG(log_cb_) << "Unexpected multiple ContentEncodingOrder."; 150 return false; 151 } 152 153 if (val != static_cast<int64>(content_encodings_.size())) { 154 // According to the spec, encoding order starts with 0 and counts upwards. 155 MEDIA_LOG(log_cb_) << "Unexpected ContentEncodingOrder."; 156 return false; 157 } 158 159 cur_content_encoding_->set_order(val); 160 return true; 161 } 162 163 if (id == kWebMIdContentEncodingScope) { 164 if (cur_content_encoding_->scope() != ContentEncoding::kScopeInvalid) { 165 MEDIA_LOG(log_cb_) << "Unexpected multiple ContentEncodingScope."; 166 return false; 167 } 168 169 if (val == ContentEncoding::kScopeInvalid || 170 val > ContentEncoding::kScopeMax) { 171 MEDIA_LOG(log_cb_) << "Unexpected ContentEncodingScope."; 172 return false; 173 } 174 175 if (val & ContentEncoding::kScopeNextContentEncodingData) { 176 MEDIA_LOG(log_cb_) << "Encoded next ContentEncoding is not supported."; 177 return false; 178 } 179 180 cur_content_encoding_->set_scope(static_cast<ContentEncoding::Scope>(val)); 181 return true; 182 } 183 184 if (id == kWebMIdContentEncodingType) { 185 if (cur_content_encoding_->type() != ContentEncoding::kTypeInvalid) { 186 MEDIA_LOG(log_cb_) << "Unexpected multiple ContentEncodingType."; 187 return false; 188 } 189 190 if (val == ContentEncoding::kTypeCompression) { 191 MEDIA_LOG(log_cb_) << "ContentCompression not supported."; 192 return false; 193 } 194 195 if (val != ContentEncoding::kTypeEncryption) { 196 MEDIA_LOG(log_cb_) << "Unexpected ContentEncodingType " << val << "."; 197 return false; 198 } 199 200 cur_content_encoding_->set_type(static_cast<ContentEncoding::Type>(val)); 201 return true; 202 } 203 204 if (id == kWebMIdContentEncAlgo) { 205 if (cur_content_encoding_->encryption_algo() != 206 ContentEncoding::kEncAlgoInvalid) { 207 MEDIA_LOG(log_cb_) << "Unexpected multiple ContentEncAlgo."; 208 return false; 209 } 210 211 if (val < ContentEncoding::kEncAlgoNotEncrypted || 212 val > ContentEncoding::kEncAlgoAes) { 213 MEDIA_LOG(log_cb_) << "Unexpected ContentEncAlgo " << val << "."; 214 return false; 215 } 216 217 cur_content_encoding_->set_encryption_algo( 218 static_cast<ContentEncoding::EncryptionAlgo>(val)); 219 return true; 220 } 221 222 if (id == kWebMIdAESSettingsCipherMode) { 223 if (cur_content_encoding_->cipher_mode() != 224 ContentEncoding::kCipherModeInvalid) { 225 MEDIA_LOG(log_cb_) << "Unexpected multiple AESSettingsCipherMode."; 226 return false; 227 } 228 229 if (val != ContentEncoding::kCipherModeCtr) { 230 MEDIA_LOG(log_cb_) << "Unexpected AESSettingsCipherMode " << val << "."; 231 return false; 232 } 233 234 cur_content_encoding_->set_cipher_mode( 235 static_cast<ContentEncoding::CipherMode>(val)); 236 return true; 237 } 238 239 // This should not happen if WebMListParser is working properly. 240 DCHECK(false); 241 return false; 242 } 243 244 // Multiple occurrence restriction is checked in this function. Mandatory 245 // restriction is checked in OnListEnd. 246 bool WebMContentEncodingsClient::OnBinary(int id, const uint8* data, int size) { 247 DCHECK(cur_content_encoding_.get()); 248 DCHECK(data); 249 DCHECK_GT(size, 0); 250 251 if (id == kWebMIdContentEncKeyID) { 252 if (!cur_content_encoding_->encryption_key_id().empty()) { 253 MEDIA_LOG(log_cb_) << "Unexpected multiple ContentEncKeyID"; 254 return false; 255 } 256 cur_content_encoding_->SetEncryptionKeyId(data, size); 257 return true; 258 } 259 260 // This should not happen if WebMListParser is working properly. 261 DCHECK(false); 262 return false; 263 } 264 265 } // namespace media 266