Add fxcrt::Split() templated function.
All the FX string functions implement Find(), Right(), etc. so
it is easy to build a generic split based on these.
-- Use it in CXFA_Node, CJX_Object, and RegenerateFormFile_Changed()
Change-Id: Ie280bb0a3b6ee7165d9b942245a59dc31ea9bfb2
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/57935
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/fx_string.h b/core/fxcrt/fx_string.h
index ce033fe..8152fbc 100644
--- a/core/fxcrt/fx_string.h
+++ b/core/fxcrt/fx_string.h
@@ -9,6 +9,8 @@
#include <stdint.h>
+#include <vector>
+
#include "core/fxcrt/bytestring.h"
#include "core/fxcrt/widestring.h"
@@ -23,4 +25,23 @@
float StringToFloat(WideStringView wsStr);
size_t FloatToString(float f, char* buf);
+namespace fxcrt {
+
+template <typename StrType>
+std::vector<StrType> Split(const StrType& that, typename StrType::CharType ch) {
+ std::vector<StrType> result;
+ StrType remaining(that);
+ while (1) {
+ Optional<size_t> index = remaining.Find(ch);
+ if (!index.has_value())
+ break;
+ result.push_back(remaining.Left(index.value()));
+ remaining = remaining.Right(remaining.GetLength() - index.value() - 1);
+ }
+ result.push_back(remaining);
+ return result;
+}
+
+} // namespace fxcrt
+
#endif // CORE_FXCRT_FX_STRING_H_
diff --git a/core/fxcrt/fx_string_unittest.cpp b/core/fxcrt/fx_string_unittest.cpp
index 578bda5..ad813ab 100644
--- a/core/fxcrt/fx_string_unittest.cpp
+++ b/core/fxcrt/fx_string_unittest.cpp
@@ -76,3 +76,199 @@
EXPECT_FLOAT_EQ(1.000000119f, StringToFloat("1.000000119"));
EXPECT_FLOAT_EQ(1.999999881f, StringToFloat("1.999999881"));
}
+
+TEST(fxstring, SplitByteString) {
+ std::vector<ByteString> result;
+ result = fxcrt::Split(ByteString(""), ',');
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("", result[0]);
+
+ result = fxcrt::Split(ByteString("a"), ',');
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("a", result[0]);
+
+ result = fxcrt::Split(ByteString(","), ',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("", result[0]);
+ EXPECT_EQ("", result[1]);
+
+ result = fxcrt::Split(ByteString("a,"), ',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("a", result[0]);
+ EXPECT_EQ("", result[1]);
+
+ result = fxcrt::Split(ByteString(",b"), ',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("", result[0]);
+ EXPECT_EQ("b", result[1]);
+
+ result = fxcrt::Split(ByteString("a,b"), ',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("a", result[0]);
+ EXPECT_EQ("b", result[1]);
+
+ result = fxcrt::Split(ByteString("a,b,"), ',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ("a", result[0]);
+ EXPECT_EQ("b", result[1]);
+ EXPECT_EQ("", result[2]);
+
+ result = fxcrt::Split(ByteString("a,,"), ',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ("a", result[0]);
+ EXPECT_EQ("", result[1]);
+ EXPECT_EQ("", result[2]);
+
+ result = fxcrt::Split(ByteString(",,a"), ',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ("", result[0]);
+ EXPECT_EQ("", result[1]);
+ EXPECT_EQ("a", result[2]);
+}
+
+TEST(fxstring, SplitByteStringView) {
+ std::vector<ByteStringView> result;
+ result = fxcrt::Split(ByteStringView(""), ',');
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("", result[0]);
+
+ result = fxcrt::Split(ByteStringView("a"), ',');
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("a", result[0]);
+
+ result = fxcrt::Split(ByteStringView(","), ',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("", result[0]);
+ EXPECT_EQ("", result[1]);
+
+ result = fxcrt::Split(ByteStringView("a,"), ',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("a", result[0]);
+ EXPECT_EQ("", result[1]);
+
+ result = fxcrt::Split(ByteStringView(",b"), ',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("", result[0]);
+ EXPECT_EQ("b", result[1]);
+
+ result = fxcrt::Split(ByteStringView("a,b"), ',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("a", result[0]);
+ EXPECT_EQ("b", result[1]);
+
+ result = fxcrt::Split(ByteStringView("a,b,"), ',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ("a", result[0]);
+ EXPECT_EQ("b", result[1]);
+ EXPECT_EQ("", result[2]);
+
+ result = fxcrt::Split(ByteStringView("a,,"), ',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ("a", result[0]);
+ EXPECT_EQ("", result[1]);
+ EXPECT_EQ("", result[2]);
+
+ result = fxcrt::Split(ByteStringView(",,a"), ',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ("", result[0]);
+ EXPECT_EQ("", result[1]);
+ EXPECT_EQ("a", result[2]);
+}
+
+TEST(fxstring, SplitWideString) {
+ std::vector<WideString> result;
+ result = fxcrt::Split(WideString(L""), L',');
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ(L"", result[0]);
+
+ result = fxcrt::Split(WideString(L"a"), L',');
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+
+ result = fxcrt::Split(WideString(L","), L',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ(L"", result[0]);
+ EXPECT_EQ(L"", result[1]);
+
+ result = fxcrt::Split(WideString(L"a,"), L',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+ EXPECT_EQ(L"", result[1]);
+
+ result = fxcrt::Split(WideString(L",b"), L',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ(L"", result[0]);
+ EXPECT_EQ(L"b", result[1]);
+
+ result = fxcrt::Split(WideString(L"a,b"), L',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+ EXPECT_EQ(L"b", result[1]);
+
+ result = fxcrt::Split(WideString(L"a,b,"), L',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+ EXPECT_EQ(L"b", result[1]);
+ EXPECT_EQ(L"", result[2]);
+
+ result = fxcrt::Split(WideString(L"a,,"), L',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+ EXPECT_EQ(L"", result[1]);
+ EXPECT_EQ(L"", result[2]);
+
+ result = fxcrt::Split(WideString(L",,a"), L',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ(L"", result[0]);
+ EXPECT_EQ(L"", result[1]);
+ EXPECT_EQ(L"a", result[2]);
+}
+
+TEST(fxstring, SplitWideStringView) {
+ std::vector<WideStringView> result;
+ result = fxcrt::Split(WideStringView(L""), L',');
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ(L"", result[0]);
+
+ result = fxcrt::Split(WideStringView(L"a"), L',');
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+
+ result = fxcrt::Split(WideStringView(L","), L',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ(L"", result[0]);
+ EXPECT_EQ(L"", result[1]);
+
+ result = fxcrt::Split(WideStringView(L"a,"), L',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+ EXPECT_EQ(L"", result[1]);
+
+ result = fxcrt::Split(WideStringView(L",b"), L',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ(L"", result[0]);
+ EXPECT_EQ(L"b", result[1]);
+
+ result = fxcrt::Split(WideStringView(L"a,b"), L',');
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+ EXPECT_EQ(L"b", result[1]);
+
+ result = fxcrt::Split(WideStringView(L"a,b,"), L',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+ EXPECT_EQ(L"b", result[1]);
+ EXPECT_EQ(L"", result[2]);
+
+ result = fxcrt::Split(WideStringView(L"a,,"), L',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ(L"a", result[0]);
+ EXPECT_EQ(L"", result[1]);
+ EXPECT_EQ(L"", result[2]);
+
+ result = fxcrt::Split(WideStringView(L",,a"), L',');
+ ASSERT_EQ(3u, result.size());
+ EXPECT_EQ(L"", result[0]);
+ EXPECT_EQ(L"", result[1]);
+ EXPECT_EQ(L"a", result[2]);
+}
diff --git a/fxjs/xfa/cjx_object.cpp b/fxjs/xfa/cjx_object.cpp
index 29d6d17..6b42802 100644
--- a/fxjs/xfa/cjx_object.cpp
+++ b/fxjs/xfa/cjx_object.cpp
@@ -557,26 +557,8 @@
CXFA_Node* pBind = ToNode(GetXFAObject())->GetBindData();
if (bSyncData && pBind) {
- std::vector<WideString> wsSaveTextArray;
- if (!wsContent.IsEmpty()) {
- size_t iStart = 0;
- size_t iLength = wsContent.GetLength();
- auto iEnd = wsContent.Find(L'\n', iStart);
- iEnd = !iEnd.has_value() ? iLength : iEnd;
- while (iEnd.value() >= iStart) {
- wsSaveTextArray.push_back(
- wsContent.Mid(iStart, iEnd.value() - iStart));
- iStart = iEnd.value() + 1;
- if (iStart >= iLength)
- break;
-
- iEnd = wsContent.Find(L'\n', iStart);
- if (!iEnd.has_value()) {
- wsSaveTextArray.push_back(
- wsContent.Mid(iStart, iLength - iStart));
- }
- }
- }
+ std::vector<WideString> wsSaveTextArray =
+ fxcrt::Split(wsContent, L'\n');
std::vector<CXFA_Node*> valueNodes =
pBind->GetNodeListForType(XFA_Element::DataValue);
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index 1de4a9e..e66bd80 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -4258,27 +4258,12 @@
}
std::vector<WideString> CXFA_Node::GetSelectedItemsValue() {
- std::vector<WideString> wsSelTextArray;
WideString wsValue = GetRawValue();
- if (IsChoiceListMultiSelect()) {
- if (!wsValue.IsEmpty()) {
- size_t iStart = 0;
- size_t iLength = wsValue.GetLength();
- auto iEnd = wsValue.Find(L'\n', iStart);
- iEnd = (!iEnd.has_value()) ? iLength : iEnd;
- while (iEnd >= iStart) {
- wsSelTextArray.push_back(wsValue.Mid(iStart, iEnd.value() - iStart));
- iStart = iEnd.value() + 1;
- if (iStart >= iLength)
- break;
- iEnd = wsValue.Find(L'\n', iStart);
- if (!iEnd.has_value())
- wsSelTextArray.push_back(wsValue.Mid(iStart, iLength - iStart));
- }
- }
- } else {
- wsSelTextArray.push_back(wsValue);
- }
+ if (IsChoiceListMultiSelect())
+ return fxcrt::Split(wsValue, L'\n');
+
+ std::vector<WideString> wsSelTextArray;
+ wsSelTextArray.push_back(wsValue);
return wsSelTextArray;
}
diff --git a/xfa/fxfa/parser/xfa_utils.cpp b/xfa/fxfa/parser/xfa_utils.cpp
index 3dddbd9..e9a01ba 100644
--- a/xfa/fxfa/parser/xfa_utils.cpp
+++ b/xfa/fxfa/parser/xfa_utils.cpp
@@ -212,25 +212,12 @@
if (!rawValue || rawValue->IsEmpty())
break;
- std::vector<WideString> wsSelTextArray;
- size_t iStart = 0;
- auto iEnd = rawValue->Find(L'\n', iStart);
- iEnd = !iEnd.has_value() ? rawValue->GetLength() : iEnd;
- while (iEnd.has_value() && iEnd >= iStart) {
- wsSelTextArray.push_back(
- rawValue->Mid(iStart, iEnd.value() - iStart));
- iStart = iEnd.value() + 1;
- if (iStart >= rawValue->GetLength())
- break;
- iEnd = rawValue->Find(L'\n', iStart);
- }
+ std::vector<WideString> wsSelTextArray =
+ fxcrt::Split(rawValue.value(), L'\n');
CXFA_Node* pParentNode = pNode->GetParent();
- ASSERT(pParentNode);
CXFA_Node* pGrandparentNode = pParentNode->GetParent();
- ASSERT(pGrandparentNode);
- WideString bodyTagName;
- bodyTagName =
+ WideString bodyTagName =
pGrandparentNode->JSObject()->GetCData(XFA_Attribute::Name);
if (bodyTagName.IsEmpty())
bodyTagName = L"ListBox1";