Create initializer-list ctor for strings.

Also use safe arithmetic for two-arg ctor.

Change-Id: I5d541d9b2d5fe5b939f4cc8c22cf034f5cb01176
Reviewed-on: https://pdfium-review.googlesource.com/3955
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/cfx_bytestring.cpp b/core/fxcrt/cfx_bytestring.cpp
index cca8ad6..ab35e5d 100644
--- a/core/fxcrt/cfx_bytestring.cpp
+++ b/core/fxcrt/cfx_bytestring.cpp
@@ -13,6 +13,7 @@
 
 #include "core/fxcrt/cfx_string_pool_template.h"
 #include "core/fxcrt/fx_basic.h"
+#include "core/fxcrt/fx_safe_types.h"
 #include "third_party/base/numerics/safe_math.h"
 #include "third_party/base/stl_util.h"
 
@@ -124,7 +125,10 @@
 
 CFX_ByteString::CFX_ByteString(const CFX_ByteStringC& str1,
                                const CFX_ByteStringC& str2) {
-  int nNewLen = str1.GetLength() + str2.GetLength();
+  FX_SAFE_STRSIZE nSafeLen = str1.GetLength();
+  nSafeLen += str2.GetLength();
+
+  FX_STRSIZE nNewLen = nSafeLen.ValueOrDie();
   if (nNewLen == 0)
     return;
 
@@ -133,6 +137,25 @@
   m_pData->CopyContentsAt(str1.GetLength(), str2.c_str(), str2.GetLength());
 }
 
+CFX_ByteString::CFX_ByteString(
+    const std::initializer_list<CFX_ByteStringC>& list) {
+  FX_SAFE_STRSIZE nSafeLen = 0;
+  for (const auto& item : list)
+    nSafeLen += item.GetLength();
+
+  FX_STRSIZE nNewLen = nSafeLen.ValueOrDie();
+  if (nNewLen == 0)
+    return;
+
+  m_pData.Reset(StringData::Create(nNewLen));
+
+  FX_STRSIZE nOffset = 0;
+  for (const auto& item : list) {
+    m_pData->CopyContentsAt(nOffset, item.c_str(), item.GetLength());
+    nOffset += item.GetLength();
+  }
+}
+
 CFX_ByteString::~CFX_ByteString() {}
 
 const CFX_ByteString& CFX_ByteString::operator=(const char* pStr) {
diff --git a/core/fxcrt/cfx_bytestring.h b/core/fxcrt/cfx_bytestring.h
index 9596fc5..b9ebd8a 100644
--- a/core/fxcrt/cfx_bytestring.h
+++ b/core/fxcrt/cfx_bytestring.h
@@ -8,6 +8,7 @@
 #define CORE_FXCRT_CFX_BYTESTRING_H_
 
 #include <functional>
+#include <utility>
 
 #include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/cfx_string_c_template.h"
@@ -38,6 +39,7 @@
 
   explicit CFX_ByteString(const CFX_ByteStringC& bstrc);
   CFX_ByteString(const CFX_ByteStringC& bstrc1, const CFX_ByteStringC& bstrc2);
+  CFX_ByteString(const std::initializer_list<CFX_ByteStringC>& list);
 
   ~CFX_ByteString();
 
diff --git a/core/fxcrt/cfx_bytestring_unittest.cpp b/core/fxcrt/cfx_bytestring_unittest.cpp
index 4f2691c..3b679a0 100644
--- a/core/fxcrt/cfx_bytestring_unittest.cpp
+++ b/core/fxcrt/cfx_bytestring_unittest.cpp
@@ -1089,3 +1089,10 @@
   const char* cstr = empty_str.c_str();
   EXPECT_EQ(0, FXSYS_strlen(cstr));
 }
