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/webm_content_encodings_client.h"
6
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "media/formats/webm/webm_constants.h"
10
11 namespace media {
12
WebMContentEncodingsClient(const LogCB & log_cb)13 WebMContentEncodingsClient::WebMContentEncodingsClient(const LogCB& log_cb)
14 : log_cb_(log_cb),
15 content_encryption_encountered_(false),
16 content_encodings_ready_(false) {
17 }
18
~WebMContentEncodingsClient()19 WebMContentEncodingsClient::~WebMContentEncodingsClient() {
20 STLDeleteElements(&content_encodings_);
21 }
22
content_encodings() const23 const ContentEncodings& WebMContentEncodingsClient::content_encodings() const {
24 DCHECK(content_encodings_ready_);
25 return content_encodings_;
26 }
27
OnListStart(int id)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.
OnListEnd(int id)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.
OnUInt(int id,int64 val)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.
OnBinary(int id,const uint8 * data,int size)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