• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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