+
+TEST(fxcrt, ByteStringInitializerList) {
+  CFX_ByteString many_str({"clams", " and ", "oysters"});
+  EXPECT_EQ("clams and oysters", many_str);
+  many_str = {"fish", " and ", "chips", " and ", "soda"};
+  EXPECT_EQ("fish and chips and soda", many_str);
+}
diff --git a/core/fxcrt/cfx_widestring.cpp b/core/fxcrt/cfx_widestring.cpp
index eb6bc66..c9a89fe 100644
--- a/core/fxcrt/cfx_widestring.cpp
+++ b/core/fxcrt/cfx_widestring.cpp
@@ -14,6 +14,7 @@
 #include "core/fxcrt/cfx_string_pool_template.h"
 #include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_ext.h"
+#include "core/fxcrt/fx_safe_types.h"
 #include "third_party/base/numerics/safe_math.h"
 #include "third_party/base/stl_util.h"
 
@@ -296,7 +297,10 @@
 
 CFX_WideString::CFX_WideString(const CFX_WideStringC& str1,
                                const CFX_WideStringC& str2) {
-  int nNewLen = str1.GetLength() + str2.GetLength();
+  FX_SAFE_STRSIZE nSafeLen = str1.GetLength();
+  nSafeLen += str2.GetLength();
+
+  FX_STRSIZE nNewLen = nSafeLen.ValueOrDie();
   if (nNewLen == 0)
     return;
 
@@ -305,6 +309,25 @@
   m_pData->CopyContentsAt(str1.GetLength(), str2.c_str(), str2.GetLength());
 }
 
+CFX_WideString::CFX_WideString(
+    const std::initializer_list<CFX_WideStringC>& list) {
+  FX_SAFE_STRSIZE nSafeLen = 0;
+  for (const auto& item : list)
+    nSafeLen += item.GetLength();
+
+  FX_STRSIZE nNewLen = nSafeLen.ValueOrDie();
+  if (nNewLen == 0)
+    return;
+
+  m_pData.Reset(StringData::Create(nNewLen));
+
+  FX_STRSIZE nOffset = 0;
+  for (const auto& item : list) {
+    m_pData->CopyContentsAt(nOffset, item.c_str(), item.GetLength());
+    nOffset += item.GetLength();
+  }
+}
+
 CFX_WideString::~CFX_WideString() {}
 
 const CFX_WideString& CFX_WideString::operator=(const wchar_t* pStr) {
diff --git a/core/fxcrt/cfx_widestring.h b/core/fxcrt/cfx_widestring.h
index 397a5dc..52cd65a 100644
--- a/core/fxcrt/cfx_widestring.h
+++ b/core/fxcrt/cfx_widestring.h
@@ -8,6 +8,7 @@
 #define CORE_FXCRT_CFX_WIDESTRING_H_
 
 #include <functional>
+#include <utility>
 
 #include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/cfx_string_c_template.h"
@@ -37,6 +38,7 @@
 
   explicit CFX_WideString(const CFX_WideStringC& str);
   CFX_WideString(const CFX_WideStringC& str1, const CFX_WideStringC& str2);
+  CFX_WideString(const std::initializer_list<CFX_WideStringC>& list);
 
   ~CFX_WideString();
 
diff --git a/core/fxcrt/cfx_widestring_unittest.cpp b/core/fxcrt/cfx_widestring_unittest.cpp
index a0523b1..dd44cb7 100644
--- a/core/fxcrt/cfx_widestring_unittest.cpp
+++ b/core/fxcrt/cfx_widestring_unittest.cpp
@@ -945,3 +945,10 @@
   const wchar_t* cstr = empty_str.c_str();
   EXPECT_EQ(0, FXSYS_wcslen(cstr));
 }
+
+TEST(fxcrt, WidStringInitializerList) {
+  CFX_WideString many_str({L"clams", L" and ", L"oysters"});
+  EXPECT_EQ(L"clams and oysters", many_str);
+  many_str = {L"fish", L" and ", L"chips", L" and ", L"soda"};
+  EXPECT_EQ(L"fish and chips and soda", many_str);
+}