Bug 1124031 part 3 - Parse min CDM version from EME keySystem string. r=bz
authorChris Pearce <cpearce@mozilla.com>
Fri, 20 Feb 2015 14:38:01 +1300
changeset 229955 b37b1cc5163fb89cf3f346f51fae6b09f604a67e
parent 229954 f0e5c16136ca2426815f23b3592e05a8fcc59c30
child 229956 138f7daa8b624c2375b855407125ab39f214c40b
push id55851
push usercpearce@mozilla.com
push dateFri, 20 Feb 2015 01:38:33 +0000
treeherdermozilla-inbound@138f7daa8b62 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1124031
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1124031 part 3 - Parse min CDM version from EME keySystem string. r=bz
dom/media/eme/EMEUtils.cpp
dom/media/eme/EMEUtils.h
dom/media/gtest/TestEME.cpp
dom/media/gtest/moz.build
--- a/dom/media/eme/EMEUtils.cpp
+++ b/dom/media/eme/EMEUtils.cpp
@@ -23,9 +23,94 @@ PRLogModuleInfo* GetEMEVerboseLog() {
   if (!log) {
     log = PR_NewLogModule("EMEV");
   }
   return log;
 }
 
 #endif
 
+static bool
+ContainsOnlyDigits(const nsAString& aString)
+{
+  nsAString::const_iterator iter, end;
+  aString.BeginReading(iter);
+  aString.EndReading(end);
+  while (iter != end) {
+    char16_t ch = *iter;
+    if (ch < '0' || ch > '9') {
+      return false;
+    }
+    iter++;
+  }
+  return true;
+}
+
+static bool
+ParseKeySystem(const nsAString& aExpectedKeySystem,
+               const nsAString& aInputKeySystem,
+               int32_t& aOutCDMVersion)
+{
+  if (!StringBeginsWith(aInputKeySystem, aExpectedKeySystem)) {
+    return false;
+  }
+
+  if (aInputKeySystem.Length() > aExpectedKeySystem.Length() + 8) {
+    // Allow up to 8 bytes for the ".version" field. 8 bytes should
+    // be enough for any versioning scheme...
+    NS_WARNING("Input KeySystem including was suspiciously long");
+    return false;
+  }
+
+  const char16_t* versionStart = aInputKeySystem.BeginReading() + aExpectedKeySystem.Length();
+  const char16_t* end = aInputKeySystem.EndReading();
+  if (versionStart == end) {
+    // No version supplied with keysystem.
+    aOutCDMVersion = NO_CDM_VERSION;
+    return true;
+  }
+  if (*versionStart != '.') {
+    // version not in correct format.
+    NS_WARNING("EME keySystem version string not prefixed by '.'");
+    return false;
+  }
+  versionStart++;
+  const nsAutoString versionStr(Substring(versionStart, end));
+  if (!ContainsOnlyDigits(versionStr)) {
+    NS_WARNING("Non-digit character in EME keySystem string's version suffix");
+    return false;
+  }
+  nsresult rv;
+  int32_t version = versionStr.ToInteger(&rv);
+  if (NS_FAILED(rv) || version < 0) {
+    NS_WARNING("Invalid version in EME keySystem string");
+    return false;
+  }
+  aOutCDMVersion = version;
+
+  return true;
+}
+
+static const char16_t* sKeySystems[] = {
+  MOZ_UTF16("org.w3.clearkey"),
+  MOZ_UTF16("com.adobe.access"),
+  MOZ_UTF16("com.adobe.primetime"),
+};
+
+bool
+ParseKeySystem(const nsAString& aInputKeySystem,
+               nsAString& aOutKeySystem,
+               int32_t& aOutCDMVersion)
+{
+  for (const char16_t* keySystem : sKeySystems) {
+    int32_t minCDMVersion = NO_CDM_VERSION;
+    if (ParseKeySystem(nsDependentString(keySystem),
+                       aInputKeySystem,
+                       minCDMVersion)) {
+      aOutKeySystem = keySystem;
+      aOutCDMVersion = minCDMVersion;
+      return true;
+    }
+  }
+  return false;
+}
+
 } // namespace mozilla
--- a/dom/media/eme/EMEUtils.h
+++ b/dom/media/eme/EMEUtils.h
@@ -3,16 +3,17 @@
 /* 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/. */
 
 #ifndef EME_LOG_H_
 #define EME_LOG_H_
 
 #include "prlog.h"
