Add << overload for CFX_StringCTemplate classes

BUG=pdfium:790

Change-Id: I4a3623dc0daac6ff8407c09cd00e9f2e4e5dd2d7
Reviewed-on: https://pdfium-review.googlesource.com/7051
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/cfx_bytestring.cpp b/core/fxcrt/cfx_bytestring.cpp
index 967bcce..9d67ed3 100644
--- a/core/fxcrt/cfx_bytestring.cpp
+++ b/core/fxcrt/cfx_bytestring.cpp
@@ -877,3 +877,7 @@
 std::ostream& operator<<(std::ostream& os, const CFX_ByteString& str) {
   return os.write(str.c_str(), str.GetLength());
 }
+
+std::ostream& operator<<(std::ostream& os, const CFX_ByteStringC& str) {
+  return os.write(str.c_str(), str.GetLength());
+}
diff --git a/core/fxcrt/cfx_bytestring.h b/core/fxcrt/cfx_bytestring.h
index 7459f27..abf8ac8 100644
--- a/core/fxcrt/cfx_bytestring.h
+++ b/core/fxcrt/cfx_bytestring.h
@@ -234,6 +234,7 @@
 uint32_t FX_HashCode_GetA(const CFX_ByteStringC& str, bool bIgnoreCase);
 
 std::ostream& operator<<(std::ostream& os, const CFX_ByteString& str);
+std::ostream& operator<<(std::ostream& os, const CFX_ByteStringC& str);
 
 namespace std {
 
diff --git a/core/fxcrt/cfx_bytestring_unittest.cpp b/core/fxcrt/cfx_bytestring_unittest.cpp
index b026503..f5d9413 100644
--- a/core/fxcrt/cfx_bytestring_unittest.cpp
+++ b/core/fxcrt/cfx_bytestring_unittest.cpp
@@ -1308,3 +1308,74 @@
   stream << str1 << str2;
   EXPECT_EQ("abcdef", stream.str());
 }
+
+TEST(fxcrt, OStreamByteStringCOverload) {
+  // Basic case, empty string
+  {
+    std::ostringstream stream;
+    CFX_ByteStringC str;
+    stream << str;
+    EXPECT_EQ("", stream.str());
+  }
+
+  // Basic case, non-empty string
+  {
+    std::ostringstream stream;
+    CFX_ByteStringC str("def");
+    stream << "abc" << str << "ghi";
+    EXPECT_EQ("abcdefghi", stream.str());
+  }
+
+  // Changing the CFX_ByteStringC does not change the stream it was written to.
+  {
+    std::ostringstream stream;
+    CFX_ByteStringC str("abc");
+    stream << str;
+    str = "123";
+    EXPECT_EQ("abc", stream.str());
+  }
+
+  // Writing it again to the stream will use the latest value.
+  {
+    std::ostringstream stream;
+    CFX_ByteStringC str("abc");
+    stream << str;
+    stream.str("");
+    str = "123";
+    stream << str;
+    EXPECT_EQ("123", stream.str());
+  }
+
+  // Writing a CFX_ByteStringC with nulls and no specified length treats it as
+  // a C-style null-terminated string.
+  {
+    std::ostringstream stream;
+    char stringWithNulls[]{'x', 'y', '\0', 'z'};
+    CFX_ByteStringC str(stringWithNulls);
+    EXPECT_EQ(2, str.GetLength());
+    stream << str;
+    EXPECT_EQ(2u, stream.tellp());
+    str = "";
+  }
+
+  // Writing a CFX_ByteStringC with nulls but specifying its length treats it as
+  // a C++-style string.
+  {
+    std::ostringstream stream;
+    char stringWithNulls[]{'x', 'y', '\0', 'z'};
+    CFX_ByteStringC str(stringWithNulls, 4);
+    EXPECT_EQ(4, str.GetLength());
+    stream << str;
+    EXPECT_EQ(4u, stream.tellp());
+    str = "";
+  }
+
+  // << operators can be chained.
+  {
+    std::ostringstream stream;
+    CFX_ByteStringC str1("abc");
+    CFX_ByteStringC str2("def");
+    stream << str1 << str2;
+    EXPECT_EQ("abcdef", stream.str());
+  }
+}
diff --git a/core/fxcrt/cfx_widestring.cpp b/core/fxcrt/cfx_widestring.cpp
index 46192de..70a0cb6 100644
--- a/core/fxcrt/cfx_widestring.cpp
+++ b/core/fxcrt/cfx_widestring.cpp
@@ -1058,3 +1058,12 @@
   os << str.UTF8Encode();
   return os;
 }
+
+std::wostream& operator<<(std::wostream& os, const CFX_WideStringC& str) {
+  return os.write(str.c_str(), str.GetLength());
+}
+
+std::ostream& operator<<(std::ostream& os, const CFX_WideStringC& str) {
+  os << FX_UTF8Encode(str);
+  return os;
+}
diff --git a/core/fxcrt/cfx_widestring.h b/core/fxcrt/cfx_widestring.h
index 3d69b0b..0e477bf 100644
--- a/core/fxcrt/cfx_widestring.h
+++ b/core/fxcrt/cfx_widestring.h
@@ -229,8 +229,9 @@
 uint32_t FX_HashCode_GetW(const CFX_WideStringC& str, bool bIgnoreCase);
 
 std::wostream& operator<<(std::wostream& os, const CFX_WideString& str);
