commit 1a8092d3eeea75e280e43fcf077a14996c6511c5
parent 888ad507a9896365dfc6148663e6329ac8b63b4e
Author: longsonr <longsonr@gmail.com>
Date: Wed, 19 Nov 2025 13:51:33 +0000
Bug 1999989 Part 1 - Rename, move and export MediaFragmentURIParser r=emilio,necko-reviewers,media-playback-reviewers,karlt,valentin
Differential Revision: https://phabricator.services.mozilla.com/D272471
Diffstat:
9 files changed, 465 insertions(+), 461 deletions(-)
diff --git a/dom/media/MediaFragmentURIParser.cpp b/dom/media/MediaFragmentURIParser.cpp
@@ -0,0 +1,353 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MediaFragmentURIParser.h"
+
+#include <utility>
+
+#include "nsCharSeparatedTokenizer.h"
+#include "nsEscape.h"
+#include "nsIURI.h"
+#include "nsTArray.h"
+
+using std::make_pair;
+using std::pair;
+
+namespace mozilla {
+
+MediaFragmentURIParser::MediaFragmentURIParser(nsIURI* aURI)
+ : mClipUnit(eClipUnit_Pixel) {
+ nsAutoCString ref;
+ aURI->GetRef(ref);
+ Parse(ref);
+}
+
+MediaFragmentURIParser::MediaFragmentURIParser(nsCString& aRef)
+ : mClipUnit(eClipUnit_Pixel) {
+ Parse(aRef);
+}
+
+bool MediaFragmentURIParser::ParseNPT(nsDependentSubstring aString) {
+ nsDependentSubstring original(aString);
+ if (aString.Length() > 4 && aString[0] == 'n' && aString[1] == 'p' &&
+ aString[2] == 't' && aString[3] == ':') {
+ aString.Rebind(aString, 4);
+ }
+
+ if (aString.Length() == 0) {
+ return false;
+ }
+
+ double start = -1.0;
+ double end = -1.0;
+
+ ParseNPTTime(aString, start);
+
+ if (aString.Length() == 0) {
+ mStart.emplace(start);
+ return true;
+ }
+
+ if (aString[0] != ',') {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ aString.Rebind(aString, 1);
+
+ if (aString.Length() == 0) {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ ParseNPTTime(aString, end);
+
+ if (end <= start || aString.Length() != 0) {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ mStart.emplace(start);
+ mEnd.emplace(end);
+ return true;
+}
+
+bool MediaFragmentURIParser::ParseNPTTime(nsDependentSubstring& aString,
+ double& aTime) {
+ if (aString.Length() == 0) {
+ return false;
+ }
+
+ return ParseNPTHHMMSS(aString, aTime) || ParseNPTMMSS(aString, aTime) ||
+ ParseNPTSec(aString, aTime);
+}
+
+// Return true if the given character is a numeric character
+static bool IsDigit(nsDependentSubstring::char_type aChar) {
+ return (aChar >= '0' && aChar <= '9');
+}
+
+// Return the index of the first character in the string that is not
+// a numerical digit, starting from 'aStart'.
+static uint32_t FirstNonDigit(nsDependentSubstring& aString, uint32_t aStart) {
+ while (aStart < aString.Length() && IsDigit(aString[aStart])) {
+ ++aStart;
+ }
+ return aStart;
+}
+
+bool MediaFragmentURIParser::ParseNPTSec(nsDependentSubstring& aString,
+ double& aSec) {
+ nsDependentSubstring original(aString);
+ if (aString.Length() == 0) {
+ return false;
+ }
+
+ uint32_t index = FirstNonDigit(aString, 0);
+ if (index == 0) {
+ return false;
+ }
+
+ nsDependentSubstring n(aString, 0, index);
+ nsresult ec;
+ int32_t s = n.ToInteger(&ec);
+ if (NS_FAILED(ec)) {
+ return false;
+ }
+
+ aString.Rebind(aString, index);
+ double fraction = 0.0;
+ if (!ParseNPTFraction(aString, fraction)) {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ aSec = s + fraction;
+ return true;
+}
+
+bool MediaFragmentURIParser::ParseNPTMMSS(nsDependentSubstring& aString,
+ double& aTime) {
+ nsDependentSubstring original(aString);
+ uint32_t mm = 0;
+ uint32_t ss = 0;
+ double fraction = 0.0;
+ if (!ParseNPTMM(aString, mm)) {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ if (aString.Length() < 2 || aString[0] != ':') {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ aString.Rebind(aString, 1);
+ if (!ParseNPTSS(aString, ss)) {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ if (!ParseNPTFraction(aString, fraction)) {
+ aString.Rebind(original, 0);
+ return false;
+ }
+ aTime = mm * 60 + ss + fraction;
+ return true;
+}
+
+bool MediaFragmentURIParser::ParseNPTFraction(nsDependentSubstring& aString,
+ double& aFraction) {
+ double fraction = 0.0;
+
+ if (aString.Length() > 0 && aString[0] == '.') {
+ uint32_t index = FirstNonDigit(aString, 1);
+
+ if (index > 1) {
+ nsDependentSubstring number(aString, 0, index);
+ nsresult ec;
+ fraction = PromiseFlatString(number).ToDouble(&ec);
+ if (NS_FAILED(ec)) {
+ return false;
+ }
+ }
+ aString.Rebind(aString, index);
+ }
+
+ aFraction = fraction;
+ return true;
+}
+
+bool MediaFragmentURIParser::ParseNPTHHMMSS(nsDependentSubstring& aString,
+ double& aTime) {
+ nsDependentSubstring original(aString);
+ uint32_t hh = 0;
+ double seconds = 0.0;
+ if (!ParseNPTHH(aString, hh)) {
+ return false;
+ }
+
+ if (aString.Length() < 2 || aString[0] != ':') {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ aString.Rebind(aString, 1);
+ if (!ParseNPTMMSS(aString, seconds)) {
+ aString.Rebind(original, 0);
+ return false;
+ }
+
+ aTime = hh * 3600 + seconds;
+ return true;
+}
+
+bool MediaFragmentURIParser::ParseNPTHH(nsDependentSubstring& aString,
+ uint32_t& aHour) {
+ if (aString.Length() == 0) {
+ return false;
+ }
+
+ uint32_t index = FirstNonDigit(aString, 0);
+ if (index == 0) {
+ return false;
+ }
+
+ nsDependentSubstring n(aString, 0, index);
+ nsresult ec;
+ int32_t u = n.ToInteger(&ec);
+ if (NS_FAILED(ec)) {
+ return false;
+ }
+
+ aString.Rebind(aString, index);
+ aHour = u;
+ return true;
+}
+
+bool MediaFragmentURIParser::ParseNPTMM(nsDependentSubstring& aString,
+ uint32_t& aMinute) {
+ return ParseNPTSS(aString, aMinute);
+}
+
+bool MediaFragmentURIParser::ParseNPTSS(nsDependentSubstring& aString,
+ uint32_t& aSecond) {
+ if (aString.Length() < 2) {
+ return false;
+ }
+
+ if (IsDigit(aString[0]) && IsDigit(aString[1])) {
+ nsDependentSubstring n(aString, 0, 2);
+ nsresult ec;
+ int32_t u = n.ToInteger(&ec);
+ if (NS_FAILED(ec)) {
+ return false;
+ }
+
+ aString.Rebind(aString, 2);
+ if (u >= 60) return false;
+
+ aSecond = u;
+ return true;
+ }
+
+ return false;
+}
+
+static bool ParseInteger(nsDependentSubstring& aString, int32_t& aResult) {
+ uint32_t index = FirstNonDigit(aString, 0);
+ if (index == 0) {
+ return false;
+ }
+
+ nsDependentSubstring n(aString, 0, index);
+ nsresult ec;
+ int32_t s = n.ToInteger(&ec);
+ if (NS_FAILED(ec)) {
+ return false;
+ }
+
+ aString.Rebind(aString, index);
+ aResult = s;
+ return true;
+}
+
+static bool ParseCommaSeparator(nsDependentSubstring& aString) {
+ if (aString.Length() > 1 && aString[0] == ',') {
+ aString.Rebind(aString, 1);
+ return true;
+ }
+
+ return false;
+}
+
+bool MediaFragmentURIParser::ParseXYWH(nsDependentSubstring aString) {
+ int32_t x, y, w, h;
+ ClipUnit clipUnit;
+
+ // Determine units.
+ if (StringBeginsWith(aString, u"pixel:"_ns)) {
+ clipUnit = eClipUnit_Pixel;
+ aString.Rebind(aString, 6);
+ } else if (StringBeginsWith(aString, u"percent:"_ns)) {
+ clipUnit = eClipUnit_Percent;
+ aString.Rebind(aString, 8);
+ } else {
+ clipUnit = eClipUnit_Pixel;
+ }
+
+ // Read and validate coordinates.
+ if (ParseInteger(aString, x) && x >= 0 && ParseCommaSeparator(aString) &&
+ ParseInteger(aString, y) && y >= 0 && ParseCommaSeparator(aString) &&
+ ParseInteger(aString, w) && w > 0 && ParseCommaSeparator(aString) &&
+ ParseInteger(aString, h) && h > 0 && aString.Length() == 0) {
+ // Reject invalid percentage coordinates.
+ if (clipUnit == eClipUnit_Percent && (x + w > 100 || y + h > 100)) {
+ return false;
+ }
+
+ mClip.emplace(x, y, w, h);
+ mClipUnit = clipUnit;
+ return true;
+ }
+
+ return false;
+}
+
+void MediaFragmentURIParser::Parse(nsACString& aRef) {
+ // Create an array of possibly-invalid media fragments.
+ nsTArray<std::pair<nsCString, nsCString> > fragments;
+
+ for (const nsACString& nv : nsCCharSeparatedTokenizer(aRef, '&').ToRange()) {
+ int32_t index = nv.FindChar('=');
+ if (index >= 0) {
+ nsAutoCString name;
+ nsAutoCString value;
+ NS_UnescapeURL(StringHead(nv, index), esc_Ref | esc_AlwaysCopy, name);
+ NS_UnescapeURL(Substring(nv, index + 1, nv.Length()),
+ esc_Ref | esc_AlwaysCopy, value);
+ fragments.AppendElement(make_pair(name, value));
+ }
+ }
+
+ // Parse the media fragment values.
+ bool gotTemporal = false, gotSpatial = false;
+ for (int i = fragments.Length() - 1; i >= 0; --i) {
+ if (gotTemporal && gotSpatial) {
+ // We've got one of each possible type. No need to look at the rest.
+ break;
+ }
+ if (!gotTemporal && fragments[i].first.EqualsLiteral("t")) {
+ nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
+ gotTemporal = ParseNPT(nsDependentSubstring(value, 0));
+ } else if (!gotSpatial && fragments[i].first.EqualsLiteral("xywh")) {
+ nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
+ gotSpatial = ParseXYWH(nsDependentSubstring(value, 0));
+ }
+ }
+}
+
+} // namespace mozilla
diff --git a/dom/media/MediaFragmentURIParser.h b/dom/media/MediaFragmentURIParser.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#if !defined(MediaFragmentURIParser_h__)
+# define MediaFragmentURIParser_h__
+
+# include "mozilla/Maybe.h"
+# include "nsRect.h"
+# include "nsStringFwd.h"
+
+class nsIURI;
+
+// Class to handle parsing of a W3C media fragment URI as per
+// spec at: http://www.w3.org/TR/media-frags/
+// Only the temporaral URI portion of the spec is implemented.
+// To use:
+// a) Construct an instance with the URI containing the fragment
+// b) Check for the validity of the values you are interested in
+// using e.g. HasStartTime().
+// c) If the values are valid, obtain them using e.g. GetStartTime().
+
+namespace mozilla {
+
+enum ClipUnit {
+ eClipUnit_Pixel,
+ eClipUnit_Percent,
+};
+
+class MediaFragmentURIParser {
+ public:
+ // Create a parser with the provided URI.
+ explicit MediaFragmentURIParser(nsIURI* aURI);
+
+ // Create a parser with the provided URI reference portion.
+ explicit MediaFragmentURIParser(nsCString& aRef);
+
+ // True if a valid temporal media fragment indicated a start time.
+ bool HasStartTime() const { return mStart.isSome(); }
+
+ // If a valid temporal media fragment indicated a start time, returns
+ // it in units of seconds. If not, defaults to 0.
+ double GetStartTime() const { return *mStart; }
+
+ // True if a valid temporal media fragment indicated an end time.
+ bool HasEndTime() const { return mEnd.isSome(); }
+
+ // If a valid temporal media fragment indicated an end time, returns
+ // it in units of seconds. If not, defaults to -1.
+ double GetEndTime() const { return *mEnd; }
+
+ // True if a valid spatial media fragment indicated a clipping region.
+ bool HasClip() const { return mClip.isSome(); }
+
+ // If a valid spatial media fragment indicated a clipping region,
+ // returns the region. If not, returns an empty region. The unit
+ // used depends on the value returned by GetClipUnit().
+ nsIntRect GetClip() const { return *mClip; }
+
+ // If a valid spatial media fragment indicated a clipping region,
+ // returns the unit used.
+ ClipUnit GetClipUnit() const { return mClipUnit; }
+
+ private:
+ // Parse the URI ref provided, looking for media fragments. This is
+ // the top-level parser the invokes the others below.
+ void Parse(nsACString& aRef);
+
+ // The following methods parse the fragment as per the media
+ // fragments specification. 'aString' contains the remaining
+ // fragment data to be parsed. The method returns true
+ // if the parse was successful and leaves the remaining unparsed
+ // data in 'aString'. If the parse fails then false is returned
+ // and 'aString' is left as it was when called.
+ bool ParseNPT(nsDependentSubstring aString);
+ bool ParseNPTTime(nsDependentSubstring& aString, double& aTime);
+ bool ParseNPTSec(nsDependentSubstring& aString, double& aSec);
+ bool ParseNPTFraction(nsDependentSubstring& aString, double& aFraction);
+ bool ParseNPTMMSS(nsDependentSubstring& aString, double& aTime);
+ bool ParseNPTHHMMSS(nsDependentSubstring& aString, double& aTime);
+ bool ParseNPTHH(nsDependentSubstring& aString, uint32_t& aHour);
+ bool ParseNPTMM(nsDependentSubstring& aString, uint32_t& aMinute);
+ bool ParseNPTSS(nsDependentSubstring& aString, uint32_t& aSecond);
+ bool ParseXYWH(nsDependentSubstring aString);
+ bool ParseMozResolution(nsDependentSubstring aString);
+
+ // Media fragment information.
+ Maybe<double> mStart;
+ Maybe<double> mEnd;
+ Maybe<nsIntRect> mClip;
+ ClipUnit mClipUnit;
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/dom/media/mediaelement/HTMLMediaElement.cpp b/dom/media/mediaelement/HTMLMediaElement.cpp
@@ -59,6 +59,7 @@
#include "mozilla/EMEUtils.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/MathAlgorithms.h"
+#include "mozilla/MediaFragmentURIParser.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/SVGObserverUtils.h"
@@ -123,7 +124,6 @@
#include "nsITimer.h"
#include "nsJSUtils.h"
#include "nsLayoutUtils.h"
-#include "nsMediaFragmentURIParser.h"
#include "nsMimeTypes.h"
#include "nsNetUtil.h"
#include "nsNodeInfoManager.h"
@@ -161,7 +161,6 @@ extern mozilla::LazyLogModule gAutoplayPermissionLog;
#define LOG_EVENT(type, msg) MOZ_LOG(gMediaElementEventsLog, type, msg)
using namespace mozilla::layers;
-using mozilla::net::nsMediaFragmentURIParser;
using namespace mozilla::dom::HTMLMediaElement_Binding;
namespace mozilla::dom {
@@ -5833,7 +5832,7 @@ void HTMLMediaElement::ProcessMediaFragmentURI() {
mFragmentStart = mFragmentEnd = -1.0;
return;
}
- nsMediaFragmentURIParser parser(mLoadingSrc);
+ MediaFragmentURIParser parser(mLoadingSrc);
if (mDecoder && parser.HasEndTime()) {
mFragmentEnd = parser.GetEndTime();
diff --git a/dom/media/mediaelement/moz.build b/dom/media/mediaelement/moz.build
@@ -33,7 +33,6 @@ include("/ipc/chromium/chromium-config.mozbuild")
LOCAL_INCLUDES += [
"/dom/base",
"/dom/media",
- "/netwerk/base",
"/third_party/abseil-cpp",
"/third_party/libwebrtc",
]
diff --git a/dom/media/moz.build b/dom/media/moz.build
@@ -82,6 +82,17 @@ if CONFIG["MOZ_WEBRTC_SIGNALING"]:
if CONFIG["FUZZING_INTERFACES"]:
TEST_DIRS += ["webrtc/tests/fuzztests"]
+if CONFIG["FUZZING_INTERFACES"] and CONFIG["LIBFUZZER"]:
+ include("/tools/fuzzing/libfuzzer-flags.mozbuild")
+ SOURCES += [
+ "MediaFragmentURIParser.cpp",
+ ]
+ SOURCES["MediaFragmentURIParser.cpp"].flags += libfuzzer_flags
+else:
+ UNIFIED_SOURCES += [
+ "MediaFragmentURIParser.cpp",
+ ]
+
MOCHITEST_MANIFESTS += [
"test/mochitest.toml",
"test/mochitest_background_video.toml",
@@ -213,6 +224,7 @@ EXPORTS += [
]
EXPORTS.mozilla += [
+ "MediaFragmentURIParser.h",
"MediaManager.h",
"UnderrunHandler.h",
]
diff --git a/image/ImageFactory.cpp b/image/ImageFactory.cpp
@@ -19,7 +19,7 @@
#include "RasterImage.h"
#include "VectorImage.h"
#include "Image.h"
-#include "nsMediaFragmentURIParser.h"
+#include "mozilla/MediaFragmentURIParser.h"
#include "nsContentUtils.h"
#include "mozilla/SchedulerGroup.h"
diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build
@@ -267,16 +267,13 @@ if CONFIG["FUZZING"]:
if CONFIG["FUZZING_INTERFACES"] and CONFIG["LIBFUZZER"]:
include("/tools/fuzzing/libfuzzer-flags.mozbuild")
SOURCES += [
- "nsMediaFragmentURIParser.cpp",
"nsURLHelper.cpp",
"nsURLParsers.cpp",
]
- SOURCES["nsMediaFragmentURIParser.cpp"].flags += libfuzzer_flags
SOURCES["nsURLHelper.cpp"].flags += libfuzzer_flags
SOURCES["nsURLParsers.cpp"].flags += libfuzzer_flags
else:
UNIFIED_SOURCES += [
- "nsMediaFragmentURIParser.cpp",
"nsURLHelper.cpp",
"nsURLParsers.cpp",
]
diff --git a/netwerk/base/nsMediaFragmentURIParser.cpp b/netwerk/base/nsMediaFragmentURIParser.cpp
@@ -1,354 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsTArray.h"
-#include "nsCharSeparatedTokenizer.h"
-#include "nsEscape.h"
-#include "nsIURI.h"
-#include <utility>
-
-#include "nsMediaFragmentURIParser.h"
-
-using std::make_pair;
-using std::pair;
-
-namespace mozilla {
-namespace net {
-
-nsMediaFragmentURIParser::nsMediaFragmentURIParser(nsIURI* aURI)
- : mClipUnit(eClipUnit_Pixel) {
- nsAutoCString ref;
- aURI->GetRef(ref);
- Parse(ref);
-}
-
-nsMediaFragmentURIParser::nsMediaFragmentURIParser(nsCString& aRef)
- : mClipUnit(eClipUnit_Pixel) {
- Parse(aRef);
-}
-
-bool nsMediaFragmentURIParser::ParseNPT(nsDependentSubstring aString) {
- nsDependentSubstring original(aString);
- if (aString.Length() > 4 && aString[0] == 'n' && aString[1] == 'p' &&
- aString[2] == 't' && aString[3] == ':') {
- aString.Rebind(aString, 4);
- }
-
- if (aString.Length() == 0) {
- return false;
- }
-
- double start = -1.0;
- double end = -1.0;
-
- ParseNPTTime(aString, start);
-
- if (aString.Length() == 0) {
- mStart.emplace(start);
- return true;
- }
-
- if (aString[0] != ',') {
- aString.Rebind(original, 0);
- return false;
- }
-
- aString.Rebind(aString, 1);
-
- if (aString.Length() == 0) {
- aString.Rebind(original, 0);
- return false;
- }
-
- ParseNPTTime(aString, end);
-
- if (end <= start || aString.Length() != 0) {
- aString.Rebind(original, 0);
- return false;
- }
-
- mStart.emplace(start);
- mEnd.emplace(end);
- return true;
-}
-
-bool nsMediaFragmentURIParser::ParseNPTTime(nsDependentSubstring& aString,
- double& aTime) {
- if (aString.Length() == 0) {
- return false;
- }
-
- return ParseNPTHHMMSS(aString, aTime) || ParseNPTMMSS(aString, aTime) ||
- ParseNPTSec(aString, aTime);
-}
-
-// Return true if the given character is a numeric character
-static bool IsDigit(nsDependentSubstring::char_type aChar) {
- return (aChar >= '0' && aChar <= '9');
-}
-
-// Return the index of the first character in the string that is not
-// a numerical digit, starting from 'aStart'.
-static uint32_t FirstNonDigit(nsDependentSubstring& aString, uint32_t aStart) {
- while (aStart < aString.Length() && IsDigit(aString[aStart])) {
- ++aStart;
- }
- return aStart;
-}
-
-bool nsMediaFragmentURIParser::ParseNPTSec(nsDependentSubstring& aString,
- double& aSec) {
- nsDependentSubstring original(aString);
- if (aString.Length() == 0) {
- return false;
- }
-
- uint32_t index = FirstNonDigit(aString, 0);
- if (index == 0) {
- return false;
- }
-
- nsDependentSubstring n(aString, 0, index);
- nsresult ec;
- int32_t s = n.ToInteger(&ec);
- if (NS_FAILED(ec)) {
- return false;
- }
-
- aString.Rebind(aString, index);
- double fraction = 0.0;
- if (!ParseNPTFraction(aString, fraction)) {
- aString.Rebind(original, 0);
- return false;
- }
-
- aSec = s + fraction;
- return true;
-}
-
-bool nsMediaFragmentURIParser::ParseNPTMMSS(nsDependentSubstring& aString,
- double& aTime) {
- nsDependentSubstring original(aString);
- uint32_t mm = 0;
- uint32_t ss = 0;
- double fraction = 0.0;
- if (!ParseNPTMM(aString, mm)) {
- aString.Rebind(original, 0);
- return false;
- }
-
- if (aString.Length() < 2 || aString[0] != ':') {
- aString.Rebind(original, 0);
- return false;
- }
-
- aString.Rebind(aString, 1);
- if (!ParseNPTSS(aString, ss)) {
- aString.Rebind(original, 0);
- return false;
- }
-
- if (!ParseNPTFraction(aString, fraction)) {
- aString.Rebind(original, 0);
- return false;
- }
- aTime = mm * 60 + ss + fraction;
- return true;
-}
-
-bool nsMediaFragmentURIParser::ParseNPTFraction(nsDependentSubstring& aString,
- double& aFraction) {
- double fraction = 0.0;
-
- if (aString.Length() > 0 && aString[0] == '.') {
- uint32_t index = FirstNonDigit(aString, 1);
-
- if (index > 1) {
- nsDependentSubstring number(aString, 0, index);
- nsresult ec;
- fraction = PromiseFlatString(number).ToDouble(&ec);
- if (NS_FAILED(ec)) {
- return false;
- }
- }
- aString.Rebind(aString, index);
- }
-
- aFraction = fraction;
- return true;
-}
-
-bool nsMediaFragmentURIParser::ParseNPTHHMMSS(nsDependentSubstring& aString,
- double& aTime) {
- nsDependentSubstring original(aString);
- uint32_t hh = 0;
- double seconds = 0.0;
- if (!ParseNPTHH(aString, hh)) {
- return false;
- }
-
- if (aString.Length() < 2 || aString[0] != ':') {
- aString.Rebind(original, 0);
- return false;
- }
-
- aString.Rebind(aString, 1);
- if (!ParseNPTMMSS(aString, seconds)) {
- aString.Rebind(original, 0);
- return false;
- }
-
- aTime = hh * 3600 + seconds;
- return true;
-}
-
-bool nsMediaFragmentURIParser::ParseNPTHH(nsDependentSubstring& aString,
- uint32_t& aHour) {
- if (aString.Length() == 0) {
- return false;
- }
-
- uint32_t index = FirstNonDigit(aString, 0);
- if (index == 0) {
- return false;
- }
-
- nsDependentSubstring n(aString, 0, index);
- nsresult ec;
- int32_t u = n.ToInteger(&ec);
- if (NS_FAILED(ec)) {
- return false;
- }
-
- aString.Rebind(aString, index);
- aHour = u;
- return true;
-}
-
-bool nsMediaFragmentURIParser::ParseNPTMM(nsDependentSubstring& aString,
- uint32_t& aMinute) {
- return ParseNPTSS(aString, aMinute);
-}
-
-bool nsMediaFragmentURIParser::ParseNPTSS(nsDependentSubstring& aString,
- uint32_t& aSecond) {
- if (aString.Length() < 2) {
- return false;
- }
-
- if (IsDigit(aString[0]) && IsDigit(aString[1])) {
- nsDependentSubstring n(aString, 0, 2);
- nsresult ec;
- int32_t u = n.ToInteger(&ec);
- if (NS_FAILED(ec)) {
- return false;
- }
-
- aString.Rebind(aString, 2);
- if (u >= 60) return false;
-
- aSecond = u;
- return true;
- }
-
- return false;
-}
-
-static bool ParseInteger(nsDependentSubstring& aString, int32_t& aResult) {
- uint32_t index = FirstNonDigit(aString, 0);
- if (index == 0) {
- return false;
- }
-
- nsDependentSubstring n(aString, 0, index);
- nsresult ec;
- int32_t s = n.ToInteger(&ec);
- if (NS_FAILED(ec)) {
- return false;
- }
-
- aString.Rebind(aString, index);
- aResult = s;
- return true;
-}
-
-static bool ParseCommaSeparator(nsDependentSubstring& aString) {
- if (aString.Length() > 1 && aString[0] == ',') {
- aString.Rebind(aString, 1);
- return true;
- }
-
- return false;
-}
-
-bool nsMediaFragmentURIParser::ParseXYWH(nsDependentSubstring aString) {
- int32_t x, y, w, h;
- ClipUnit clipUnit;
-
- // Determine units.
- if (StringBeginsWith(aString, u"pixel:"_ns)) {
- clipUnit = eClipUnit_Pixel;
- aString.Rebind(aString, 6);
- } else if (StringBeginsWith(aString, u"percent:"_ns)) {
- clipUnit = eClipUnit_Percent;
- aString.Rebind(aString, 8);
- } else {
- clipUnit = eClipUnit_Pixel;
- }
-
- // Read and validate coordinates.
- if (ParseInteger(aString, x) && x >= 0 && ParseCommaSeparator(aString) &&
- ParseInteger(aString, y) && y >= 0 && ParseCommaSeparator(aString) &&
- ParseInteger(aString, w) && w > 0 && ParseCommaSeparator(aString) &&
- ParseInteger(aString, h) && h > 0 && aString.Length() == 0) {
- // Reject invalid percentage coordinates.
- if (clipUnit == eClipUnit_Percent && (x + w > 100 || y + h > 100)) {
- return false;
- }
-
- mClip.emplace(x, y, w, h);
- mClipUnit = clipUnit;
- return true;
- }
-
- return false;
-}
-
-void nsMediaFragmentURIParser::Parse(nsACString& aRef) {
- // Create an array of possibly-invalid media fragments.
- nsTArray<std::pair<nsCString, nsCString> > fragments;
-
- for (const nsACString& nv : nsCCharSeparatedTokenizer(aRef, '&').ToRange()) {
- int32_t index = nv.FindChar('=');
- if (index >= 0) {
- nsAutoCString name;
- nsAutoCString value;
- NS_UnescapeURL(StringHead(nv, index), esc_Ref | esc_AlwaysCopy, name);
- NS_UnescapeURL(Substring(nv, index + 1, nv.Length()),
- esc_Ref | esc_AlwaysCopy, value);
- fragments.AppendElement(make_pair(name, value));
- }
- }
-
- // Parse the media fragment values.
- bool gotTemporal = false, gotSpatial = false;
- for (int i = fragments.Length() - 1; i >= 0; --i) {
- if (gotTemporal && gotSpatial) {
- // We've got one of each possible type. No need to look at the rest.
- break;
- }
- if (!gotTemporal && fragments[i].first.EqualsLiteral("t")) {
- nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
- gotTemporal = ParseNPT(nsDependentSubstring(value, 0));
- } else if (!gotSpatial && fragments[i].first.EqualsLiteral("xywh")) {
- nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
- gotSpatial = ParseXYWH(nsDependentSubstring(value, 0));
- }
- }
-}
-
-} // namespace net
-} // namespace mozilla
diff --git a/netwerk/base/nsMediaFragmentURIParser.h b/netwerk/base/nsMediaFragmentURIParser.h
@@ -1,99 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#if !defined(nsMediaFragmentURIParser_h__)
-# define nsMediaFragmentURIParser_h__
-
-# include "mozilla/Maybe.h"
-# include "nsStringFwd.h"
-# include "nsRect.h"
-
-class nsIURI;
-
-// Class to handle parsing of a W3C media fragment URI as per
-// spec at: http://www.w3.org/TR/media-frags/
-// Only the temporaral URI portion of the spec is implemented.
-// To use:
-// a) Construct an instance with the URI containing the fragment
-// b) Check for the validity of the values you are interested in
-// using e.g. HasStartTime().
-// c) If the values are valid, obtain them using e.g. GetStartTime().
-
-namespace mozilla {
-namespace net {
-
-enum ClipUnit {
- eClipUnit_Pixel,
- eClipUnit_Percent,
-};
-
-class nsMediaFragmentURIParser {
- public:
- // Create a parser with the provided URI.
- explicit nsMediaFragmentURIParser(nsIURI* aURI);
-
- // Create a parser with the provided URI reference portion.
- explicit nsMediaFragmentURIParser(nsCString& aRef);
-
- // True if a valid temporal media fragment indicated a start time.
- bool HasStartTime() const { return mStart.isSome(); }
-
- // If a valid temporal media fragment indicated a start time, returns
- // it in units of seconds. If not, defaults to 0.
- double GetStartTime() const { return *mStart; }
-
- // True if a valid temporal media fragment indicated an end time.
- bool HasEndTime() const { return mEnd.isSome(); }
-
- // If a valid temporal media fragment indicated an end time, returns
- // it in units of seconds. If not, defaults to -1.
- double GetEndTime() const { return *mEnd; }
-
- // True if a valid spatial media fragment indicated a clipping region.
- bool HasClip() const { return mClip.isSome(); }
-
- // If a valid spatial media fragment indicated a clipping region,
- // returns the region. If not, returns an empty region. The unit
- // used depends on the value returned by GetClipUnit().
- nsIntRect GetClip() const { return *mClip; }
-
- // If a valid spatial media fragment indicated a clipping region,
- // returns the unit used.
- ClipUnit GetClipUnit() const { return mClipUnit; }
-
- private:
- // Parse the URI ref provided, looking for media fragments. This is
- // the top-level parser the invokes the others below.
- void Parse(nsACString& aRef);
-
- // The following methods parse the fragment as per the media
- // fragments specification. 'aString' contains the remaining
- // fragment data to be parsed. The method returns true
- // if the parse was successful and leaves the remaining unparsed
- // data in 'aString'. If the parse fails then false is returned
- // and 'aString' is left as it was when called.
- bool ParseNPT(nsDependentSubstring aString);
- bool ParseNPTTime(nsDependentSubstring& aString, double& aTime);
- bool ParseNPTSec(nsDependentSubstring& aString, double& aSec);
- bool ParseNPTFraction(nsDependentSubstring& aString, double& aFraction);
- bool ParseNPTMMSS(nsDependentSubstring& aString, double& aTime);
- bool ParseNPTHHMMSS(nsDependentSubstring& aString, double& aTime);
- bool ParseNPTHH(nsDependentSubstring& aString, uint32_t& aHour);
- bool ParseNPTMM(nsDependentSubstring& aString, uint32_t& aMinute);
- bool ParseNPTSS(nsDependentSubstring& aString, uint32_t& aSecond);
- bool ParseXYWH(nsDependentSubstring aString);
- bool ParseMozResolution(nsDependentSubstring aString);
-
- // Media fragment information.
- Maybe<double> mStart;
- Maybe<double> mEnd;
- Maybe<nsIntRect> mClip;
- ClipUnit mClipUnit;
-};
-
-} // namespace net
-} // namespace mozilla
-
-#endif