+#include "nsString.h"
 
 namespace mozilla {
 
 #ifdef PR_LOGGING
 
   #ifndef EME_LOG
     PRLogModuleInfo* GetEMELog();
     #define EME_LOG(...) PR_LOG(GetEMELog(), PR_LOG_DEBUG, (__VA_ARGS__))
@@ -38,11 +39,31 @@ namespace mozilla {
   #endif
 
   #ifndef EME_VERBOSE_LOG
     #define EME_VERBOSE_LOG(...)
   #endif
 
 #endif // PR_LOGGING
 
+#define NO_CDM_VERSION -1
+
+// Checks a keySystem string against a whitelist, and determines whether
+// the keySystem is in the whitelist, and extracts the requested minimum
+// CDM version.
+//
+// Format of EME keysystems:
+// com.domain.keysystem[.minVersionAsInt]
+// i.e. org.w3.clearkey, com.adobe.primetime.7
+//
+// Returns true if aKeySystem contains a valid keySystem which we support,
+// false otherwise.
+//
+// On success, aOutKeySystem contains the keySystem string stripped of the
+// min version number, and aOutMinCDMVersion contains the min version number
+// if present. If it was not present, aOutMinCDMVersion is NO_CDM_VERSION.
+bool ParseKeySystem(const nsAString& aKeySystem,
+                    nsAString& aOutKeySystem,
+                    int32_t& aOutMinCDMVersion);
+
 } // namespace mozilla
 
 #endif // EME_LOG_H_
new file mode 100644
--- /dev/null
+++ b/dom/media/gtest/TestEME.cpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "gtest/gtest.h"
+#include "mozilla/EMEUtils.h"
+
+using namespace std;
+using namespace mozilla;
+
+struct ParseKeySystemTestCase {
+  const char16_t* mInputKeySystemString;
+  int32_t mOutCDMVersion;
+  bool mShouldPass;
+};
+
+const ParseKeySystemTestCase ParseKeySystemTests[] = {
+  {
+    MOZ_UTF16("org.w3.clearkey"),
+    NO_CDM_VERSION,
+    true,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.123"),
+    123,
+    true,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.-1"),
+    NO_CDM_VERSION,
+    false,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.NaN"),
+    NO_CDM_VERSION,
+    false,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.0"),
+    0,
+    true,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.123567890123567890123567890123567890123567890"),
+    NO_CDM_VERSION,
+    false,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.0.1"),
+    NO_CDM_VERSION,
+    false,
+  }
+};
+
+TEST(EME, EMEParseKeySystem) {
+  const nsAutoString clearkey(MOZ_UTF16("org.w3.clearkey"));
+  for (const ParseKeySystemTestCase& test : ParseKeySystemTests) {
+    nsAutoString keySystem;
+    int32_t version;
+    bool rv = ParseKeySystem(nsDependentString(test.mInputKeySystemString),
+                             keySystem,
+                             version);
+    EXPECT_EQ(rv, test.mShouldPass) << "parse should succeed if expected to";
+    if (!test.mShouldPass) {
+      continue;
+    }
+    EXPECT_TRUE(keySystem.Equals(clearkey)) << NS_ConvertUTF16toUTF8(keySystem).get(); //"should extract expected keysystem" << ;
+    EXPECT_EQ(test.mOutCDMVersion, version) << "should extract expected version";
+  }
+}
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -10,16 +10,21 @@ SOURCES += [
     'TestGMPCrossOrigin.cpp',
     'TestMP4Demuxer.cpp',
     'TestMP4Reader.cpp',
     'TestTrackEncoder.cpp',
     'TestVideoSegment.cpp',
     'TestWebMBuffered.cpp',
 ]
 
+if CONFIG['MOZ_EME']:
+    SOURCES += [
+        'TestEME.cpp',
+    ]
+
 if CONFIG['MOZ_WEBM_ENCODER']:
     SOURCES += [
         'TestVideoTrackEncoder.cpp',
         'TestVorbisTrackEncoder.cpp',
         'TestWebMWriter.cpp',
     ]
 
 TEST_HARNESS_FILES.gtest += [
@@ -29,16 +34,17 @@ TEST_HARNESS_FILES.gtest += [
     'mediasource_test.mp4',
     'test.webm',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/dom/media',
+    '/dom/media/eme',
     '/dom/media/encoder',
     '/dom/media/fmp4',
     '/dom/media/gmp',
     '/security/certverifier',
     '/security/pkix/include',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'