Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: third_party/WebKit/Source/core/html/MediaFragmentURIParser.cpp

Issue 2780403004: Create core/html/media/ and move auxiliary media files in it. (Closed)
Patch Set: actually add autoplay files Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "core/html/MediaFragmentURIParser.h"
27
28 #include "wtf/text/CString.h"
29 #include "wtf/text/StringBuilder.h"
30 #include "wtf/text/WTFString.h"
31
32 namespace blink {
33
34 const unsigned nptIdentiferLength = 4; // "npt:"
35
36 static String collectDigits(const LChar* input,
37 unsigned length,
38 unsigned& position) {
39 StringBuilder digits;
40
41 // http://www.ietf.org/rfc/rfc2326.txt
42 // DIGIT ; any positive number
43 while (position < length && isASCIIDigit(input[position]))
44 digits.append(input[position++]);
45 return digits.toString();
46 }
47
48 static String collectFraction(const LChar* input,
49 unsigned length,
50 unsigned& position) {
51 StringBuilder digits;
52
53 // http://www.ietf.org/rfc/rfc2326.txt
54 // [ "." *DIGIT ]
55 if (input[position] != '.')
56 return String();
57
58 digits.append(input[position++]);
59 while (position < length && isASCIIDigit(input[position]))
60 digits.append(input[position++]);
61 return digits.toString();
62 }
63
64 MediaFragmentURIParser::MediaFragmentURIParser(const KURL& url)
65 : m_url(url),
66 m_timeFormat(None),
67 m_startTime(std::numeric_limits<double>::quiet_NaN()),
68 m_endTime(std::numeric_limits<double>::quiet_NaN()) {}
69
70 double MediaFragmentURIParser::startTime() {
71 if (!m_url.isValid())
72 return std::numeric_limits<double>::quiet_NaN();
73 if (m_timeFormat == None)
74 parseTimeFragment();
75 return m_startTime;
76 }
77
78 double MediaFragmentURIParser::endTime() {
79 if (!m_url.isValid())
80 return std::numeric_limits<double>::quiet_NaN();
81 if (m_timeFormat == None)
82 parseTimeFragment();
83 return m_endTime;
84 }
85
86 void MediaFragmentURIParser::parseFragments() {
87 if (!m_url.hasFragmentIdentifier())
88 return;
89 String fragmentString = m_url.fragmentIdentifier();
90 if (fragmentString.isEmpty())
91 return;
92
93 unsigned offset = 0;
94 unsigned end = fragmentString.length();
95 while (offset < end) {
96 // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#proces sing-name-value-components
97 // 1. Parse the octet string according to the namevalues syntax, yielding a
98 // list of name-value pairs, where name and value are both octet string.
99 // In accordance with RFC 3986, the name and value components must be
100 // parsed and separated before percent-encoded octets are decoded.
101 size_t parameterStart = offset;
102 size_t parameterEnd = fragmentString.find('&', offset);
103 if (parameterEnd == kNotFound)
104 parameterEnd = end;
105
106 size_t equalOffset = fragmentString.find('=', offset);
107 if (equalOffset == kNotFound || equalOffset > parameterEnd) {
108 offset = parameterEnd + 1;
109 continue;
110 }
111
112 // 2. For each name-value pair:
113 // a. Decode percent-encoded octets in name and value as defined by RFC
114 // 3986. If either name or value are not valid percent-encoded strings,
115 // then remove the name-value pair from the list.
116 String name = decodeURLEscapeSequences(
117 fragmentString.substring(parameterStart, equalOffset - parameterStart));
118 String value;
119 if (equalOffset != parameterEnd)
120 value = decodeURLEscapeSequences(fragmentString.substring(
121 equalOffset + 1, parameterEnd - equalOffset - 1));
122
123 // b. Convert name and value to Unicode strings by interpreting them as
124 // UTF-8. If either name or value are not valid UTF-8 strings, then
125 // remove the name-value pair from the list.
126 bool validUTF8 = true;
127 if (!name.isEmpty()) {
128 name = name.utf8(StrictUTF8Conversion).data();
129 validUTF8 = !name.isEmpty();
130 }
131 if (validUTF8 && !value.isEmpty()) {
132 value = value.utf8(StrictUTF8Conversion).data();
133 validUTF8 = !value.isEmpty();
134 }
135
136 if (validUTF8)
137 m_fragments.push_back(std::make_pair(name, value));
138
139 offset = parameterEnd + 1;
140 }
141 }
142
143 void MediaFragmentURIParser::parseTimeFragment() {
144 DCHECK_EQ(m_timeFormat, None);
145
146 if (m_fragments.isEmpty())
147 parseFragments();
148
149 m_timeFormat = Invalid;
150
151 for (const auto& fragment : m_fragments) {
152 DCHECK(fragment.first.is8Bit());
153 DCHECK(fragment.second.is8Bit());
154
155 // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#naming -time
156 // Temporal clipping is denoted by the name t, and specified as an interval
157 // with a begin time and an end time
158 if (fragment.first != "t")
159 continue;
160
161 // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#npt-ti me
162 // Temporal clipping can be specified either as Normal Play Time (npt) RFC
163 // 2326, as SMPTE timecodes, SMPTE, or as real-world clock time (clock) RFC
164 // 2326. Begin and end times are always specified in the same format. The
165 // format is specified by name, followed by a colon (:), with npt: being the
166 // default.
167
168 double start = std::numeric_limits<double>::quiet_NaN();
169 double end = std::numeric_limits<double>::quiet_NaN();
170 if (parseNPTFragment(fragment.second.characters8(),
171 fragment.second.length(), start, end)) {
172 m_startTime = start;
173 m_endTime = end;
174 m_timeFormat = NormalPlayTime;
175
176 // Although we have a valid fragment, don't return yet because when a
177 // fragment dimensions occurs multiple times, only the last occurrence of
178 // that dimension is used:
179 // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#erro r-uri-general
180 // Multiple occurrences of the same dimension: only the last valid
181 // occurrence of a dimension (e.g., t=10 in #t=2&t=10) is interpreted, all
182 // previous occurrences (valid or invalid) SHOULD be ignored by the UA.
183 }
184 }
185 m_fragments.clear();
186 }
187
188 bool MediaFragmentURIParser::parseNPTFragment(const LChar* timeString,
189 unsigned length,
190 double& startTime,
191 double& endTime) {
192 unsigned offset = 0;
193 if (length >= nptIdentiferLength && timeString[0] == 'n' &&
194 timeString[1] == 'p' && timeString[2] == 't' && timeString[3] == ':')
195 offset += nptIdentiferLength;
196
197 if (offset == length)
198 return false;
199
200 // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#naming-t ime
201 // If a single number only is given, this corresponds to the begin time except
202 // if it is preceded by a comma that would in this case indicate the end time.
203 if (timeString[offset] == ',') {
204 startTime = 0;
205 } else {
206 if (!parseNPTTime(timeString, length, offset, startTime))
207 return false;
208 }
209
210 if (offset == length)
211 return true;
212
213 if (timeString[offset] != ',')
214 return false;
215 if (++offset == length)
216 return false;
217
218 if (!parseNPTTime(timeString, length, offset, endTime))
219 return false;
220
221 if (offset != length)
222 return false;
223
224 if (startTime >= endTime)
225 return false;
226
227 return true;
228 }
229
230 bool MediaFragmentURIParser::parseNPTTime(const LChar* timeString,
231 unsigned length,
232 unsigned& offset,
233 double& time) {
234 enum Mode { Minutes, Hours };
235 Mode mode = Minutes;
236
237 if (offset >= length || !isASCIIDigit(timeString[offset]))
238 return false;
239
240 // http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#npttimed ef
241 // Normal Play Time can either be specified as seconds, with an optional
242 // fractional part to indicate miliseconds, or as colon-separated hours,
243 // minutes and seconds (again with an optional fraction). Minutes and
244 // seconds must be specified as exactly two digits, hours and fractional
245 // seconds can be any number of digits. The hours, minutes and seconds
246 // specification for NPT is a convenience only, it does not signal frame
247 // accuracy. The specification of the "npt:" identifier is optional since
248 // NPT is the default time scheme. This specification builds on the RTSP
249 // specification of NPT RFC 2326.
250 //
251 // ; defined in RFC 2326
252 // npt-sec = 1*DIGIT [ "." *DIGIT ]
253 // npt-hhmmss = npt-hh ":" npt-mm ":" npt-ss [ "." *DIGIT]
254 // npt-mmss = npt-mm ":" npt-ss [ "." *DIGIT]
255 // npt-hh = 1*DIGIT ; any positive number
256 // npt-mm = 2DIGIT ; 0-59
257 // npt-ss = 2DIGIT ; 0-59
258
259 String digits1 = collectDigits(timeString, length, offset);
260 int value1 = digits1.toInt();
261 if (offset >= length || timeString[offset] == ',') {
262 time = value1;
263 return true;
264 }
265
266 double fraction = 0;
267 if (timeString[offset] == '.') {
268 if (offset == length)
269 return true;
270 String digits = collectFraction(timeString, length, offset);
271 fraction = digits.toDouble();
272 time = value1 + fraction;
273 return true;
274 }
275
276 if (digits1.length() < 2)
277 return false;
278 if (digits1.length() > 2)
279 mode = Hours;
280
281 // Collect the next sequence of 0-9 after ':'
282 if (offset >= length || timeString[offset++] != ':')
283 return false;
284 if (offset >= length || !isASCIIDigit(timeString[(offset)]))
285 return false;
286 String digits2 = collectDigits(timeString, length, offset);
287 int value2 = digits2.toInt();
288 if (digits2.length() != 2)
289 return false;
290
291 // Detect whether this timestamp includes hours.
292 int value3;
293 if (mode == Hours || (offset < length && timeString[offset] == ':')) {
294 if (offset >= length || timeString[offset++] != ':')
295 return false;
296 if (offset >= length || !isASCIIDigit(timeString[offset]))
297 return false;
298 String digits3 = collectDigits(timeString, length, offset);
299 if (digits3.length() != 2)
300 return false;
301 value3 = digits3.toInt();
302 } else {
303 value3 = value2;
304 value2 = value1;
305 value1 = 0;
306 }
307
308 if (offset < length && timeString[offset] == '.')
309 fraction = collectFraction(timeString, length, offset).toDouble();
310
311 const int secondsPerHour = 3600;
312 const int secondsPerMinute = 60;
313 time = (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 +
314 fraction;
315 return true;
316 }
317
318 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698