Bug 908413 - Make dom::MimeType a template to make it usable with nsCString r=hsivonen
authorValentin Gosu <valentin.gosu@gmail.com>
Fri, 07 Sep 2018 05:41:29 +0000
changeset 435197 95bd6ba098c0c5f3499d2c0f4bc71dde9d5d55ee
parent 435196 4cf474bee0bebe365177b36e77857e0d8ceddd23
child 435198 cbf8c92608e3a8d83bb475939e274aa3ce0d674f
push id107591
push userdluca@mozilla.com
push dateFri, 07 Sep 2018 16:40:10 +0000
treeherdermozilla-inbound@293c4672dd15 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs908413
milestone64.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 908413 - Make dom::MimeType a template to make it usable with nsCString r=hsivonen Differential Revision: https://phabricator.services.mozilla.com/D5094
dom/base/MimeType.cpp
dom/base/MimeType.h
dom/base/test/gtest/TestMimeType.cpp
mfbt/TextUtils.h
--- a/dom/base/MimeType.cpp
+++ b/dom/base/MimeType.cpp
@@ -1,66 +1,69 @@
 #include "MimeType.h"
 #include "nsUnicharUtils.h"
 
 namespace {
-  static inline bool IsHTTPTokenPoint(const char16_t c) {
+  template<typename char_type>
+  static inline bool IsHTTPTokenPoint(const char_type c) {
     return c == '!' || c == '#' || c == '$' || c == '%' || c == '&' ||
            c == '\'' || c == '*' || c == '+' || c == '-' || c == '.' ||
            c == '^' || c == '_' || c == '`' || c == '|' || c == '~' ||
            mozilla::IsAsciiAlphanumeric(c);
   }
 
-  static inline bool IsHTTPQuotedStringTokenPoint(const char16_t c) {
-    return c == 0x9 || (c >= ' ' && c <= '~') || (c >= 0x80 && c <= 0xFF);
+  template<typename char_type>
+  static inline bool IsHTTPQuotedStringTokenPoint(const char_type c) {
+    return c == 0x9 || (c >= ' ' && c <= '~') || mozilla::IsNonAsciiLatin1(c);
   }
 }
 
-/* static */ mozilla::UniquePtr<MimeType>
-MimeType::Parse(const nsAString& aMimeType)
+template<typename char_type>
+/* static */ mozilla::UniquePtr<TMimeType<char_type>>
+TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType)
 {
   // See https://mimesniff.spec.whatwg.org/#parsing-a-mime-type
 
   // Steps 1-2
-  const char16_t* pos = aMimeType.BeginReading();
-  const char16_t* end = aMimeType.EndReading();
+  const char_type* pos = aMimeType.BeginReading();
+  const char_type* end = aMimeType.EndReading();
   while (pos < end && mozilla::IsAsciiWhitespace(*pos)) {
     ++pos;
   }
   if (pos == end) {
     return nullptr;
   }
   while (end > pos && mozilla::IsAsciiWhitespace(*(end - 1))) {
     --end;
   }
 
   // Steps 3-4
-  const char16_t* typeStart = pos;
+  const char_type* typeStart = pos;
   while (pos < end && *pos != '/') {
     if (!IsHTTPTokenPoint(*pos)) {
       return nullptr;
     }
     ++pos;
   }
-  const char16_t* typeEnd = pos;
+  const char_type* typeEnd = pos;
   if (typeStart == typeEnd) {
     return nullptr;
   }
 
   // Step 5
   if (pos == end) {
     return nullptr;
   }
 
   // Step 6
   ++pos;
 
   // Step 7-9
-  const char16_t* subtypeStart = pos;
-  const char16_t* subtypeEnd = nullptr;
+  const char_type* subtypeStart = pos;
+  const char_type* subtypeEnd = nullptr;
   while (pos < end && *pos != ';') {
     if (!IsHTTPTokenPoint(*pos)) {
       // If we hit a whitespace, check that the rest of
       // the subtype is whitespace, otherwise fail.
       if (mozilla::IsAsciiWhitespace(*pos)) {
         subtypeEnd = pos;
         ++pos;
         while (pos < end && *pos != ';') {
@@ -79,38 +82,38 @@ MimeType::Parse(const nsAString& aMimeTy
   if (subtypeEnd == nullptr) {
     subtypeEnd = pos;
   }
   if (subtypeStart == subtypeEnd) {
     return nullptr;
   }
 
   // Step 10
-  nsString type;
-  nsString subtype;
-  for (const char16_t* c = typeStart; c < typeEnd; ++c) {
+  nsTString<char_type> type;
+  nsTString<char_type> subtype;
+  for (const char_type* c = typeStart; c < typeEnd; ++c) {
     type.Append(ToLowerCaseASCII(*c));
   }
-  for (const char16_t* c = subtypeStart; c < subtypeEnd; ++c) {
+  for (const char_type* c = subtypeStart; c < subtypeEnd; ++c) {
     subtype.Append(ToLowerCaseASCII(*c));
   }
-  mozilla::UniquePtr<MimeType> mimeType(mozilla::MakeUnique<MimeType>(type, subtype));
+  mozilla::UniquePtr<TMimeType<char_type>> mimeType(mozilla::MakeUnique<TMimeType<char_type>>(type, subtype));
 
   // Step 11
   while (pos < end) {
     // Step 11.1
     ++pos;
 
     // Step 11.2
     while (pos < end && mozilla::IsAsciiWhitespace(*pos)) {
       ++pos;
     }
 
     // Steps 11.3 and 11.4
-    nsString paramName;
+    nsTString<char_type> paramName;
     bool paramNameHadInvalidChars = false;
     while (pos < end && *pos != ';' && *pos != '=') {
       if (!IsHTTPTokenPoint(*pos)) {
         paramNameHadInvalidChars = true;
       }
       paramName.Append(ToLowerCaseASCII(*pos));
       ++pos;
     }
@@ -181,37 +184,37 @@ MimeType::Parse(const nsAString& aMimeTy
 
         // Step 11.7.1.3
         while (pos < end && *pos != ';') {
           ++pos;
         }
 
       } else {
 
-        const char16_t* paramValueStart = pos;
+        const char_type* paramValueStart = pos;
 
         // Step 11.7.2.1
         while (pos < end && *pos != ';') {
           if (!IsHTTPQuotedStringTokenPoint(*pos)) {
             paramValueHadInvalidChars = true;
           }
           if (!IsHTTPTokenPoint(*pos)) {
             paramValue.mRequiresQuoting = true;
           }
           ++pos;
         }
 
         // Step 11.7.2.2
-        const char16_t* paramValueEnd = pos - 1;
+        const char_type* paramValueEnd = pos - 1;
         while (paramValueEnd >= paramValueStart &&
                mozilla::IsAsciiWhitespace(*paramValueEnd)) {
           --paramValueEnd;
         }
 
-        for (const char16_t* c = paramValueStart; c <= paramValueEnd; ++c) {
+        for (const char_type* c = paramValueStart; c <= paramValueEnd; ++c) {
           paramValue.Append(*c);
         }
       }
 
       // Step 11.8
       if (!paramName.IsEmpty() && !paramValue.IsEmpty() &&
           !paramNameHadInvalidChars && !paramValueHadInvalidChars &&
           !mimeType->mParameters.Get(paramName, &paramValue)) {
@@ -219,38 +222,44 @@ MimeType::Parse(const nsAString& aMimeTy
         mimeType->mParameterNames.AppendElement(paramName);
       }
     }
   }
 
   return mimeType;
 }
 
+template<typename char_type>
 void
-MimeType::Serialize(nsAString& aOutput) const
+TMimeType<char_type>::Serialize(nsTSubstring<char_type>& aOutput) const
 {
   aOutput.Assign(mType);
   aOutput.AppendLiteral("/");
   aOutput.Append(mSubtype);
   for (uint32_t i = 0; i < mParameterNames.Length(); i++) {
     auto name = mParameterNames[i];
     ParameterValue value;
     mParameters.Get(name, &value);
     aOutput.AppendLiteral(";");
     aOutput.Append(name);
     aOutput.AppendLiteral("=");
     if (value.mRequiresQuoting) {
       aOutput.AppendLiteral("\"");
-      const char16_t* vcur = value.BeginReading();
-      const char16_t* vend = value.EndReading();
+      const char_type* vcur = value.BeginReading();
+      const char_type* vend = value.EndReading();
       while (vcur < vend) {
         if (*vcur == '"' || *vcur == '\\') {
           aOutput.AppendLiteral("\\");
         }
         aOutput.Append(*vcur);
         vcur++;
       }
       aOutput.AppendLiteral("\"");
     } else {
       aOutput.Append(value);
     }
   }
 }
+
+template mozilla::UniquePtr<TMimeType<char16_t>> TMimeType<char16_t>::Parse(const nsTSubstring<char16_t>& aMimeType);
+template mozilla::UniquePtr<TMimeType<char>> TMimeType<char>::Parse(const nsTSubstring<char>& aMimeType);
+template void TMimeType<char16_t>::Serialize(nsTSubstring<char16_t>& aOutput) const;
+template void TMimeType<char>::Serialize(nsTSubstring<char>& aOutput) const;
--- a/dom/base/MimeType.h
+++ b/dom/base/MimeType.h
@@ -7,36 +7,46 @@
 #ifndef mozilla_dom_MimeType_h
 #define mozilla_dom_MimeType_h
 
 #include "mozilla/TextUtils.h"
 #include "mozilla/UniquePtr.h"
 #include "nsDataHashtable.h"
 #include "nsTArray.h"
 
-class MimeType final
+template<typename char_type> struct HashKeyType;
+template<> struct HashKeyType<char16_t> { typedef nsStringHashKey HashType; };
+template<> struct HashKeyType<char> { typedef nsCStringHashKey HashType; };
+
+
+template <typename char_type>
+class TMimeType final
 {
 private:
-  class ParameterValue : public nsString
+  class ParameterValue : public nsTString<char_type>
   {
   public:
     bool mRequiresQuoting;
 
     ParameterValue()
       : mRequiresQuoting(false)
     {}
   };
 
-  nsString mType;
-  nsString mSubtype;
-  nsDataHashtable<nsStringHashKey, ParameterValue> mParameters;
-  nsTArray<nsString> mParameterNames;
+  nsTString<char_type> mType;
+  nsTString<char_type> mSubtype;
+  nsDataHashtable<typename HashKeyType<char_type>::HashType, ParameterValue> mParameters;
+  nsTArray<nsTString<char_type>> mParameterNames;
 
 public:
-  MimeType(const nsAString& aType, const nsAString& aSubtype)
+  TMimeType(const nsTSubstring<char_type>& aType, const nsTSubstring<char_type>& aSubtype)
     : mType(aType), mSubtype(aSubtype)
   {}
 
-  static mozilla::UniquePtr<MimeType> Parse(const nsAString& aStr);
-  void Serialize(nsAString& aStr) const;
+  static mozilla::UniquePtr<TMimeType<char_type>> Parse(const nsTSubstring<char_type>& aStr);
+
+  void Serialize(nsTSubstring<char_type>& aStr) const;
 };
 
+using MimeType = TMimeType<char16_t>;
+using CMimeType = TMimeType<char>;
+
 #endif // mozilla_dom_MimeType_h
--- a/dom/base/test/gtest/TestMimeType.cpp
+++ b/dom/base/test/gtest/TestMimeType.cpp
@@ -207,16 +207,27 @@ TEST(MimeType, DuplicateParameter2)
   UniquePtr<MimeType> parsed = MimeType::Parse(in);
   ASSERT_TRUE(parsed) << "Parsing succeeded";
   nsString out;
   parsed->Serialize(out);
   ASSERT_TRUE(out.Equals(NS_LITERAL_STRING("text/html;charset=\"()\""))) <<
     "Duplicate parameter #2";
 }
 
+TEST(MimeType, CString)
+{
+  const auto in = NS_LITERAL_CSTRING("text/html;charset=();charset=GBK");
+  UniquePtr<CMimeType> parsed = CMimeType::Parse(in);
+  ASSERT_TRUE(parsed) << "Parsing succeeded";
+  nsCString out;
+  parsed->Serialize(out);
+  ASSERT_TRUE(out.Equals(NS_LITERAL_CSTRING("text/html;charset=\"()\""))) <<
+    "Duplicate parameter #2";
+}
+
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4819)
 #endif
 TEST(MimeType, NonAlphanumericParametersAreQuoted)
 {
   const auto in = NS_LITERAL_STRING("text/html;test=\x00FF\\;charset=gbk");
   UniquePtr<MimeType> parsed = MimeType::Parse(in);
--- a/mfbt/TextUtils.h
+++ b/mfbt/TextUtils.h
@@ -42,16 +42,25 @@ template<typename Char>
 constexpr bool
 IsAscii(Char aChar)
 {
   using UnsignedChar = typename detail::MakeUnsignedChar<Char>::Type;
   auto uc = static_cast<UnsignedChar>(aChar);
   return uc < 0x80;
 }
 
+template<typename Char>
+constexpr bool
+IsNonAsciiLatin1(Char aChar)
+{
+  using UnsignedChar = typename detail::MakeUnsignedChar<Char>::Type;
+  auto uc = static_cast<UnsignedChar>(aChar);
+  return uc >= 0x80 && uc <= 0xFF;
+}
+
 /**
  * Returns true iff |aChar| matches Ascii Whitespace.
  *
  * This function is intended to match the Infra standard
  * (https://infra.spec.whatwg.org/#ascii-whitespace)
  */
 template<typename Char>
 constexpr bool