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