Bug 1124031 part 3 - Parse min CDM version from EME keySystem string. r=bz a=lmandel
authorChris Pearce <cpearce@mozilla.com>
Fri, 20 Feb 2015 14:38:01 +1300
changeset 250222 16dddf827464
parent 250221 cee66f9d30e7
child 250223 6437b406a0fa
push id4521
push usercpearce@mozilla.com
push date2015-03-04 01:22 +0000
treeherdermozilla-beta@8abdbdecd2d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, lmandel
bugs1124031
milestone37.0
Bug 1124031 part 3 - Parse min CDM version from EME keySystem string. r=bz a=lmandel
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 += [
@@ -30,16 +35,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'