Bug 1330326 - Add Split() function on String classes. r?froydnj draft
authorGian-Carlo Pascutto <gcp@mozilla.com>
Mon, 23 Jan 2017 20:08:06 +0100
changeset 465073 0a9932b1f6a8f1ba2b2dc962b2d3e8d65cf9fee9
parent 465072 a54ac7c147e56fd5562df930e10b348c98bf5719
child 543092 125991d0c162210b96b618d4da3289d84296071e
push id42537
push usergpascutto@mozilla.com
push dateMon, 23 Jan 2017 19:11:25 +0000
reviewersfroydnj
bugs1330326
milestone53.0a1
Bug 1330326 - Add Split() function on String classes. r?froydnj MozReview-Commit-ID: 8GpqWsfGnWp
dom/ipc/ContentChild.cpp
security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
xpcom/string/nsTSubstring.cpp
xpcom/string/nsTSubstring.h
xpcom/string/string-template-def-char.h
xpcom/string/string-template-def-unichar.h
xpcom/string/string-template-undef.h
xpcom/tests/gtest/TestStrings.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -219,39 +219,16 @@ using namespace mozilla::psm;
 using namespace mozilla::widget;
 #if defined(MOZ_WIDGET_GONK)
 using namespace mozilla::system;
 #endif
 using namespace mozilla::widget;
 
 namespace mozilla {
 
-static nsTArray<nsCString> StringSplit(const nsACString& str)
-{
-  nsTArray<nsCString> result;
-
-  nsACString::const_iterator begin, iter, end;
-  str.BeginReading(begin);
-  str.EndReading(end);
-  while (begin != end) {
-    iter = begin;
-    FindCharInReadable(',', iter, end);
-    nsDependentCSubstring path = Substring(begin, iter);
-    if (!path.IsEmpty()) {
-      result.AppendElement(Substring(begin, iter));
-    }
-    begin = iter;
-    if (begin != end) {
-      begin++;
-    }
-  }
-
-  return result;
-}
-
 namespace dom {
 
 class MemoryReportRequestChild : public PMemoryReportRequestChild,
                                  public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
 
@@ -1524,20 +1501,19 @@ ContentChild::RecvSetProcessSandbox(cons
       // didn't intend it.
       MOZ_RELEASE_ASSERT(brokerFd >= 0);
     }
     // Allow user overrides of seccomp-bpf syscall filtering
     std::vector<int> syscallWhitelist;
     nsAdoptingCString extraSyscalls =
       Preferences::GetCString("security.sandbox.content.syscall_whitelist");
     if (extraSyscalls) {
-      auto callNumbers = StringSplit(extraSyscalls);
-      for (const nsCString& callNrString : callNumbers) {
+      for (const nsCSubstring& callNrString : extraSyscalls.Split(',')) {
         nsresult rv;
-        int callNr = callNrString.ToInteger(&rv);
+        int callNr = PromiseFlatCString(callNrString).ToInteger(&rv);
         if (NS_SUCCEEDED(rv)) {
           syscallWhitelist.push_back(callNr);
         }
       }
     }
     sandboxEnabled = SetContentProcessSandbox(brokerFd, syscallWhitelist);
   }
 #elif defined(XP_WIN)
--- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
+++ b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
@@ -49,39 +49,16 @@ static const int wronly = SandboxBroker:
 static const int rdwr = rdonly | wronly;
 static const int rdwrcr = rdwr | SandboxBroker::MAY_CREATE;
 #if defined(MOZ_WIDGET_GONK)
 static const int wrlog = wronly | SandboxBroker::MAY_CREATE;
 #endif
 }
 #endif
 
-static nsTArray<nsCString> StringSplit(const nsACString& str)
-{
-  nsTArray<nsCString> result;
-
-  nsACString::const_iterator begin, iter, end;
-  str.BeginReading(begin);
-  str.EndReading(end);
-  while (begin != end) {
-    iter = begin;
-    FindCharInReadable(',', iter, end);
-    nsDependentCSubstring path = Substring(begin, iter);
-    if (!path.IsEmpty()) {
-      result.AppendElement(Substring(begin, iter));
-    }
-    begin = iter;
-    if (begin != end) {
-      begin++;
-    }
-  }
-
-  return result;
-}
-
 SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
 {
   // Policy entries that are the same in every process go here, and
   // are cached over the lifetime of the factory.
 #if defined(MOZ_CONTENT_SANDBOX) && defined(MOZ_WIDGET_GONK)
   SandboxBroker::Policy* policy = new SandboxBroker::Policy;
 
   // Devices that need write access:
@@ -215,21 +192,21 @@ SandboxBrokerPolicyFactory::GetContentPo
   UniquePtr<SandboxBroker::Policy>
     policy(new SandboxBroker::Policy(*mCommonContentPolicy));
 
   // Now read any extra paths, this requires accessing user preferences
   // so we can only do it now. Our constructor is initialized before
   // user preferences are read in.
   nsAdoptingCString extraPathString =
     Preferences::GetCString("security.sandbox.content.write_path_whitelist");
-
   if (extraPathString) {
-    auto extraPaths = StringSplit(extraPathString);
-    for (const nsCString& path : extraPaths) {
-      policy->AddDynamic(rdwr, path.get());
+    for (const nsCSubstring& path : extraPathString.Split(',')) {
+      nsCString stripPath(path);
+      stripPath.StripWhitespace();
+      policy->AddDynamic(rdwr, stripPath.get());
     }
   }
 
   // Return the common policy.
   return policy;
 #endif
 }
 
--- a/xpcom/string/nsTSubstring.cpp
+++ b/xpcom/string/nsTSubstring.cpp
@@ -1078,8 +1078,17 @@ nsTSubstring_CharT::SizeOfIncludingThisI
 
 size_t
 nsTSubstring_CharT::SizeOfIncludingThisEvenIfShared(
     mozilla::MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThisEvenIfShared(aMallocSizeOf);
 }
 
+nsTSubstringSplitter_CharT nsTSubstring_CharT::Split(const nsTSubstring_CharT::char_type aChar)
+{
+  return nsTSubstringSplitter_CharT(this, aChar);
+}
+
+const nsTSubstring_CharT& nsTSubstringSplitter_CharT::nsTSubstringSplit_Iter::operator* () const
+{
+   return mObj.Get(mPos);
+}
--- a/xpcom/string/nsTSubstring.h
+++ b/xpcom/string/nsTSubstring.h
@@ -1,16 +1,17 @@
 /* -*- 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/. */
 // IWYU pragma: private, include "nsString.h"
 
 #include "mozilla/Casting.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/MemoryReporting.h"
 
 #ifndef MOZILLA_INTERNAL_API
 #error Cannot use internal string classes without MOZILLA_INTERNAL_API defined. Use the frozen header nsStringAPI.h instead.
 #endif
 
 /**
  * The base for string comparators
@@ -41,16 +42,18 @@ public:
   nsTDefaultStringComparator_CharT()
   {
   }
 
   virtual int operator()(const char_type*, const char_type*,
                          uint32_t, uint32_t) const override;
 };
 
+class nsTSubstringSplitter_CharT;
+
 /**
  * nsTSubstring is the most abstract class in the string hierarchy. It
  * represents a single contiguous array of characters, which may or may not
  * be null-terminated. This type is not instantiated directly.  A sub-class
  * is instantiated instead.  For example, see nsTString.
  *
  * NAMES:
  *   nsAString for wide characters
@@ -704,16 +707,17 @@ public:
     ReplaceLiteral(aPos, 0, aStr, N - 1);
   }
 
   void Cut(index_type aCutStart, size_type aCutLength)
   {
     Replace(aCutStart, aCutLength, char_traits::sEmptyBuffer, 0);
   }
 
+  nsTSubstringSplitter_CharT Split(const char_type aChar);
 
   /**
    * buffer sizing
    */
 
   /**
    * Attempts to set the capacity to the given size in number of
    * characters, without affecting the length of the string.
@@ -902,18 +906,17 @@ public:
   {
     ::NS_ABORT_OOM(aLength * sizeof(char_type));
   }
 
 protected:
 
   friend class nsTObsoleteAStringThunk_CharT;
   friend class nsTSubstringTuple_CharT;
-
-  // XXX GCC 3.4 needs this :-(
+  friend class nsTSubstringSplitter_CharT;
   friend class nsTPromiseFlatString_CharT;
 
   char_type*  mData;
   size_type   mLength;
   uint32_t    mFlags;
 
   // default initialization
   nsTSubstring_CharT()
@@ -1163,8 +1166,94 @@ operator>=(const nsTSubstring_CharT::bas
 }
 
 inline bool
 operator>(const nsTSubstring_CharT::base_string_type& aLhs,
           const nsTSubstring_CharT::base_string_type& aRhs)
 {
   return Compare(aLhs, aRhs) > 0;
 }
+
+class nsTSubstringSplitter_CharT
+{
+  class nsTSubstringSplit_Iter
+  {
+  public:
+    nsTSubstringSplit_Iter(const nsTSubstringSplitter_CharT& aObj,
+                           nsTSubstring_CharT::size_type aPos)
+      : mObj(aObj)
+      , mPos(aPos)
+    {
+    }
+
+    bool operator!=(const nsTSubstringSplit_Iter& other) const
+    {
+      return mPos != other.mPos;
+    }
+
+    const nsTSubstring_CharT& operator*() const;
+
+    const nsTSubstringSplit_Iter& operator++()
+    {
+      ++mPos;
+      return *this;
+    }
+
+  private:
+    const nsTSubstringSplitter_CharT& mObj;
+    nsTSubstring_CharT::size_type mPos;
+  };
+
+private:
+  const nsTSubstring_CharT* mStr;
+  mozilla::UniquePtr<nsTSubstring_CharT[]> mArray;
+  nsTSubstring_CharT::size_type mArraySize;
+  const nsTSubstring_CharT::char_type mDelim;
+
+public:
+  nsTSubstringSplitter_CharT(const nsTSubstring_CharT* aStr,
+                             nsTSubstring_CharT::char_type aDelim)
+    : mStr(aStr)
+    , mArray(nullptr)
+    , mDelim(aDelim)
+  {
+    if (mStr->IsEmpty()) {
+      mArraySize = 0;
+      return;
+    }
+
+    nsTSubstring_CharT::size_type delimCount = mStr->CountChar(aDelim);
+    mArraySize = delimCount + 1;
+    mArray.reset(new nsTSubstring_CharT[mArraySize]);
+
+    size_t seenParts = 0;
+    // signed int due to return from FindChar
+    int32_t start = 0;
+    do {
+      int32_t offset = mStr->FindChar(aDelim, start);
+      if (offset != -1) {
+        nsTSubstring_CharT::size_type length = offset - start;
+        mArray[seenParts++].Assign(mStr->Data() + start, length);
+        start = offset + 1;
+      } else {
+        // Get the remainder
+        mArray[seenParts++].Assign(mStr->Data() + start, mStr->Length() - start);
+        break;
+      }
+    } while (start < (int32_t)mStr->Length());
+  }
+
+  nsTSubstringSplit_Iter begin() const
+  {
+    return nsTSubstringSplit_Iter(*this, 0);
+  }
+
+  nsTSubstringSplit_Iter end() const
+  {
+    return nsTSubstringSplit_Iter(*this, mArraySize);
+  }
+
+  const nsTSubstring_CharT& Get(const nsTSubstring_CharT::size_type index) const
+  {
+    MOZ_ASSERT(index < mArraySize);
+    return mArray[index];
+  }
+};
--- a/xpcom/string/string-template-def-char.h
+++ b/xpcom/string/string-template-def-char.h
@@ -18,8 +18,9 @@
 #define nsTDependentString_CharT            nsDependentCString
 #define nsTDependentSubstring_CharT         nsDependentCSubstring
 #define nsTLiteralString_CharT              nsLiteralCString
 #define nsTXPIDLString_CharT                nsXPIDLCString
 #define nsTGetterCopies_CharT               nsCGetterCopies
 #define nsTAdoptingString_CharT             nsAdoptingCString
 #define nsTPromiseFlatString_CharT          nsPromiseFlatCString
 #define TPromiseFlatString_CharT            PromiseFlatCString
+#define nsTSubstringSplitter_CharT          nsCSubstringSplitter
--- a/xpcom/string/string-template-def-unichar.h
+++ b/xpcom/string/string-template-def-unichar.h
@@ -18,8 +18,9 @@
 #define nsTDependentString_CharT            nsDependentString
 #define nsTDependentSubstring_CharT         nsDependentSubstring
 #define nsTLiteralString_CharT              nsLiteralString
 #define nsTXPIDLString_CharT                nsXPIDLString
 #define nsTGetterCopies_CharT               nsGetterCopies
 #define nsTAdoptingString_CharT             nsAdoptingString
 #define nsTPromiseFlatString_CharT          nsPromiseFlatString
 #define TPromiseFlatString_CharT            PromiseFlatString
+#define nsTSubstringSpliiter_CharT          nsSubstringSplitter
--- a/xpcom/string/string-template-undef.h
+++ b/xpcom/string/string-template-undef.h
@@ -19,8 +19,9 @@
 #undef nsTDependentString_CharT
 #undef nsTDependentSubstring_CharT
 #undef nsTLiteralString_CharT
 #undef nsTXPIDLString_CharT
 #undef nsTGetterCopies_CharT
 #undef nsTAdoptingString_CharT
 #undef nsTPromiseFlatString_CharT
 #undef TPromiseFlatString_CharT
+#undef nsTSubstringSplitter_CharT
--- a/xpcom/tests/gtest/TestStrings.cpp
+++ b/xpcom/tests/gtest/TestStrings.cpp
@@ -973,9 +973,47 @@ TEST(Strings, todouble)
   test_todouble_helper(NS_LITERAL_STRING("123456789.98765432123456"), 123456789.98765432123456, true);
   test_todouble_helper(NS_LITERAL_STRING("0"), 0, true);
   test_todouble_helper(NS_LITERAL_STRING("1.e5"), 100000, true);
   test_todouble_helper(NS_LITERAL_STRING(""), 0, false);
   test_todouble_helper(NS_LITERAL_STRING("42foo"), 42, false);
   test_todouble_helper(NS_LITERAL_STRING("foo"), 0, false);
 }
 
+TEST(Strings, Split)
+{
+   nsCString one("one"),
+             two("one;two"),
+             three("one--three");
+
+  size_t counter = 0;
+  for (const nsCSubstring& token : one.Split(',')) {
+    EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("one")));
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)1);
+
+  counter = 0;
+  for (const nsCSubstring& token : two.Split(';')) {
+    if (counter == 0) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("one")));
+    } else if (counter == 1) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("two")));
+    }
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)2);
+
+  counter = 0;
+  for (const nsCSubstring& token : three.Split('-')) {
+    if (counter == 0) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("one")));
+    } else if (counter == 1) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("")));
+    } else if (counter == 2) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("three")));
+    }
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)3);
+}
+
 } // namespace TestStrings