-
 std::ostream& operator<<(std::ostream& os, const CFX_WideString& str);
+std::wostream& operator<<(std::wostream& os, const CFX_WideStringC& str);
+std::ostream& operator<<(std::ostream& os, const CFX_WideStringC& str);
 
 namespace std {
 
diff --git a/core/fxcrt/cfx_widestring_unittest.cpp b/core/fxcrt/cfx_widestring_unittest.cpp
index 2578cb6..4cd71d9 100644
--- a/core/fxcrt/cfx_widestring_unittest.cpp
+++ b/core/fxcrt/cfx_widestring_unittest.cpp
@@ -1210,3 +1210,159 @@
   stream << str1 << str2;
   EXPECT_EQ(L"abcdef", stream.str());
 }
+
+TEST(fxcrt, OStreamWideStringCOverload) {
+  // Basic case, empty string
+  {
+    std::ostringstream stream;
+    CFX_WideStringC str;
+    stream << str;
+    EXPECT_EQ("", stream.str());
+  }
+
+  // Basic case, non-empty string
+  {
+    std::ostringstream stream;
+    CFX_WideStringC str(L"def");
+    stream << "abc" << str << "ghi";
+    EXPECT_EQ("abcdefghi", stream.str());
+  }
+
+  // Basic case, wide character
+  {
+    std::ostringstream stream;
+    CFX_WideStringC str(L"\u20AC");
+    stream << str;
+    EXPECT_EQ("\u20AC", stream.str());
+  }
+
+  // Changing the CFX_WideStringC does not change the stream it was written to.
+  {
+    std::ostringstream stream;
+    CFX_WideStringC str(L"abc");
+    stream << str;
+    str = L"123";
+    EXPECT_EQ("abc", stream.str());
+  }
+
+  // Writing it again to the stream will use the latest value.
+  {
+    std::ostringstream stream;
+    CFX_WideStringC str(L"abc");
+    stream << str;
+    stream.str("");
+    str = L"123";
+    stream << str;
+    EXPECT_EQ("123", stream.str());
+  }
+
+  // Writing a CFX_WideStringC with nulls and no specified length treats it as
+  // a C-style null-terminated string.
+  {
+    wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
+    std::ostringstream stream;
+    CFX_WideStringC str(stringWithNulls);
+    EXPECT_EQ(2, str.GetLength());
+    stream << str;
+    EXPECT_EQ(2u, stream.tellp());
+    str = L"";
+  }
+
+  // Writing a CFX_WideStringC with nulls but specifying its length treats it as
+  // a C++-style string.
+  {
+    wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
+    std::ostringstream stream;
+    CFX_WideStringC str(stringWithNulls, 4);
+    EXPECT_EQ(4, str.GetLength());
+    stream << str;
+    EXPECT_EQ(4u, stream.tellp());
+    str = L"";
+  }
+
+  // << operators can be chained.
+  {
+    std::ostringstream stream;
+    CFX_WideStringC str1(L"abc");
+    CFX_WideStringC str2(L"def");
+    stream << str1 << str2;
+    EXPECT_EQ("abcdef", stream.str());
+  }
+}
+
+TEST(fxcrt, WideOStreamWideStringCOverload) {
+  // Basic case, empty string
+  {
+    std::wostringstream stream;
+    CFX_WideStringC str;
+    stream << str;
+    EXPECT_EQ(L"", stream.str());
+  }
+
+  // Basic case, non-empty string
+  {
+    std::wostringstream stream;
+    CFX_WideStringC str(L"def");
+    stream << "abc" << str << "ghi";
+    EXPECT_EQ(L"abcdefghi", stream.str());
+  }
+
+  // Basic case, wide character
+  {
+    std::wostringstream stream;
+    CFX_WideStringC str(L"\u20AC");
+    stream << str;
+    EXPECT_EQ(L"\u20AC", stream.str());
+  }
+
+  // Changing the CFX_WideStringC does not change the stream it was written to.
+  {
+    std::wostringstream stream;
+    CFX_WideStringC str(L"abc");
+    stream << str;
+    str = L"123";
+    EXPECT_EQ(L"abc", stream.str());
+  }
+
+  // Writing it again to the stream will use the latest value.
+  {
+    std::wostringstream stream;
+    CFX_WideStringC str(L"abc");
+    stream << str;
+    stream.str(L"");
+    str = L"123";
+    stream << str;
+    EXPECT_EQ(L"123", stream.str());
+  }
+
+  // Writing a CFX_WideStringC with nulls and no specified length treats it as
+  // a C-style null-terminated string.
+  {
+    wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
+    std::wostringstream stream;
+    CFX_WideStringC str(stringWithNulls);
+    EXPECT_EQ(2, str.GetLength());
+    stream << str;
+    EXPECT_EQ(2u, stream.tellp());
+  }
+
+  // Writing a CFX_WideStringC with nulls but specifying its length treats it as
+  // a C++-style string.
+  {
+    wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
+    std::wostringstream stream;
+    CFX_WideStringC str(stringWithNulls, 4);
+    EXPECT_EQ(4, str.GetLength());
+    stream << str;
+    EXPECT_EQ(4u, stream.tellp());
+  }
+
+  // << operators can be chained.
+  {
+    std::wostringstream stream;
+    CFX_WideStringC str1(L"abc");
+    CFX_WideStringC str2(L"def");
+    stream << str1 << str2;
+    EXPECT_EQ(L"abcdef", stream.str());
+  }
+}