1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/xfa_utils.h"
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
10*3ac0a46fSAndroid Build Coastguard Worker #include <vector>
11*3ac0a46fSAndroid Build Coastguard Worker
12*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/cfx_memorystream.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_codepage.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_extension.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/widetext_buffer.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmlchardata.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmlelement.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmlnode.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmltext.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/xfa/cjx_object.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_document.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_localemgr.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_measurement.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_node.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_ui.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_value.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/xfa_basic_data.h"
29*3ac0a46fSAndroid Build Coastguard Worker
30*3ac0a46fSAndroid Build Coastguard Worker namespace {
31*3ac0a46fSAndroid Build Coastguard Worker
32*3ac0a46fSAndroid Build Coastguard Worker const char kFormNS[] = "http://www.xfa.org/schema/xfa-form/";
33*3ac0a46fSAndroid Build Coastguard Worker
ExportEncodeAttribute(const WideString & str)34*3ac0a46fSAndroid Build Coastguard Worker WideString ExportEncodeAttribute(const WideString& str) {
35*3ac0a46fSAndroid Build Coastguard Worker WideString textBuf;
36*3ac0a46fSAndroid Build Coastguard Worker textBuf.Reserve(str.GetLength()); // Result always at least as big as input.
37*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < str.GetLength(); i++) {
38*3ac0a46fSAndroid Build Coastguard Worker switch (str[i]) {
39*3ac0a46fSAndroid Build Coastguard Worker case '&':
40*3ac0a46fSAndroid Build Coastguard Worker textBuf += L"&";
41*3ac0a46fSAndroid Build Coastguard Worker break;
42*3ac0a46fSAndroid Build Coastguard Worker case '<':
43*3ac0a46fSAndroid Build Coastguard Worker textBuf += L"<";
44*3ac0a46fSAndroid Build Coastguard Worker break;
45*3ac0a46fSAndroid Build Coastguard Worker case '>':
46*3ac0a46fSAndroid Build Coastguard Worker textBuf += L">";
47*3ac0a46fSAndroid Build Coastguard Worker break;
48*3ac0a46fSAndroid Build Coastguard Worker case '\'':
49*3ac0a46fSAndroid Build Coastguard Worker textBuf += L"'";
50*3ac0a46fSAndroid Build Coastguard Worker break;
51*3ac0a46fSAndroid Build Coastguard Worker case '\"':
52*3ac0a46fSAndroid Build Coastguard Worker textBuf += L""";
53*3ac0a46fSAndroid Build Coastguard Worker break;
54*3ac0a46fSAndroid Build Coastguard Worker default:
55*3ac0a46fSAndroid Build Coastguard Worker textBuf += str[i];
56*3ac0a46fSAndroid Build Coastguard Worker }
57*3ac0a46fSAndroid Build Coastguard Worker }
58*3ac0a46fSAndroid Build Coastguard Worker return textBuf;
59*3ac0a46fSAndroid Build Coastguard Worker }
60*3ac0a46fSAndroid Build Coastguard Worker
IsXMLValidChar(wchar_t ch)61*3ac0a46fSAndroid Build Coastguard Worker bool IsXMLValidChar(wchar_t ch) {
62*3ac0a46fSAndroid Build Coastguard Worker return ch == 0x09 || ch == 0x0A || ch == 0x0D ||
63*3ac0a46fSAndroid Build Coastguard Worker (ch >= 0x20 && ch <= 0xD7FF) || (ch >= 0xE000 && ch <= 0xFFFD);
64*3ac0a46fSAndroid Build Coastguard Worker }
65*3ac0a46fSAndroid Build Coastguard Worker
ExportEncodeContent(const WideString & str)66*3ac0a46fSAndroid Build Coastguard Worker WideString ExportEncodeContent(const WideString& str) {
67*3ac0a46fSAndroid Build Coastguard Worker WideTextBuffer textBuf;
68*3ac0a46fSAndroid Build Coastguard Worker size_t iLen = str.GetLength();
69*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < iLen; i++) {
70*3ac0a46fSAndroid Build Coastguard Worker wchar_t ch = str[i];
71*3ac0a46fSAndroid Build Coastguard Worker if (!IsXMLValidChar(ch))
72*3ac0a46fSAndroid Build Coastguard Worker continue;
73*3ac0a46fSAndroid Build Coastguard Worker
74*3ac0a46fSAndroid Build Coastguard Worker if (ch == '&') {
75*3ac0a46fSAndroid Build Coastguard Worker textBuf << "&";
76*3ac0a46fSAndroid Build Coastguard Worker } else if (ch == '<') {
77*3ac0a46fSAndroid Build Coastguard Worker textBuf << "<";
78*3ac0a46fSAndroid Build Coastguard Worker } else if (ch == '>') {
79*3ac0a46fSAndroid Build Coastguard Worker textBuf << ">";
80*3ac0a46fSAndroid Build Coastguard Worker } else if (ch == '\'') {
81*3ac0a46fSAndroid Build Coastguard Worker textBuf << "'";
82*3ac0a46fSAndroid Build Coastguard Worker } else if (ch == '\"') {
83*3ac0a46fSAndroid Build Coastguard Worker textBuf << """;
84*3ac0a46fSAndroid Build Coastguard Worker } else if (ch == ' ') {
85*3ac0a46fSAndroid Build Coastguard Worker if (i && str[i - 1] != ' ') {
86*3ac0a46fSAndroid Build Coastguard Worker textBuf.AppendChar(' ');
87*3ac0a46fSAndroid Build Coastguard Worker } else {
88*3ac0a46fSAndroid Build Coastguard Worker textBuf << " ";
89*3ac0a46fSAndroid Build Coastguard Worker }
90*3ac0a46fSAndroid Build Coastguard Worker } else {
91*3ac0a46fSAndroid Build Coastguard Worker textBuf.AppendChar(str[i]);
92*3ac0a46fSAndroid Build Coastguard Worker }
93*3ac0a46fSAndroid Build Coastguard Worker }
94*3ac0a46fSAndroid Build Coastguard Worker return textBuf.MakeString();
95*3ac0a46fSAndroid Build Coastguard Worker }
96*3ac0a46fSAndroid Build Coastguard Worker
AttributeSaveInDataModel(CXFA_Node * pNode,XFA_Attribute eAttribute)97*3ac0a46fSAndroid Build Coastguard Worker bool AttributeSaveInDataModel(CXFA_Node* pNode, XFA_Attribute eAttribute) {
98*3ac0a46fSAndroid Build Coastguard Worker bool bSaveInDataModel = false;
99*3ac0a46fSAndroid Build Coastguard Worker if (pNode->GetElementType() != XFA_Element::Image)
100*3ac0a46fSAndroid Build Coastguard Worker return bSaveInDataModel;
101*3ac0a46fSAndroid Build Coastguard Worker
102*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pValueNode = pNode->GetParent();
103*3ac0a46fSAndroid Build Coastguard Worker if (!pValueNode || pValueNode->GetElementType() != XFA_Element::Value)
104*3ac0a46fSAndroid Build Coastguard Worker return bSaveInDataModel;
105*3ac0a46fSAndroid Build Coastguard Worker
106*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pFieldNode = pValueNode->GetParent();
107*3ac0a46fSAndroid Build Coastguard Worker if (pFieldNode && pFieldNode->GetBindData() &&
108*3ac0a46fSAndroid Build Coastguard Worker eAttribute == XFA_Attribute::Href) {
109*3ac0a46fSAndroid Build Coastguard Worker bSaveInDataModel = true;
110*3ac0a46fSAndroid Build Coastguard Worker }
111*3ac0a46fSAndroid Build Coastguard Worker return bSaveInDataModel;
112*3ac0a46fSAndroid Build Coastguard Worker }
113*3ac0a46fSAndroid Build Coastguard Worker
ContentNodeNeedtoExport(CXFA_Node * pContentNode)114*3ac0a46fSAndroid Build Coastguard Worker bool ContentNodeNeedtoExport(CXFA_Node* pContentNode) {
115*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> wsContent =
116*3ac0a46fSAndroid Build Coastguard Worker pContentNode->JSObject()->TryContent(false, false);
117*3ac0a46fSAndroid Build Coastguard Worker if (!wsContent.has_value())
118*3ac0a46fSAndroid Build Coastguard Worker return false;
119*3ac0a46fSAndroid Build Coastguard Worker
120*3ac0a46fSAndroid Build Coastguard Worker DCHECK(pContentNode->IsContentNode());
121*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pParentNode = pContentNode->GetParent();
122*3ac0a46fSAndroid Build Coastguard Worker if (!pParentNode || pParentNode->GetElementType() != XFA_Element::Value)
123*3ac0a46fSAndroid Build Coastguard Worker return true;
124*3ac0a46fSAndroid Build Coastguard Worker
125*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pGrandParentNode = pParentNode->GetParent();
126*3ac0a46fSAndroid Build Coastguard Worker if (!pGrandParentNode || !pGrandParentNode->IsContainerNode())
127*3ac0a46fSAndroid Build Coastguard Worker return true;
128*3ac0a46fSAndroid Build Coastguard Worker if (!pGrandParentNode->GetBindData())
129*3ac0a46fSAndroid Build Coastguard Worker return false;
130*3ac0a46fSAndroid Build Coastguard Worker if (pGrandParentNode->GetFFWidgetType() == XFA_FFWidgetType::kPasswordEdit)
131*3ac0a46fSAndroid Build Coastguard Worker return false;
132*3ac0a46fSAndroid Build Coastguard Worker return true;
133*3ac0a46fSAndroid Build Coastguard Worker }
134*3ac0a46fSAndroid Build Coastguard Worker
SaveAttribute(CXFA_Node * pNode,XFA_Attribute eName,WideStringView wsName,bool bProto)135*3ac0a46fSAndroid Build Coastguard Worker WideString SaveAttribute(CXFA_Node* pNode,
136*3ac0a46fSAndroid Build Coastguard Worker XFA_Attribute eName,
137*3ac0a46fSAndroid Build Coastguard Worker WideStringView wsName,
138*3ac0a46fSAndroid Build Coastguard Worker bool bProto) {
139*3ac0a46fSAndroid Build Coastguard Worker if (!bProto && !pNode->JSObject()->HasAttribute(eName))
140*3ac0a46fSAndroid Build Coastguard Worker return WideString();
141*3ac0a46fSAndroid Build Coastguard Worker
142*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> value =
143*3ac0a46fSAndroid Build Coastguard Worker pNode->JSObject()->TryAttribute(eName, false);
144*3ac0a46fSAndroid Build Coastguard Worker if (!value.has_value())
145*3ac0a46fSAndroid Build Coastguard Worker return WideString();
146*3ac0a46fSAndroid Build Coastguard Worker
147*3ac0a46fSAndroid Build Coastguard Worker WideString wsEncoded = ExportEncodeAttribute(value.value());
148*3ac0a46fSAndroid Build Coastguard Worker return WideString{L" ", wsName, L"=\"", wsEncoded.AsStringView(), L"\""};
149*3ac0a46fSAndroid Build Coastguard Worker }
150*3ac0a46fSAndroid Build Coastguard Worker
RegenerateFormFile_Changed(CXFA_Node * pNode,WideTextBuffer & buf,bool bSaveXML)151*3ac0a46fSAndroid Build Coastguard Worker void RegenerateFormFile_Changed(CXFA_Node* pNode,
152*3ac0a46fSAndroid Build Coastguard Worker WideTextBuffer& buf,
153*3ac0a46fSAndroid Build Coastguard Worker bool bSaveXML) {
154*3ac0a46fSAndroid Build Coastguard Worker WideString wsAttrs;
155*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0;; ++i) {
156*3ac0a46fSAndroid Build Coastguard Worker XFA_Attribute attr = pNode->GetAttribute(i);
157*3ac0a46fSAndroid Build Coastguard Worker if (attr == XFA_Attribute::Unknown)
158*3ac0a46fSAndroid Build Coastguard Worker break;
159*3ac0a46fSAndroid Build Coastguard Worker
160*3ac0a46fSAndroid Build Coastguard Worker if (attr == XFA_Attribute::Name ||
161*3ac0a46fSAndroid Build Coastguard Worker (AttributeSaveInDataModel(pNode, attr) && !bSaveXML)) {
162*3ac0a46fSAndroid Build Coastguard Worker continue;
163*3ac0a46fSAndroid Build Coastguard Worker }
164*3ac0a46fSAndroid Build Coastguard Worker WideString wsAttr = WideString::FromASCII(XFA_AttributeToName(attr));
165*3ac0a46fSAndroid Build Coastguard Worker wsAttrs += SaveAttribute(pNode, attr, wsAttr.AsStringView(), bSaveXML);
166*3ac0a46fSAndroid Build Coastguard Worker }
167*3ac0a46fSAndroid Build Coastguard Worker
168*3ac0a46fSAndroid Build Coastguard Worker WideString wsChildren;
169*3ac0a46fSAndroid Build Coastguard Worker switch (pNode->GetObjectType()) {
170*3ac0a46fSAndroid Build Coastguard Worker case XFA_ObjectType::ContentNode: {
171*3ac0a46fSAndroid Build Coastguard Worker if (!bSaveXML && !ContentNodeNeedtoExport(pNode))
172*3ac0a46fSAndroid Build Coastguard Worker break;
173*3ac0a46fSAndroid Build Coastguard Worker
174*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pRawValueNode = pNode->GetFirstChild();
175*3ac0a46fSAndroid Build Coastguard Worker while (pRawValueNode &&
176*3ac0a46fSAndroid Build Coastguard Worker pRawValueNode->GetElementType() != XFA_Element::SharpxHTML &&
177*3ac0a46fSAndroid Build Coastguard Worker pRawValueNode->GetElementType() != XFA_Element::Sharptext &&
178*3ac0a46fSAndroid Build Coastguard Worker pRawValueNode->GetElementType() != XFA_Element::Sharpxml) {
179*3ac0a46fSAndroid Build Coastguard Worker pRawValueNode = pRawValueNode->GetNextSibling();
180*3ac0a46fSAndroid Build Coastguard Worker }
181*3ac0a46fSAndroid Build Coastguard Worker if (!pRawValueNode)
182*3ac0a46fSAndroid Build Coastguard Worker break;
183*3ac0a46fSAndroid Build Coastguard Worker
184*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> contentType =
185*3ac0a46fSAndroid Build Coastguard Worker pNode->JSObject()->TryAttribute(XFA_Attribute::ContentType, false);
186*3ac0a46fSAndroid Build Coastguard Worker if (pRawValueNode->GetElementType() == XFA_Element::SharpxHTML &&
187*3ac0a46fSAndroid Build Coastguard Worker contentType.has_value() &&
188*3ac0a46fSAndroid Build Coastguard Worker contentType.value().EqualsASCII("text/html")) {
189*3ac0a46fSAndroid Build Coastguard Worker CFX_XMLNode* pExDataXML = pNode->GetXMLMappingNode();
190*3ac0a46fSAndroid Build Coastguard Worker if (!pExDataXML)
191*3ac0a46fSAndroid Build Coastguard Worker break;
192*3ac0a46fSAndroid Build Coastguard Worker
193*3ac0a46fSAndroid Build Coastguard Worker CFX_XMLNode* pRichTextXML = pExDataXML->GetFirstChild();
194*3ac0a46fSAndroid Build Coastguard Worker if (!pRichTextXML)
195*3ac0a46fSAndroid Build Coastguard Worker break;
196*3ac0a46fSAndroid Build Coastguard Worker
197*3ac0a46fSAndroid Build Coastguard Worker auto pMemStream = pdfium::MakeRetain<CFX_MemoryStream>();
198*3ac0a46fSAndroid Build Coastguard Worker pRichTextXML->Save(pMemStream);
199*3ac0a46fSAndroid Build Coastguard Worker wsChildren +=
200*3ac0a46fSAndroid Build Coastguard Worker WideString::FromUTF8(ByteStringView(pMemStream->GetSpan()));
201*3ac0a46fSAndroid Build Coastguard Worker } else if (pRawValueNode->GetElementType() == XFA_Element::Sharpxml &&
202*3ac0a46fSAndroid Build Coastguard Worker contentType.has_value() &&
203*3ac0a46fSAndroid Build Coastguard Worker contentType.value().EqualsASCII("text/xml")) {
204*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> rawValue =
205*3ac0a46fSAndroid Build Coastguard Worker pRawValueNode->JSObject()->TryAttribute(XFA_Attribute::Value,
206*3ac0a46fSAndroid Build Coastguard Worker false);
207*3ac0a46fSAndroid Build Coastguard Worker if (!rawValue.has_value() || rawValue->IsEmpty())
208*3ac0a46fSAndroid Build Coastguard Worker break;
209*3ac0a46fSAndroid Build Coastguard Worker
210*3ac0a46fSAndroid Build Coastguard Worker std::vector<WideString> wsSelTextArray =
211*3ac0a46fSAndroid Build Coastguard Worker fxcrt::Split(rawValue.value(), L'\n');
212*3ac0a46fSAndroid Build Coastguard Worker
213*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pParentNode = pNode->GetParent();
214*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pGrandparentNode = pParentNode->GetParent();
215*3ac0a46fSAndroid Build Coastguard Worker WideString bodyTagName =
216*3ac0a46fSAndroid Build Coastguard Worker pGrandparentNode->JSObject()->GetCData(XFA_Attribute::Name);
217*3ac0a46fSAndroid Build Coastguard Worker if (bodyTagName.IsEmpty())
218*3ac0a46fSAndroid Build Coastguard Worker bodyTagName = L"ListBox1";
219*3ac0a46fSAndroid Build Coastguard Worker
220*3ac0a46fSAndroid Build Coastguard Worker buf << "<" << bodyTagName << " xmlns=\"\">\n";
221*3ac0a46fSAndroid Build Coastguard Worker for (const WideString& text : wsSelTextArray)
222*3ac0a46fSAndroid Build Coastguard Worker buf << "<value>" << ExportEncodeContent(text) << "</value>\n";
223*3ac0a46fSAndroid Build Coastguard Worker buf << "</" << bodyTagName << ">\n";
224*3ac0a46fSAndroid Build Coastguard Worker wsChildren += buf.AsStringView();
225*3ac0a46fSAndroid Build Coastguard Worker buf.Clear();
226*3ac0a46fSAndroid Build Coastguard Worker } else {
227*3ac0a46fSAndroid Build Coastguard Worker WideString wsValue =
228*3ac0a46fSAndroid Build Coastguard Worker pRawValueNode->JSObject()->GetCData(XFA_Attribute::Value);
229*3ac0a46fSAndroid Build Coastguard Worker wsChildren += ExportEncodeContent(wsValue);
230*3ac0a46fSAndroid Build Coastguard Worker }
231*3ac0a46fSAndroid Build Coastguard Worker break;
232*3ac0a46fSAndroid Build Coastguard Worker }
233*3ac0a46fSAndroid Build Coastguard Worker case XFA_ObjectType::TextNode:
234*3ac0a46fSAndroid Build Coastguard Worker case XFA_ObjectType::NodeC:
235*3ac0a46fSAndroid Build Coastguard Worker case XFA_ObjectType::NodeV: {
236*3ac0a46fSAndroid Build Coastguard Worker WideString wsValue = pNode->JSObject()->GetCData(XFA_Attribute::Value);
237*3ac0a46fSAndroid Build Coastguard Worker wsChildren += ExportEncodeContent(wsValue);
238*3ac0a46fSAndroid Build Coastguard Worker break;
239*3ac0a46fSAndroid Build Coastguard Worker }
240*3ac0a46fSAndroid Build Coastguard Worker default:
241*3ac0a46fSAndroid Build Coastguard Worker if (pNode->GetElementType() == XFA_Element::Items) {
242*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pTemplateNode = pNode->GetTemplateNodeIfExists();
243*3ac0a46fSAndroid Build Coastguard Worker if (!pTemplateNode ||
244*3ac0a46fSAndroid Build Coastguard Worker pTemplateNode->CountChildren(XFA_Element::Unknown, false) !=
245*3ac0a46fSAndroid Build Coastguard Worker pNode->CountChildren(XFA_Element::Unknown, false)) {
246*3ac0a46fSAndroid Build Coastguard Worker bSaveXML = true;
247*3ac0a46fSAndroid Build Coastguard Worker }
248*3ac0a46fSAndroid Build Coastguard Worker }
249*3ac0a46fSAndroid Build Coastguard Worker WideTextBuffer newBuf;
250*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pChildNode = pNode->GetFirstChild();
251*3ac0a46fSAndroid Build Coastguard Worker while (pChildNode) {
252*3ac0a46fSAndroid Build Coastguard Worker RegenerateFormFile_Changed(pChildNode, newBuf, bSaveXML);
253*3ac0a46fSAndroid Build Coastguard Worker wsChildren += newBuf.AsStringView();
254*3ac0a46fSAndroid Build Coastguard Worker newBuf.Clear();
255*3ac0a46fSAndroid Build Coastguard Worker pChildNode = pChildNode->GetNextSibling();
256*3ac0a46fSAndroid Build Coastguard Worker }
257*3ac0a46fSAndroid Build Coastguard Worker if (!bSaveXML && !wsChildren.IsEmpty() &&
258*3ac0a46fSAndroid Build Coastguard Worker pNode->GetElementType() == XFA_Element::Items) {
259*3ac0a46fSAndroid Build Coastguard Worker wsChildren.clear();
260*3ac0a46fSAndroid Build Coastguard Worker bSaveXML = true;
261*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pChild = pNode->GetFirstChild();
262*3ac0a46fSAndroid Build Coastguard Worker while (pChild) {
263*3ac0a46fSAndroid Build Coastguard Worker RegenerateFormFile_Changed(pChild, newBuf, bSaveXML);
264*3ac0a46fSAndroid Build Coastguard Worker wsChildren += newBuf.AsStringView();
265*3ac0a46fSAndroid Build Coastguard Worker newBuf.Clear();
266*3ac0a46fSAndroid Build Coastguard Worker pChild = pChild->GetNextSibling();
267*3ac0a46fSAndroid Build Coastguard Worker }
268*3ac0a46fSAndroid Build Coastguard Worker }
269*3ac0a46fSAndroid Build Coastguard Worker break;
270*3ac0a46fSAndroid Build Coastguard Worker }
271*3ac0a46fSAndroid Build Coastguard Worker
272*3ac0a46fSAndroid Build Coastguard Worker if (!wsChildren.IsEmpty() || !wsAttrs.IsEmpty() ||
273*3ac0a46fSAndroid Build Coastguard Worker pNode->JSObject()->HasAttribute(XFA_Attribute::Name)) {
274*3ac0a46fSAndroid Build Coastguard Worker WideString wsElement = WideString::FromASCII(pNode->GetClassName());
275*3ac0a46fSAndroid Build Coastguard Worker buf << "<";
276*3ac0a46fSAndroid Build Coastguard Worker buf << wsElement;
277*3ac0a46fSAndroid Build Coastguard Worker buf << SaveAttribute(pNode, XFA_Attribute::Name, L"name", true);
278*3ac0a46fSAndroid Build Coastguard Worker buf << wsAttrs;
279*3ac0a46fSAndroid Build Coastguard Worker if (wsChildren.IsEmpty()) {
280*3ac0a46fSAndroid Build Coastguard Worker buf << "/>\n";
281*3ac0a46fSAndroid Build Coastguard Worker } else {
282*3ac0a46fSAndroid Build Coastguard Worker buf << ">\n" << wsChildren << "</" << wsElement << ">\n";
283*3ac0a46fSAndroid Build Coastguard Worker }
284*3ac0a46fSAndroid Build Coastguard Worker }
285*3ac0a46fSAndroid Build Coastguard Worker }
286*3ac0a46fSAndroid Build Coastguard Worker
RegenerateFormFile_Container(CXFA_Node * pNode,const RetainPtr<IFX_SeekableStream> & pStream,bool bSaveXML)287*3ac0a46fSAndroid Build Coastguard Worker void RegenerateFormFile_Container(CXFA_Node* pNode,
288*3ac0a46fSAndroid Build Coastguard Worker const RetainPtr<IFX_SeekableStream>& pStream,
289*3ac0a46fSAndroid Build Coastguard Worker bool bSaveXML) {
290*3ac0a46fSAndroid Build Coastguard Worker XFA_Element eType = pNode->GetElementType();
291*3ac0a46fSAndroid Build Coastguard Worker if (eType == XFA_Element::Field || eType == XFA_Element::Draw ||
292*3ac0a46fSAndroid Build Coastguard Worker !pNode->IsContainerNode()) {
293*3ac0a46fSAndroid Build Coastguard Worker WideTextBuffer buf;
294*3ac0a46fSAndroid Build Coastguard Worker RegenerateFormFile_Changed(pNode, buf, bSaveXML);
295*3ac0a46fSAndroid Build Coastguard Worker size_t nLen = buf.GetLength();
296*3ac0a46fSAndroid Build Coastguard Worker if (nLen > 0)
297*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(buf.MakeString().ToUTF8().AsStringView());
298*3ac0a46fSAndroid Build Coastguard Worker return;
299*3ac0a46fSAndroid Build Coastguard Worker }
300*3ac0a46fSAndroid Build Coastguard Worker
301*3ac0a46fSAndroid Build Coastguard Worker WideString wsElement = WideString::FromASCII(pNode->GetClassName());
302*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString("<");
303*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(wsElement.ToUTF8().AsStringView());
304*3ac0a46fSAndroid Build Coastguard Worker
305*3ac0a46fSAndroid Build Coastguard Worker WideString wsOutput =
306*3ac0a46fSAndroid Build Coastguard Worker SaveAttribute(pNode, XFA_Attribute::Name, L"name", true);
307*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0;; ++i) {
308*3ac0a46fSAndroid Build Coastguard Worker XFA_Attribute attr = pNode->GetAttribute(i);
309*3ac0a46fSAndroid Build Coastguard Worker if (attr == XFA_Attribute::Unknown)
310*3ac0a46fSAndroid Build Coastguard Worker break;
311*3ac0a46fSAndroid Build Coastguard Worker if (attr == XFA_Attribute::Name)
312*3ac0a46fSAndroid Build Coastguard Worker continue;
313*3ac0a46fSAndroid Build Coastguard Worker
314*3ac0a46fSAndroid Build Coastguard Worker WideString wsAttr = WideString::FromASCII(XFA_AttributeToName(attr));
315*3ac0a46fSAndroid Build Coastguard Worker wsOutput += SaveAttribute(pNode, attr, wsAttr.AsStringView(), false);
316*3ac0a46fSAndroid Build Coastguard Worker }
317*3ac0a46fSAndroid Build Coastguard Worker
318*3ac0a46fSAndroid Build Coastguard Worker if (!wsOutput.IsEmpty())
319*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(wsOutput.ToUTF8().AsStringView());
320*3ac0a46fSAndroid Build Coastguard Worker
321*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pChildNode = pNode->GetFirstChild();
322*3ac0a46fSAndroid Build Coastguard Worker if (!pChildNode) {
323*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(" />\n");
324*3ac0a46fSAndroid Build Coastguard Worker return;
325*3ac0a46fSAndroid Build Coastguard Worker }
326*3ac0a46fSAndroid Build Coastguard Worker
327*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(">\n");
328*3ac0a46fSAndroid Build Coastguard Worker while (pChildNode) {
329*3ac0a46fSAndroid Build Coastguard Worker RegenerateFormFile_Container(pChildNode, pStream, bSaveXML);
330*3ac0a46fSAndroid Build Coastguard Worker pChildNode = pChildNode->GetNextSibling();
331*3ac0a46fSAndroid Build Coastguard Worker }
332*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString("</");
333*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(wsElement.ToUTF8().AsStringView());
334*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(">\n");
335*3ac0a46fSAndroid Build Coastguard Worker }
336*3ac0a46fSAndroid Build Coastguard Worker
RecognizeXFAVersionNumber(CXFA_Node * pTemplateRoot)337*3ac0a46fSAndroid Build Coastguard Worker WideString RecognizeXFAVersionNumber(CXFA_Node* pTemplateRoot) {
338*3ac0a46fSAndroid Build Coastguard Worker if (!pTemplateRoot)
339*3ac0a46fSAndroid Build Coastguard Worker return WideString();
340*3ac0a46fSAndroid Build Coastguard Worker
341*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> templateNS =
342*3ac0a46fSAndroid Build Coastguard Worker pTemplateRoot->JSObject()->TryNamespace();
343*3ac0a46fSAndroid Build Coastguard Worker if (!templateNS.has_value())
344*3ac0a46fSAndroid Build Coastguard Worker return WideString();
345*3ac0a46fSAndroid Build Coastguard Worker
346*3ac0a46fSAndroid Build Coastguard Worker XFA_VERSION eVersion =
347*3ac0a46fSAndroid Build Coastguard Worker pTemplateRoot->GetDocument()->RecognizeXFAVersionNumber(
348*3ac0a46fSAndroid Build Coastguard Worker templateNS.value());
349*3ac0a46fSAndroid Build Coastguard Worker if (eVersion == XFA_VERSION_UNKNOWN)
350*3ac0a46fSAndroid Build Coastguard Worker eVersion = XFA_VERSION_DEFAULT;
351*3ac0a46fSAndroid Build Coastguard Worker
352*3ac0a46fSAndroid Build Coastguard Worker return WideString::Format(L"%i.%i", eVersion / 100, eVersion % 100);
353*3ac0a46fSAndroid Build Coastguard Worker }
354*3ac0a46fSAndroid Build Coastguard Worker
355*3ac0a46fSAndroid Build Coastguard Worker } // namespace
356*3ac0a46fSAndroid Build Coastguard Worker
XFA_GetLocaleValue(const CXFA_Node * pNode)357*3ac0a46fSAndroid Build Coastguard Worker CXFA_LocaleValue XFA_GetLocaleValue(const CXFA_Node* pNode) {
358*3ac0a46fSAndroid Build Coastguard Worker const auto* pNodeValue =
359*3ac0a46fSAndroid Build Coastguard Worker pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
360*3ac0a46fSAndroid Build Coastguard Worker if (!pNodeValue)
361*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue();
362*3ac0a46fSAndroid Build Coastguard Worker
363*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pValueChild = pNodeValue->GetFirstChild();
364*3ac0a46fSAndroid Build Coastguard Worker if (!pValueChild)
365*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue();
366*3ac0a46fSAndroid Build Coastguard Worker
367*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue(XFA_GetLocaleValueType(pValueChild->GetElementType()),
368*3ac0a46fSAndroid Build Coastguard Worker pNode->GetRawValue(),
369*3ac0a46fSAndroid Build Coastguard Worker pNode->GetDocument()->GetLocaleMgr());
370*3ac0a46fSAndroid Build Coastguard Worker }
371*3ac0a46fSAndroid Build Coastguard Worker
XFA_GetLocaleValueType(XFA_Element element)372*3ac0a46fSAndroid Build Coastguard Worker CXFA_LocaleValue::ValueType XFA_GetLocaleValueType(XFA_Element element) {
373*3ac0a46fSAndroid Build Coastguard Worker switch (element) {
374*3ac0a46fSAndroid Build Coastguard Worker case XFA_Element::Decimal:
375*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kDecimal;
376*3ac0a46fSAndroid Build Coastguard Worker case XFA_Element::Float:
377*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kFloat;
378*3ac0a46fSAndroid Build Coastguard Worker case XFA_Element::Date:
379*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kDate;
380*3ac0a46fSAndroid Build Coastguard Worker case XFA_Element::Time:
381*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kTime;
382*3ac0a46fSAndroid Build Coastguard Worker case XFA_Element::DateTime:
383*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kDateTime;
384*3ac0a46fSAndroid Build Coastguard Worker case XFA_Element::Boolean:
385*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kBoolean;
386*3ac0a46fSAndroid Build Coastguard Worker case XFA_Element::Integer:
387*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kInteger;
388*3ac0a46fSAndroid Build Coastguard Worker case XFA_Element::Text:
389*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kText;
390*3ac0a46fSAndroid Build Coastguard Worker default:
391*3ac0a46fSAndroid Build Coastguard Worker return CXFA_LocaleValue::ValueType::kNull;
392*3ac0a46fSAndroid Build Coastguard Worker }
393*3ac0a46fSAndroid Build Coastguard Worker }
394*3ac0a46fSAndroid Build Coastguard Worker
XFA_FDEExtension_ResolveNamespaceQualifier(CFX_XMLElement * pNode,const WideString & wsQualifier,WideString * wsNamespaceURI)395*3ac0a46fSAndroid Build Coastguard Worker bool XFA_FDEExtension_ResolveNamespaceQualifier(CFX_XMLElement* pNode,
396*3ac0a46fSAndroid Build Coastguard Worker const WideString& wsQualifier,
397*3ac0a46fSAndroid Build Coastguard Worker WideString* wsNamespaceURI) {
398*3ac0a46fSAndroid Build Coastguard Worker if (!pNode)
399*3ac0a46fSAndroid Build Coastguard Worker return false;
400*3ac0a46fSAndroid Build Coastguard Worker
401*3ac0a46fSAndroid Build Coastguard Worker CFX_XMLNode* pFakeRoot = pNode->GetRoot();
402*3ac0a46fSAndroid Build Coastguard Worker WideString wsNSAttribute;
403*3ac0a46fSAndroid Build Coastguard Worker bool bRet = false;
404*3ac0a46fSAndroid Build Coastguard Worker if (wsQualifier.IsEmpty()) {
405*3ac0a46fSAndroid Build Coastguard Worker wsNSAttribute = L"xmlns";
406*3ac0a46fSAndroid Build Coastguard Worker bRet = true;
407*3ac0a46fSAndroid Build Coastguard Worker } else {
408*3ac0a46fSAndroid Build Coastguard Worker wsNSAttribute = L"xmlns:" + wsQualifier;
409*3ac0a46fSAndroid Build Coastguard Worker }
410*3ac0a46fSAndroid Build Coastguard Worker for (CFX_XMLNode* pParent = pNode; pParent != pFakeRoot;
411*3ac0a46fSAndroid Build Coastguard Worker pParent = pParent->GetParent()) {
412*3ac0a46fSAndroid Build Coastguard Worker CFX_XMLElement* pElement = ToXMLElement(pParent);
413*3ac0a46fSAndroid Build Coastguard Worker if (pElement && pElement->HasAttribute(wsNSAttribute)) {
414*3ac0a46fSAndroid Build Coastguard Worker *wsNamespaceURI = pElement->GetAttribute(wsNSAttribute);
415*3ac0a46fSAndroid Build Coastguard Worker return true;
416*3ac0a46fSAndroid Build Coastguard Worker }
417*3ac0a46fSAndroid Build Coastguard Worker }
418*3ac0a46fSAndroid Build Coastguard Worker wsNamespaceURI->clear();
419*3ac0a46fSAndroid Build Coastguard Worker return bRet;
420*3ac0a46fSAndroid Build Coastguard Worker }
421*3ac0a46fSAndroid Build Coastguard Worker
XFA_DataExporter_DealWithDataGroupNode(CXFA_Node * pDataNode)422*3ac0a46fSAndroid Build Coastguard Worker void XFA_DataExporter_DealWithDataGroupNode(CXFA_Node* pDataNode) {
423*3ac0a46fSAndroid Build Coastguard Worker if (!pDataNode || pDataNode->GetElementType() == XFA_Element::DataValue)
424*3ac0a46fSAndroid Build Coastguard Worker return;
425*3ac0a46fSAndroid Build Coastguard Worker
426*3ac0a46fSAndroid Build Coastguard Worker int32_t iChildNum = 0;
427*3ac0a46fSAndroid Build Coastguard Worker for (CXFA_Node* pChildNode = pDataNode->GetFirstChild(); pChildNode;
428*3ac0a46fSAndroid Build Coastguard Worker pChildNode = pChildNode->GetNextSibling()) {
429*3ac0a46fSAndroid Build Coastguard Worker iChildNum++;
430*3ac0a46fSAndroid Build Coastguard Worker XFA_DataExporter_DealWithDataGroupNode(pChildNode);
431*3ac0a46fSAndroid Build Coastguard Worker }
432*3ac0a46fSAndroid Build Coastguard Worker
433*3ac0a46fSAndroid Build Coastguard Worker if (pDataNode->GetElementType() != XFA_Element::DataGroup)
434*3ac0a46fSAndroid Build Coastguard Worker return;
435*3ac0a46fSAndroid Build Coastguard Worker
436*3ac0a46fSAndroid Build Coastguard Worker CFX_XMLElement* pElement = ToXMLElement(pDataNode->GetXMLMappingNode());
437*3ac0a46fSAndroid Build Coastguard Worker if (iChildNum > 0) {
438*3ac0a46fSAndroid Build Coastguard Worker pElement->RemoveAttribute(L"xfa:dataNode");
439*3ac0a46fSAndroid Build Coastguard Worker return;
440*3ac0a46fSAndroid Build Coastguard Worker }
441*3ac0a46fSAndroid Build Coastguard Worker pElement->SetAttribute(L"xfa:dataNode", L"dataGroup");
442*3ac0a46fSAndroid Build Coastguard Worker }
443*3ac0a46fSAndroid Build Coastguard Worker
XFA_DataExporter_RegenerateFormFile(CXFA_Node * pNode,const RetainPtr<IFX_SeekableStream> & pStream,bool bSaveXML)444*3ac0a46fSAndroid Build Coastguard Worker void XFA_DataExporter_RegenerateFormFile(
445*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pNode,
446*3ac0a46fSAndroid Build Coastguard Worker const RetainPtr<IFX_SeekableStream>& pStream,
447*3ac0a46fSAndroid Build Coastguard Worker bool bSaveXML) {
448*3ac0a46fSAndroid Build Coastguard Worker if (pNode->IsModelNode()) {
449*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString("<form xmlns=\"");
450*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(kFormNS);
451*3ac0a46fSAndroid Build Coastguard Worker
452*3ac0a46fSAndroid Build Coastguard Worker WideString wsVersionNumber = RecognizeXFAVersionNumber(
453*3ac0a46fSAndroid Build Coastguard Worker ToNode(pNode->GetDocument()->GetXFAObject(XFA_HASHCODE_Template)));
454*3ac0a46fSAndroid Build Coastguard Worker if (wsVersionNumber.IsEmpty())
455*3ac0a46fSAndroid Build Coastguard Worker wsVersionNumber = L"2.8";
456*3ac0a46fSAndroid Build Coastguard Worker
457*3ac0a46fSAndroid Build Coastguard Worker wsVersionNumber += L"/\">\n";
458*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString(wsVersionNumber.ToUTF8().AsStringView());
459*3ac0a46fSAndroid Build Coastguard Worker
460*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pChildNode = pNode->GetFirstChild();
461*3ac0a46fSAndroid Build Coastguard Worker while (pChildNode) {
462*3ac0a46fSAndroid Build Coastguard Worker RegenerateFormFile_Container(pChildNode, pStream, false);
463*3ac0a46fSAndroid Build Coastguard Worker pChildNode = pChildNode->GetNextSibling();
464*3ac0a46fSAndroid Build Coastguard Worker }
465*3ac0a46fSAndroid Build Coastguard Worker pStream->WriteString("</form>\n");
466*3ac0a46fSAndroid Build Coastguard Worker } else {
467*3ac0a46fSAndroid Build Coastguard Worker RegenerateFormFile_Container(pNode, pStream, bSaveXML);
468*3ac0a46fSAndroid Build Coastguard Worker }
469*3ac0a46fSAndroid Build Coastguard Worker }
470*3ac0a46fSAndroid Build Coastguard Worker
XFA_FieldIsMultiListBox(const CXFA_Node * pFieldNode)471*3ac0a46fSAndroid Build Coastguard Worker bool XFA_FieldIsMultiListBox(const CXFA_Node* pFieldNode) {
472*3ac0a46fSAndroid Build Coastguard Worker if (!pFieldNode)
473*3ac0a46fSAndroid Build Coastguard Worker return false;
474*3ac0a46fSAndroid Build Coastguard Worker
475*3ac0a46fSAndroid Build Coastguard Worker const auto* pUIChild =
476*3ac0a46fSAndroid Build Coastguard Worker pFieldNode->GetChild<CXFA_Ui>(0, XFA_Element::Ui, false);
477*3ac0a46fSAndroid Build Coastguard Worker if (!pUIChild)
478*3ac0a46fSAndroid Build Coastguard Worker return false;
479*3ac0a46fSAndroid Build Coastguard Worker
480*3ac0a46fSAndroid Build Coastguard Worker CXFA_Node* pFirstChild = pUIChild->GetFirstChild();
481*3ac0a46fSAndroid Build Coastguard Worker if (!pFirstChild ||
482*3ac0a46fSAndroid Build Coastguard Worker pFirstChild->GetElementType() != XFA_Element::ChoiceList) {
483*3ac0a46fSAndroid Build Coastguard Worker return false;
484*3ac0a46fSAndroid Build Coastguard Worker }
485*3ac0a46fSAndroid Build Coastguard Worker
486*3ac0a46fSAndroid Build Coastguard Worker return pFirstChild->JSObject()->GetEnum(XFA_Attribute::Open) ==
487*3ac0a46fSAndroid Build Coastguard Worker XFA_AttributeValue::MultiSelect;
488*3ac0a46fSAndroid Build Coastguard Worker }
489*3ac0a46fSAndroid Build Coastguard Worker
XFA_MapRotation(int32_t nRotation)490*3ac0a46fSAndroid Build Coastguard Worker int32_t XFA_MapRotation(int32_t nRotation) {
491*3ac0a46fSAndroid Build Coastguard Worker nRotation = nRotation % 360;
492*3ac0a46fSAndroid Build Coastguard Worker nRotation = nRotation < 0 ? nRotation + 360 : nRotation;
493*3ac0a46fSAndroid Build Coastguard Worker return nRotation;
494*3ac0a46fSAndroid Build Coastguard Worker }
495*3ac0a46fSAndroid Build Coastguard Worker
XFA_EventErrorAccumulate(XFA_EventError * pAcc,XFA_EventError eNew)496*3ac0a46fSAndroid Build Coastguard Worker void XFA_EventErrorAccumulate(XFA_EventError* pAcc, XFA_EventError eNew) {
497*3ac0a46fSAndroid Build Coastguard Worker if (*pAcc == XFA_EventError::kNotExist || eNew == XFA_EventError::kError)
498*3ac0a46fSAndroid Build Coastguard Worker *pAcc = eNew;
499*3ac0a46fSAndroid Build Coastguard Worker }
500