1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is the media fragment URI parser.
17 : *
18 : * The Initial Developer of the Original Code is the Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2011
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Chris Double <chris.double@double.co.nz>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 : #include "nsCharSeparatedTokenizer.h"
39 : #include "nsEscape.h"
40 : #include "nsMediaFragmentURIParser.h"
41 :
42 0 : nsMediaFragmentURIParser::nsMediaFragmentURIParser(const nsCString& aSpec)
43 : {
44 0 : nsReadingIterator<char> start, end;
45 0 : aSpec.BeginReading(start);
46 0 : aSpec.EndReading(end);
47 0 : if (FindCharInReadable('#', start, end)) {
48 0 : mHash = Substring(++start, end);
49 : }
50 0 : }
51 :
52 0 : bool nsMediaFragmentURIParser::ParseNPT(nsDependentSubstring& aString, double& aStart, double& aEnd)
53 : {
54 0 : nsDependentSubstring original(aString);
55 0 : if (aString.Length() > 4 &&
56 0 : aString[0] == 'n' && aString[1] == 'p' &&
57 0 : aString[2] == 't' && aString[3] == ':') {
58 0 : aString.Rebind(aString, 4);
59 : }
60 :
61 0 : if (aString.Length() == 0) {
62 0 : return false;
63 : }
64 :
65 0 : double start = -1.0;
66 0 : double end = -1.0;
67 :
68 0 : if (ParseNPTTime(aString, start)) {
69 0 : aStart = start;
70 : }
71 :
72 0 : if (aString.Length() == 0) {
73 0 : return true;
74 : }
75 :
76 0 : if (aString[0] != ',') {
77 0 : aString.Rebind(original, 0);
78 0 : return false;
79 : }
80 :
81 0 : aString.Rebind(aString, 1);
82 :
83 0 : if (aString.Length() == 0) {
84 0 : aString.Rebind(original, 0);
85 0 : return false;
86 : }
87 :
88 0 : if (ParseNPTTime(aString, end)) {
89 0 : aEnd = end;
90 : }
91 :
92 0 : if (aString.Length() != 0) {
93 0 : aString.Rebind(original, 0);
94 0 : return false;
95 : }
96 :
97 0 : return true;
98 : }
99 :
100 0 : bool nsMediaFragmentURIParser::ParseNPTTime(nsDependentSubstring& aString, double& aTime)
101 : {
102 0 : if (aString.Length() == 0) {
103 0 : return false;
104 : }
105 :
106 : return
107 0 : ParseNPTHHMMSS(aString, aTime) ||
108 0 : ParseNPTMMSS(aString, aTime) ||
109 0 : ParseNPTSec(aString, aTime);
110 : }
111 :
112 : // Return true if the given character is a numeric character
113 0 : static bool IsDigit(nsDependentSubstring::char_type aChar)
114 : {
115 0 : return (aChar >= '0' && aChar <= '9');
116 : }
117 :
118 : // Return the index of the first character in the string that is not
119 : // a numerical digit, starting from 'aStart'.
120 0 : static PRUint32 FirstNonDigit(nsDependentSubstring& aString, PRUint32 aStart)
121 : {
122 0 : while (aStart < aString.Length() && IsDigit(aString[aStart])) {
123 0 : ++aStart;
124 : }
125 0 : return aStart;
126 : }
127 :
128 0 : bool nsMediaFragmentURIParser::ParseNPTSec(nsDependentSubstring& aString, double& aSec)
129 : {
130 0 : nsDependentSubstring original(aString);
131 0 : if (aString.Length() == 0) {
132 0 : return false;
133 : }
134 :
135 0 : PRUint32 index = FirstNonDigit(aString, 0);
136 0 : if (index == 0) {
137 0 : return false;
138 : }
139 :
140 0 : nsDependentSubstring n(aString, 0, index);
141 : PRInt32 ec;
142 0 : PRInt32 s = PromiseFlatString(n).ToInteger(&ec);
143 0 : if (NS_FAILED(ec)) {
144 0 : return false;
145 : }
146 :
147 0 : aString.Rebind(aString, index);
148 0 : double fraction = 0.0;
149 0 : if (!ParseNPTFraction(aString, fraction)) {
150 0 : aString.Rebind(original, 0);
151 0 : return false;
152 : }
153 :
154 0 : aSec = s + fraction;
155 0 : return true;
156 : }
157 :
158 0 : bool nsMediaFragmentURIParser::ParseNPTMMSS(nsDependentSubstring& aString, double& aTime)
159 : {
160 0 : nsDependentSubstring original(aString);
161 0 : PRUint32 mm = 0;
162 0 : PRUint32 ss = 0;
163 0 : double fraction = 0.0;
164 0 : if (!ParseNPTMM(aString, mm)) {
165 0 : aString.Rebind(original, 0);
166 0 : return false;
167 : }
168 :
169 0 : if (aString.Length() < 2 || aString[0] != ':') {
170 0 : aString.Rebind(original, 0);
171 0 : return false;
172 : }
173 :
174 0 : aString.Rebind(aString, 1);
175 0 : if (!ParseNPTSS(aString, ss)) {
176 0 : aString.Rebind(original, 0);
177 0 : return false;
178 : }
179 :
180 0 : if (!ParseNPTFraction(aString, fraction)) {
181 0 : aString.Rebind(original, 0);
182 0 : return false;
183 : }
184 0 : aTime = mm * 60 + ss + fraction;
185 0 : return true;
186 : }
187 :
188 0 : bool nsMediaFragmentURIParser::ParseNPTFraction(nsDependentSubstring& aString, double& aFraction)
189 : {
190 0 : double fraction = 0.0;
191 :
192 0 : if (aString.Length() > 0 && aString[0] == '.') {
193 0 : PRUint32 index = FirstNonDigit(aString, 1);
194 :
195 0 : if (index > 1) {
196 0 : nsDependentSubstring number(aString, 0, index);
197 : PRInt32 ec;
198 0 : fraction = PromiseFlatString(number).ToDouble(&ec);
199 0 : if (NS_FAILED(ec)) {
200 0 : return false;
201 : }
202 : }
203 0 : aString.Rebind(aString, index);
204 : }
205 :
206 0 : aFraction = fraction;
207 0 : return true;
208 : }
209 :
210 0 : bool nsMediaFragmentURIParser::ParseNPTHHMMSS(nsDependentSubstring& aString, double& aTime)
211 : {
212 0 : nsDependentSubstring original(aString);
213 0 : PRUint32 hh = 0;
214 0 : double seconds = 0.0;
215 0 : if (!ParseNPTHH(aString, hh)) {
216 0 : return false;
217 : }
218 :
219 0 : if (aString.Length() < 2 || aString[0] != ':') {
220 0 : aString.Rebind(original, 0);
221 0 : return false;
222 : }
223 :
224 0 : aString.Rebind(aString, 1);
225 0 : if (!ParseNPTMMSS(aString, seconds)) {
226 0 : aString.Rebind(original, 0);
227 0 : return false;
228 : }
229 :
230 0 : aTime = hh * 3600 + seconds;
231 0 : return true;
232 : }
233 :
234 0 : bool nsMediaFragmentURIParser::ParseNPTHH(nsDependentSubstring& aString, PRUint32& aHour)
235 : {
236 0 : if (aString.Length() == 0) {
237 0 : return false;
238 : }
239 :
240 0 : PRUint32 index = FirstNonDigit(aString, 0);
241 0 : if (index == 0) {
242 0 : return false;
243 : }
244 :
245 0 : nsDependentSubstring n(aString, 0, index);
246 : PRInt32 ec;
247 0 : PRInt32 u = PromiseFlatString(n).ToInteger(&ec);
248 0 : if (NS_FAILED(ec)) {
249 0 : return false;
250 : }
251 :
252 0 : aString.Rebind(aString, index);
253 0 : aHour = u;
254 0 : return true;
255 : }
256 :
257 0 : bool nsMediaFragmentURIParser::ParseNPTMM(nsDependentSubstring& aString, PRUint32& aMinute)
258 : {
259 0 : return ParseNPTSS(aString, aMinute);
260 : }
261 :
262 0 : bool nsMediaFragmentURIParser::ParseNPTSS(nsDependentSubstring& aString, PRUint32& aSecond)
263 : {
264 0 : if (aString.Length() < 2) {
265 0 : return false;
266 : }
267 :
268 0 : if (IsDigit(aString[0]) && IsDigit(aString[1])) {
269 0 : nsDependentSubstring n(aString, 0, 2);
270 : PRInt32 ec;
271 :
272 0 : PRInt32 u = PromiseFlatString(n).ToInteger(&ec);
273 0 : if (NS_FAILED(ec)) {
274 0 : return false;
275 : }
276 :
277 0 : aString.Rebind(aString, 2);
278 0 : if (u >= 60)
279 0 : return false;
280 :
281 0 : aSecond = u;
282 0 : return true;
283 : }
284 :
285 0 : return false;
286 : }
287 :
288 0 : void nsMediaFragmentURIParser::Parse()
289 : {
290 0 : nsCCharSeparatedTokenizer tokenizer(mHash, '&');
291 0 : while (tokenizer.hasMoreTokens()) {
292 0 : const nsCSubstring& nv = tokenizer.nextToken();
293 0 : PRInt32 index = nv.FindChar('=');
294 0 : if (index >= 0) {
295 0 : nsCAutoString name;
296 0 : nsCAutoString value;
297 0 : NS_UnescapeURL(StringHead(nv, index), esc_Ref | esc_AlwaysCopy, name);
298 0 : NS_UnescapeURL(Substring(nv, index + 1, nv.Length()),
299 0 : esc_Ref | esc_AlwaysCopy, value);
300 0 : nsAutoString a = NS_ConvertUTF8toUTF16(name);
301 0 : nsAutoString b = NS_ConvertUTF8toUTF16(value);
302 0 : mFragments.AppendElement(Pair(a, b));
303 : }
304 : }
305 0 : }
306 :
307 0 : double nsMediaFragmentURIParser::GetStartTime()
308 : {
309 0 : for (PRUint32 i = 0; i < mFragments.Length(); ++i) {
310 0 : PRUint32 index = mFragments.Length() - i - 1;
311 0 : if (mFragments[index].mName.EqualsLiteral("t")) {
312 0 : double start = -1;
313 0 : double end = -1;
314 0 : nsDependentSubstring s(mFragments[index].mValue, 0);
315 0 : if (ParseNPT(s, start, end)) {
316 0 : return start;
317 : }
318 : }
319 : }
320 0 : return 0.0;
321 : }
322 :
323 0 : double nsMediaFragmentURIParser::GetEndTime()
324 : {
325 0 : for (PRUint32 i = 0; i < mFragments.Length(); ++i) {
326 0 : PRUint32 index = mFragments.Length() - i - 1;
327 0 : if (mFragments[index].mName.EqualsLiteral("t")) {
328 0 : double start = -1;
329 0 : double end = -1;
330 0 : nsDependentSubstring s(mFragments[index].mValue, 0);
331 0 : if (ParseNPT(s, start, end)) {
332 0 : return end;
333 : }
334 : }
335 : }
336 0 : return -1;
337 : }
338 :
339 :
|