1 // Copyright 2017 PDFium Authors. All rights reserved.
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 "fxjs/xfa/cjx_object.h"
8
9 #include <set>
10 #include <tuple>
11
12 #include "core/fxcrt/fx_extension.h"
13 #include "core/fxcrt/xml/cfx_xmlelement.h"
14 #include "core/fxcrt/xml/cfx_xmltext.h"
15 #include "fxjs/cjs_result.h"
16 #include "fxjs/xfa/cfxjse_engine.h"
17 #include "fxjs/xfa/cfxjse_value.h"
18 #include "fxjs/xfa/cjx_boolean.h"
19 #include "fxjs/xfa/cjx_draw.h"
20 #include "fxjs/xfa/cjx_field.h"
21 #include "fxjs/xfa/cjx_instancemanager.h"
22 #include "third_party/base/compiler_specific.h"
23 #include "third_party/base/ptr_util.h"
24 #include "third_party/base/stl_util.h"
25 #include "xfa/fgas/crt/cfgas_decimal.h"
26 #include "xfa/fxfa/cxfa_ffnotify.h"
27 #include "xfa/fxfa/cxfa_ffwidget.h"
28 #include "xfa/fxfa/parser/cxfa_border.h"
29 #include "xfa/fxfa/parser/cxfa_datavalue.h"
30 #include "xfa/fxfa/parser/cxfa_document.h"
31 #include "xfa/fxfa/parser/cxfa_edge.h"
32 #include "xfa/fxfa/parser/cxfa_fill.h"
33 #include "xfa/fxfa/parser/cxfa_font.h"
34 #include "xfa/fxfa/parser/cxfa_measurement.h"
35 #include "xfa/fxfa/parser/cxfa_node.h"
36 #include "xfa/fxfa/parser/cxfa_object.h"
37 #include "xfa/fxfa/parser/cxfa_occur.h"
38 #include "xfa/fxfa/parser/cxfa_proto.h"
39 #include "xfa/fxfa/parser/cxfa_subform.h"
40 #include "xfa/fxfa/parser/cxfa_validate.h"
41 #include "xfa/fxfa/parser/cxfa_value.h"
42 #include "xfa/fxfa/parser/xfa_basic_data.h"
43 #include "xfa/fxfa/parser/xfa_utils.h"
44
45 namespace {
46
XFA_DeleteWideString(void * pData)47 void XFA_DeleteWideString(void* pData) {
48 delete static_cast<WideString*>(pData);
49 }
50
XFA_CopyWideString(void * & pData)51 void XFA_CopyWideString(void*& pData) {
52 if (!pData)
53 return;
54 pData = new WideString(*reinterpret_cast<WideString*>(pData));
55 }
56
57 const XFA_MAPDATABLOCKCALLBACKINFO deleteWideStringCallBack = {
58 XFA_DeleteWideString, XFA_CopyWideString};
59
60 enum XFA_KEYTYPE {
61 XFA_KEYTYPE_Custom,
62 XFA_KEYTYPE_Element,
63 };
64
GetMapKey_Custom(WideStringView wsKey)65 void* GetMapKey_Custom(WideStringView wsKey) {
66 uint32_t dwKey = FX_HashCode_GetW(wsKey, false);
67 return (void*)(uintptr_t)((dwKey << 1) | XFA_KEYTYPE_Custom);
68 }
69
GetMapKey_Element(XFA_Element eType,XFA_Attribute eAttribute)70 void* GetMapKey_Element(XFA_Element eType, XFA_Attribute eAttribute) {
71 return (void*)(uintptr_t)((static_cast<uint32_t>(eType) << 16) |
72 (static_cast<uint32_t>(eAttribute) << 8) |
73 XFA_KEYTYPE_Element);
74 }
75
StrToRGB(const WideString & strRGB)76 std::tuple<int32_t, int32_t, int32_t> StrToRGB(const WideString& strRGB) {
77 int32_t r = 0;
78 int32_t g = 0;
79 int32_t b = 0;
80
81 size_t iIndex = 0;
82 for (size_t i = 0; i < strRGB.GetLength(); ++i) {
83 wchar_t ch = strRGB[i];
84 if (ch == L',')
85 ++iIndex;
86 if (iIndex > 2)
87 break;
88
89 int32_t iValue = ch - L'0';
90 if (iValue >= 0 && iValue <= 9) {
91 switch (iIndex) {
92 case 0:
93 r = r * 10 + iValue;
94 break;
95 case 1:
96 g = g * 10 + iValue;
97 break;
98 default:
99 b = b * 10 + iValue;
100 break;
101 }
102 }
103 }
104 return {r, g, b};
105 }
106
107 } // namespace
108
109 struct XFA_MAPDATABLOCK {
GetDataXFA_MAPDATABLOCK110 uint8_t* GetData() const { return (uint8_t*)this + sizeof(XFA_MAPDATABLOCK); }
111
112 const XFA_MAPDATABLOCKCALLBACKINFO* pCallbackInfo;
113 int32_t iBytes;
114 };
115
116 struct XFA_MAPMODULEDATA {
XFA_MAPMODULEDATAXFA_MAPMODULEDATA117 XFA_MAPMODULEDATA() {}
~XFA_MAPMODULEDATAXFA_MAPMODULEDATA118 ~XFA_MAPMODULEDATA() {}
119
120 std::map<void*, void*> m_ValueMap;
121 std::map<void*, XFA_MAPDATABLOCK*> m_BufferMap;
122 };
123
CJX_Object(CXFA_Object * obj)124 CJX_Object::CJX_Object(CXFA_Object* obj) : object_(obj) {}
125
~CJX_Object()126 CJX_Object::~CJX_Object() {
127 ClearMapModuleBuffer();
128 }
129
DynamicTypeIs(TypeTag eType) const130 bool CJX_Object::DynamicTypeIs(TypeTag eType) const {
131 return eType == static_type__;
132 }
133
DefineMethods(pdfium::span<const CJX_MethodSpec> methods)134 void CJX_Object::DefineMethods(pdfium::span<const CJX_MethodSpec> methods) {
135 for (const auto& item : methods)
136 method_specs_[item.pName] = item.pMethodCall;
137 }
138
GetDocument() const139 CXFA_Document* CJX_Object::GetDocument() const {
140 return object_->GetDocument();
141 }
142
className(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)143 void CJX_Object::className(CFXJSE_Value* pValue,
144 bool bSetting,
145 XFA_Attribute eAttribute) {
146 if (bSetting) {
147 ThrowInvalidPropertyException();
148 return;
149 }
150 pValue->SetString(GetXFAObject()->GetClassName());
151 }
152
Subform_and_SubformSet_InstanceIndex()153 int32_t CJX_Object::Subform_and_SubformSet_InstanceIndex() {
154 int32_t index = 0;
155 for (CXFA_Node* pNode = ToNode(GetXFAObject())->GetPrevSibling(); pNode;
156 pNode = pNode->GetPrevSibling()) {
157 if ((pNode->GetElementType() != XFA_Element::Subform) &&
158 (pNode->GetElementType() != XFA_Element::SubformSet)) {
159 break;
160 }
161 index++;
162 }
163 return index;
164 }
165
HasMethod(const WideString & func) const166 bool CJX_Object::HasMethod(const WideString& func) const {
167 return pdfium::ContainsKey(method_specs_, func.ToUTF8());
168 }
169
RunMethod(const WideString & func,const std::vector<v8::Local<v8::Value>> & params)170 CJS_Result CJX_Object::RunMethod(
171 const WideString& func,
172 const std::vector<v8::Local<v8::Value>>& params) {
173 auto it = method_specs_.find(func.ToUTF8());
174 if (it == method_specs_.end())
175 return CJS_Result::Failure(JSMessage::kUnknownMethod);
176
177 return it->second(this, GetXFAObject()->GetDocument()->GetScriptContext(),
178 params);
179 }
180
ThrowTooManyOccurancesException(const WideString & obj) const181 void CJX_Object::ThrowTooManyOccurancesException(const WideString& obj) const {
182 ThrowException(WideString::FromASCII("The element [") + obj +
183 WideString::FromASCII(
184 "] has violated its allowable number of occurrences."));
185 }
186
ThrowInvalidPropertyException() const187 void CJX_Object::ThrowInvalidPropertyException() const {
188 ThrowException(WideString::FromASCII("Invalid property set operation."));
189 }
190
ThrowIndexOutOfBoundsException() const191 void CJX_Object::ThrowIndexOutOfBoundsException() const {
192 ThrowException(WideString::FromASCII("Index value is out of bounds."));
193 }
194
ThrowParamCountMismatchException(const WideString & method) const195 void CJX_Object::ThrowParamCountMismatchException(
196 const WideString& method) const {
197 ThrowException(
198 WideString::FromASCII("Incorrect number of parameters calling method '") +
199 method + WideString::FromASCII("'."));
200 }
201
ThrowArgumentMismatchException() const202 void CJX_Object::ThrowArgumentMismatchException() const {
203 ThrowException(WideString::FromASCII(
204 "Argument mismatch in property or function argument."));
205 }
206
ThrowException(const WideString & str) const207 void CJX_Object::ThrowException(const WideString& str) const {
208 ASSERT(!str.IsEmpty());
209 FXJSE_ThrowMessage(str.ToUTF8().AsStringView());
210 }
211
HasAttribute(XFA_Attribute eAttr)212 bool CJX_Object::HasAttribute(XFA_Attribute eAttr) {
213 void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
214 return HasMapModuleKey(pKey);
215 }
216
SetAttribute(XFA_Attribute eAttr,WideStringView wsValue,bool bNotify)217 void CJX_Object::SetAttribute(XFA_Attribute eAttr,
218 WideStringView wsValue,
219 bool bNotify) {
220 switch (ToNode(GetXFAObject())->GetAttributeType(eAttr)) {
221 case XFA_AttributeType::Enum: {
222 Optional<XFA_AttributeValue> item = XFA_GetAttributeValueByName(wsValue);
223 SetEnum(eAttr,
224 item ? *item : *(ToNode(GetXFAObject())->GetDefaultEnum(eAttr)),
225 bNotify);
226 break;
227 }
228 case XFA_AttributeType::CData:
229 SetCData(eAttr, WideString(wsValue), bNotify, false);
230 break;
231 case XFA_AttributeType::Boolean:
232 SetBoolean(eAttr, !wsValue.EqualsASCII("0"), bNotify);
233 break;
234 case XFA_AttributeType::Integer:
235 SetInteger(eAttr,
236 FXSYS_roundf(FXSYS_wcstof(wsValue.unterminated_c_str(),
237 wsValue.GetLength(), nullptr)),
238 bNotify);
239 break;
240 case XFA_AttributeType::Measure:
241 SetMeasure(eAttr, CXFA_Measurement(wsValue), bNotify);
242 break;
243 default:
244 break;
245 }
246 }
247
SetMapModuleString(void * pKey,WideStringView wsValue)248 void CJX_Object::SetMapModuleString(void* pKey, WideStringView wsValue) {
249 SetMapModuleBuffer(pKey, const_cast<wchar_t*>(wsValue.unterminated_c_str()),
250 wsValue.GetLength() * sizeof(wchar_t), nullptr);
251 }
252
SetAttribute(WideStringView wsAttr,WideStringView wsValue,bool bNotify)253 void CJX_Object::SetAttribute(WideStringView wsAttr,
254 WideStringView wsValue,
255 bool bNotify) {
256 Optional<XFA_ATTRIBUTEINFO> attr = XFA_GetAttributeByName(wsAttr);
257 if (attr.has_value()) {
258 SetAttribute(attr.value().attribute, wsValue, bNotify);
259 return;
260 }
261 void* pKey = GetMapKey_Custom(wsAttr);
262 SetMapModuleString(pKey, wsValue);
263 }
264
GetAttribute(WideStringView attr)265 WideString CJX_Object::GetAttribute(WideStringView attr) {
266 return TryAttribute(attr, true).value_or(WideString());
267 }
268
GetAttribute(XFA_Attribute attr)269 WideString CJX_Object::GetAttribute(XFA_Attribute attr) {
270 return TryAttribute(attr, true).value_or(WideString());
271 }
272
TryAttribute(XFA_Attribute eAttr,bool bUseDefault)273 Optional<WideString> CJX_Object::TryAttribute(XFA_Attribute eAttr,
274 bool bUseDefault) {
275 switch (ToNode(GetXFAObject())->GetAttributeType(eAttr)) {
276 case XFA_AttributeType::Enum: {
277 Optional<XFA_AttributeValue> value = TryEnum(eAttr, bUseDefault);
278 if (!value)
279 return {};
280 return WideString::FromASCII(XFA_AttributeValueToName(*value));
281 }
282 case XFA_AttributeType::CData:
283 return TryCData(eAttr, bUseDefault);
284
285 case XFA_AttributeType::Boolean: {
286 Optional<bool> value = TryBoolean(eAttr, bUseDefault);
287 if (!value)
288 return {};
289 return WideString(*value ? L"1" : L"0");
290 }
291 case XFA_AttributeType::Integer: {
292 Optional<int32_t> iValue = TryInteger(eAttr, bUseDefault);
293 if (!iValue)
294 return {};
295 return WideString::Format(L"%d", *iValue);
296 }
297 case XFA_AttributeType::Measure: {
298 Optional<CXFA_Measurement> value = TryMeasure(eAttr, bUseDefault);
299 if (!value)
300 return {};
301
302 return value->ToString();
303 }
304 default:
305 break;
306 }
307 return {};
308 }
309
TryAttribute(WideStringView wsAttr,bool bUseDefault)310 Optional<WideString> CJX_Object::TryAttribute(WideStringView wsAttr,
311 bool bUseDefault) {
312 Optional<XFA_ATTRIBUTEINFO> attr = XFA_GetAttributeByName(wsAttr);
313 if (attr.has_value())
314 return TryAttribute(attr.value().attribute, bUseDefault);
315 return GetMapModuleString(GetMapKey_Custom(wsAttr));
316 }
317
RemoveAttribute(WideStringView wsAttr)318 void CJX_Object::RemoveAttribute(WideStringView wsAttr) {
319 void* pKey = GetMapKey_Custom(wsAttr);
320 if (pKey)
321 RemoveMapModuleKey(pKey);
322 }
323
TryBoolean(XFA_Attribute eAttr,bool bUseDefault)324 Optional<bool> CJX_Object::TryBoolean(XFA_Attribute eAttr, bool bUseDefault) {
325 void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
326 Optional<void*> value = GetMapModuleValue(pKey);
327 if (value.has_value())
328 return !!value.value();
329 if (!bUseDefault)
330 return {};
331 return ToNode(GetXFAObject())->GetDefaultBoolean(eAttr);
332 }
333
SetBoolean(XFA_Attribute eAttr,bool bValue,bool bNotify)334 void CJX_Object::SetBoolean(XFA_Attribute eAttr, bool bValue, bool bNotify) {
335 CFX_XMLElement* elem = SetValue(eAttr, (void*)(uintptr_t)bValue, bNotify);
336 if (elem) {
337 elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
338 bValue ? L"1" : L"0");
339 }
340 }
341
GetBoolean(XFA_Attribute eAttr)342 bool CJX_Object::GetBoolean(XFA_Attribute eAttr) {
343 return TryBoolean(eAttr, true).value_or(false);
344 }
345
SetInteger(XFA_Attribute eAttr,int32_t iValue,bool bNotify)346 void CJX_Object::SetInteger(XFA_Attribute eAttr, int32_t iValue, bool bNotify) {
347 CFX_XMLElement* elem = SetValue(eAttr, (void*)(uintptr_t)iValue, bNotify);
348 if (elem) {
349 elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
350 WideString::Format(L"%d", iValue));
351 }
352 }
353
GetInteger(XFA_Attribute eAttr) const354 int32_t CJX_Object::GetInteger(XFA_Attribute eAttr) const {
355 return TryInteger(eAttr, true).value_or(0);
356 }
357
TryInteger(XFA_Attribute eAttr,bool bUseDefault) const358 Optional<int32_t> CJX_Object::TryInteger(XFA_Attribute eAttr,
359 bool bUseDefault) const {
360 void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
361 Optional<void*> value = GetMapModuleValue(pKey);
362 if (value.has_value())
363 return static_cast<int32_t>(reinterpret_cast<uintptr_t>(value.value()));
364 if (!bUseDefault)
365 return {};
366 return ToNode(GetXFAObject())->GetDefaultInteger(eAttr);
367 }
368
TryEnum(XFA_Attribute eAttr,bool bUseDefault) const369 Optional<XFA_AttributeValue> CJX_Object::TryEnum(XFA_Attribute eAttr,
370 bool bUseDefault) const {
371 void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
372 Optional<void*> value = GetMapModuleValue(pKey);
373 if (value.has_value()) {
374 return static_cast<XFA_AttributeValue>(
375 reinterpret_cast<uintptr_t>(value.value()));
376 }
377 if (!bUseDefault)
378 return {};
379 return ToNode(GetXFAObject())->GetDefaultEnum(eAttr);
380 }
381
SetEnum(XFA_Attribute eAttr,XFA_AttributeValue eValue,bool bNotify)382 void CJX_Object::SetEnum(XFA_Attribute eAttr,
383 XFA_AttributeValue eValue,
384 bool bNotify) {
385 CFX_XMLElement* elem = SetValue(eAttr, (void*)(uintptr_t)eValue, bNotify);
386 if (elem) {
387 elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
388 WideString::FromASCII(XFA_AttributeValueToName(eValue)));
389 }
390 }
391
GetEnum(XFA_Attribute eAttr) const392 XFA_AttributeValue CJX_Object::GetEnum(XFA_Attribute eAttr) const {
393 return TryEnum(eAttr, true).value_or(XFA_AttributeValue::Unknown);
394 }
395
SetMeasure(XFA_Attribute eAttr,CXFA_Measurement mValue,bool bNotify)396 void CJX_Object::SetMeasure(XFA_Attribute eAttr,
397 CXFA_Measurement mValue,
398 bool bNotify) {
399 void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
400 OnChanging(eAttr, bNotify);
401 SetMapModuleBuffer(pKey, &mValue, sizeof(CXFA_Measurement), nullptr);
402 OnChanged(eAttr, bNotify, false);
403 }
404
TryMeasure(XFA_Attribute eAttr,bool bUseDefault) const405 Optional<CXFA_Measurement> CJX_Object::TryMeasure(XFA_Attribute eAttr,
406 bool bUseDefault) const {
407 void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
408 void* pValue;
409 int32_t iBytes;
410 if (GetMapModuleBuffer(pKey, &pValue, &iBytes) &&
411 iBytes == sizeof(CXFA_Measurement)) {
412 return *static_cast<CXFA_Measurement*>(pValue);
413 }
414 if (!bUseDefault)
415 return {};
416 return ToNode(GetXFAObject())->GetDefaultMeasurement(eAttr);
417 }
418
TryMeasureAsFloat(XFA_Attribute attr) const419 Optional<float> CJX_Object::TryMeasureAsFloat(XFA_Attribute attr) const {
420 Optional<CXFA_Measurement> measure = TryMeasure(attr, false);
421 if (measure)
422 return measure->ToUnit(XFA_Unit::Pt);
423 return {};
424 }
425
GetMeasure(XFA_Attribute eAttr) const426 CXFA_Measurement CJX_Object::GetMeasure(XFA_Attribute eAttr) const {
427 return TryMeasure(eAttr, true).value_or(CXFA_Measurement());
428 }
429
GetMeasureInUnit(XFA_Attribute eAttr,XFA_Unit unit) const430 float CJX_Object::GetMeasureInUnit(XFA_Attribute eAttr, XFA_Unit unit) const {
431 auto measure = TryMeasure(eAttr, true).value_or(CXFA_Measurement());
432 return measure.ToUnit(unit);
433 }
434
GetCData(XFA_Attribute eAttr) const435 WideString CJX_Object::GetCData(XFA_Attribute eAttr) const {
436 return TryCData(eAttr, true).value_or(WideString());
437 }
438
SetCData(XFA_Attribute eAttr,const WideString & wsValue,bool bNotify,bool bScriptModify)439 void CJX_Object::SetCData(XFA_Attribute eAttr,
440 const WideString& wsValue,
441 bool bNotify,
442 bool bScriptModify) {
443 CXFA_Node* xfaObj = ToNode(GetXFAObject());
444 void* pKey = GetMapKey_Element(xfaObj->GetElementType(), eAttr);
445 OnChanging(eAttr, bNotify);
446 if (eAttr == XFA_Attribute::Value) {
447 WideString* pClone = new WideString(wsValue);
448 SetUserData(pKey, pClone, &deleteWideStringCallBack);
449 } else {
450 SetMapModuleString(pKey, wsValue.AsStringView());
451 if (eAttr == XFA_Attribute::Name)
452 xfaObj->UpdateNameHash();
453 }
454 OnChanged(eAttr, bNotify, bScriptModify);
455
456 if (!xfaObj->IsNeedSavingXMLNode() || eAttr == XFA_Attribute::QualifiedName ||
457 eAttr == XFA_Attribute::BindingNode) {
458 return;
459 }
460
461 if (eAttr == XFA_Attribute::Name &&
462 (xfaObj->GetElementType() == XFA_Element::DataValue ||
463 xfaObj->GetElementType() == XFA_Element::DataGroup)) {
464 return;
465 }
466
467 if (eAttr == XFA_Attribute::Value) {
468 xfaObj->SetToXML(wsValue);
469 return;
470 }
471
472 WideString wsAttrName = WideString::FromASCII(XFA_AttributeToName(eAttr));
473 if (eAttr == XFA_Attribute::ContentType)
474 wsAttrName = L"xfa:" + wsAttrName;
475
476 CFX_XMLElement* elem = ToXMLElement(xfaObj->GetXMLMappingNode());
477 elem->SetAttribute(wsAttrName, wsValue);
478 return;
479 }
480
SetAttributeValue(const WideString & wsValue,const WideString & wsXMLValue,bool bNotify,bool bScriptModify)481 void CJX_Object::SetAttributeValue(const WideString& wsValue,
482 const WideString& wsXMLValue,
483 bool bNotify,
484 bool bScriptModify) {
485 auto* xfaObj = ToNode(GetXFAObject());
486 void* pKey =
487 GetMapKey_Element(xfaObj->GetElementType(), XFA_Attribute::Value);
488
489 OnChanging(XFA_Attribute::Value, bNotify);
490 WideString* pClone = new WideString(wsValue);
491
492 SetUserData(pKey, pClone, &deleteWideStringCallBack);
493 OnChanged(XFA_Attribute::Value, bNotify, bScriptModify);
494
495 if (!xfaObj->IsNeedSavingXMLNode())
496 return;
497
498 xfaObj->SetToXML(wsXMLValue);
499 }
500
TryCData(XFA_Attribute eAttr,bool bUseDefault) const501 Optional<WideString> CJX_Object::TryCData(XFA_Attribute eAttr,
502 bool bUseDefault) const {
503 void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
504 if (eAttr == XFA_Attribute::Value) {
505 void* pData;
506 int32_t iBytes = 0;
507 WideString* pStr = nullptr;
508 if (GetMapModuleBuffer(pKey, &pData, &iBytes) && iBytes == sizeof(void*)) {
509 memcpy(&pData, pData, iBytes);
510 pStr = reinterpret_cast<WideString*>(pData);
511 }
512 if (pStr)
513 return *pStr;
514 } else {
515 Optional<WideString> value = GetMapModuleString(pKey);
516 if (value.has_value())
517 return value;
518 }
519 if (!bUseDefault)
520 return {};
521 return ToNode(GetXFAObject())->GetDefaultCData(eAttr);
522 }
523
SetValue(XFA_Attribute eAttr,void * pValue,bool bNotify)524 CFX_XMLElement* CJX_Object::SetValue(XFA_Attribute eAttr,
525 void* pValue,
526 bool bNotify) {
527 void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
528 OnChanging(eAttr, bNotify);
529 SetMapModuleValue(pKey, pValue);
530 OnChanged(eAttr, bNotify, false);
531
532 CXFA_Node* pNode = ToNode(GetXFAObject());
533 return pNode->IsNeedSavingXMLNode() ? ToXMLElement(pNode->GetXMLMappingNode())
534 : nullptr;
535 }
536
SetContent(const WideString & wsContent,const WideString & wsXMLValue,bool bNotify,bool bScriptModify,bool bSyncData)537 void CJX_Object::SetContent(const WideString& wsContent,
538 const WideString& wsXMLValue,
539 bool bNotify,
540 bool bScriptModify,
541 bool bSyncData) {
542 CXFA_Node* pNode = nullptr;
543 CXFA_Node* pBindNode = nullptr;
544 switch (ToNode(GetXFAObject())->GetObjectType()) {
545 case XFA_ObjectType::ContainerNode: {
546 if (XFA_FieldIsMultiListBox(ToNode(GetXFAObject()))) {
547 CXFA_Value* pValue =
548 GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
549 if (!pValue)
550 break;
551
552 CXFA_Node* pChildValue = pValue->GetFirstChild();
553 pChildValue->JSObject()->SetCData(XFA_Attribute::ContentType,
554 L"text/xml", false, false);
555 pChildValue->JSObject()->SetContent(wsContent, wsContent, bNotify,
556 bScriptModify, false);
557
558 CXFA_Node* pBind = ToNode(GetXFAObject())->GetBindData();
559 if (bSyncData && pBind) {
560 std::vector<WideString> wsSaveTextArray =
561 fxcrt::Split(wsContent, L'\n');
562 std::vector<CXFA_Node*> valueNodes =
563 pBind->GetNodeListForType(XFA_Element::DataValue);
564
565 // Adusting node count might have side effects, do not trust that
566 // we'll ever actually get there.
567 size_t tries = 0;
568 while (valueNodes.size() != wsSaveTextArray.size()) {
569 if (++tries > 4)
570 return;
571 if (valueNodes.size() < wsSaveTextArray.size()) {
572 size_t iAddNodes = wsSaveTextArray.size() - valueNodes.size();
573 while (iAddNodes-- > 0) {
574 CXFA_Node* pValueNodes =
575 pBind->CreateSamePacketNode(XFA_Element::DataValue);
576 pValueNodes->JSObject()->SetCData(XFA_Attribute::Name, L"value",
577 false, false);
578 pValueNodes->CreateXMLMappingNode();
579 pBind->InsertChildAndNotify(pValueNodes, nullptr);
580 }
581 } else {
582 size_t iDelNodes = valueNodes.size() - wsSaveTextArray.size();
583 for (size_t i = 0; i < iDelNodes; ++i)
584 pBind->RemoveChildAndNotify(valueNodes[i], true);
585 }
586 valueNodes = pBind->GetNodeListForType(XFA_Element::DataValue);
587 }
588 ASSERT(valueNodes.size() == wsSaveTextArray.size());
589 size_t i = 0;
590 for (CXFA_Node* pValueNode : valueNodes) {
591 pValueNode->JSObject()->SetAttributeValue(
592 wsSaveTextArray[i], wsSaveTextArray[i], false, false);
593 i++;
594 }
595 for (auto* pArrayNode : pBind->GetBindItemsCopy()) {
596 if (pArrayNode != ToNode(GetXFAObject())) {
597 pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
598 bScriptModify, false);
599 }
600 }
601 }
602 break;
603 }
604 if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::ExclGroup) {
605 pNode = ToNode(GetXFAObject());
606 } else {
607 CXFA_Value* pValue =
608 GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
609 if (!pValue)
610 break;
611
612 CXFA_Node* pChildValue = pValue->GetFirstChild();
613 ASSERT(pChildValue);
614 pChildValue->JSObject()->SetContent(wsContent, wsContent, bNotify,
615 bScriptModify, false);
616 }
617 pBindNode = ToNode(GetXFAObject())->GetBindData();
618 if (pBindNode && bSyncData) {
619 pBindNode->JSObject()->SetContent(wsContent, wsXMLValue, bNotify,
620 bScriptModify, false);
621 for (auto* pArrayNode : pBindNode->GetBindItemsCopy()) {
622 if (pArrayNode != ToNode(GetXFAObject())) {
623 pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
624 true, false);
625 }
626 }
627 }
628 pBindNode = nullptr;
629 break;
630 }
631 case XFA_ObjectType::ContentNode: {
632 WideString wsContentType;
633 if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::ExData) {
634 Optional<WideString> ret =
635 TryAttribute(XFA_Attribute::ContentType, false);
636 if (ret)
637 wsContentType = *ret;
638 if (wsContentType.EqualsASCII("text/html")) {
639 wsContentType.clear();
640 SetAttribute(XFA_Attribute::ContentType, wsContentType.AsStringView(),
641 false);
642 }
643 }
644
645 CXFA_Node* pContentRawDataNode = ToNode(GetXFAObject())->GetFirstChild();
646 if (!pContentRawDataNode) {
647 pContentRawDataNode =
648 ToNode(GetXFAObject())
649 ->CreateSamePacketNode(wsContentType.EqualsASCII("text/xml")
650 ? XFA_Element::Sharpxml
651 : XFA_Element::Sharptext);
652 ToNode(GetXFAObject())
653 ->InsertChildAndNotify(pContentRawDataNode, nullptr);
654 }
655 pContentRawDataNode->JSObject()->SetContent(
656 wsContent, wsXMLValue, bNotify, bScriptModify, bSyncData);
657 return;
658 }
659 case XFA_ObjectType::NodeC:
660 case XFA_ObjectType::TextNode:
661 pNode = ToNode(GetXFAObject());
662 break;
663 case XFA_ObjectType::NodeV:
664 pNode = ToNode(GetXFAObject());
665 if (bSyncData &&
666 ToNode(GetXFAObject())->GetPacketType() == XFA_PacketType::Form) {
667 CXFA_Node* pParent = ToNode(GetXFAObject())->GetParent();
668 if (pParent) {
669 pParent = pParent->GetParent();
670 }
671 if (pParent && pParent->GetElementType() == XFA_Element::Value) {
672 pParent = pParent->GetParent();
673 if (pParent && pParent->IsContainerNode()) {
674 pBindNode = pParent->GetBindData();
675 if (pBindNode) {
676 pBindNode->JSObject()->SetContent(wsContent, wsXMLValue, bNotify,
677 bScriptModify, false);
678 }
679 }
680 }
681 }
682 break;
683 default:
684 if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::DataValue) {
685 pNode = ToNode(GetXFAObject());
686 pBindNode = ToNode(GetXFAObject());
687 }
688 break;
689 }
690 if (!pNode)
691 return;
692
693 SetAttributeValue(wsContent, wsXMLValue, bNotify, bScriptModify);
694 if (pBindNode && bSyncData) {
695 for (auto* pArrayNode : pBindNode->GetBindItemsCopy()) {
696 pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
697 bScriptModify, false);
698 }
699 }
700 }
701
GetContent(bool bScriptModify)702 WideString CJX_Object::GetContent(bool bScriptModify) {
703 return TryContent(bScriptModify, true).value_or(WideString());
704 }
705
TryContent(bool bScriptModify,bool bProto)706 Optional<WideString> CJX_Object::TryContent(bool bScriptModify, bool bProto) {
707 CXFA_Node* pNode = nullptr;
708 switch (ToNode(GetXFAObject())->GetObjectType()) {
709 case XFA_ObjectType::ContainerNode:
710 if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::ExclGroup) {
711 pNode = ToNode(GetXFAObject());
712 } else {
713 CXFA_Value* pValue =
714 ToNode(GetXFAObject())
715 ->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
716 if (!pValue)
717 return {};
718
719 CXFA_Node* pChildValue = pValue->GetFirstChild();
720 if (pChildValue && XFA_FieldIsMultiListBox(ToNode(GetXFAObject()))) {
721 pChildValue->JSObject()->SetAttribute(XFA_Attribute::ContentType,
722 L"text/xml", false);
723 }
724 if (pChildValue)
725 return pChildValue->JSObject()->TryContent(bScriptModify, bProto);
726 return {};
727 }
728 break;
729 case XFA_ObjectType::ContentNode: {
730 CXFA_Node* pContentRawDataNode = ToNode(GetXFAObject())->GetFirstChild();
731 if (!pContentRawDataNode) {
732 XFA_Element element = XFA_Element::Sharptext;
733 if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::ExData) {
734 Optional<WideString> contentType =
735 TryAttribute(XFA_Attribute::ContentType, false);
736 if (contentType.has_value()) {
737 if (contentType.value().EqualsASCII("text/html"))
738 element = XFA_Element::SharpxHTML;
739 else if (contentType.value().EqualsASCII("text/xml"))
740 element = XFA_Element::Sharpxml;
741 }
742 }
743 pContentRawDataNode =
744 ToNode(GetXFAObject())->CreateSamePacketNode(element);
745 ToNode(GetXFAObject())
746 ->InsertChildAndNotify(pContentRawDataNode, nullptr);
747 }
748 return pContentRawDataNode->JSObject()->TryContent(bScriptModify, true);
749 }
750 case XFA_ObjectType::NodeC:
751 case XFA_ObjectType::NodeV:
752 case XFA_ObjectType::TextNode:
753 pNode = ToNode(GetXFAObject());
754 FALLTHROUGH;
755 default:
756 if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::DataValue)
757 pNode = ToNode(GetXFAObject());
758 break;
759 }
760 if (pNode) {
761 if (bScriptModify) {
762 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
763 pScriptContext->AddNodesOfRunScript(ToNode(GetXFAObject()));
764 }
765 return TryCData(XFA_Attribute::Value, false);
766 }
767 return {};
768 }
769
TryNamespace()770 Optional<WideString> CJX_Object::TryNamespace() {
771 if (ToNode(GetXFAObject())->IsModelNode() ||
772 ToNode(GetXFAObject())->GetElementType() == XFA_Element::Packet) {
773 CFX_XMLNode* pXMLNode = ToNode(GetXFAObject())->GetXMLMappingNode();
774 CFX_XMLElement* element = ToXMLElement(pXMLNode);
775 if (!element)
776 return {};
777
778 return element->GetNamespaceURI();
779 }
780
781 if (ToNode(GetXFAObject())->GetPacketType() != XFA_PacketType::Datasets)
782 return ToNode(GetXFAObject())->GetModelNode()->JSObject()->TryNamespace();
783
784 CFX_XMLNode* pXMLNode = ToNode(GetXFAObject())->GetXMLMappingNode();
785 CFX_XMLElement* element = ToXMLElement(pXMLNode);
786 if (!element)
787 return {};
788
789 if (ToNode(GetXFAObject())->GetElementType() == XFA_Element::DataValue &&
790 GetEnum(XFA_Attribute::Contains) == XFA_AttributeValue::MetaData) {
791 WideString wsNamespace;
792 if (!XFA_FDEExtension_ResolveNamespaceQualifier(
793 element, GetCData(XFA_Attribute::QualifiedName), &wsNamespace)) {
794 return {};
795 }
796 return wsNamespace;
797 }
798 return element->GetNamespaceURI();
799 }
800
GetPropertyInternal(int32_t index,XFA_Element eProperty) const801 std::pair<CXFA_Node*, int32_t> CJX_Object::GetPropertyInternal(
802 int32_t index,
803 XFA_Element eProperty) const {
804 return ToNode(GetXFAObject())->GetProperty(index, eProperty);
805 }
806
GetOrCreatePropertyInternal(int32_t index,XFA_Element eProperty)807 CXFA_Node* CJX_Object::GetOrCreatePropertyInternal(int32_t index,
808 XFA_Element eProperty) {
809 return ToNode(GetXFAObject())->GetOrCreateProperty(index, eProperty);
810 }
811
SetUserData(void * pKey,void * pData,const XFA_MAPDATABLOCKCALLBACKINFO * pCallbackInfo)812 void CJX_Object::SetUserData(
813 void* pKey,
814 void* pData,
815 const XFA_MAPDATABLOCKCALLBACKINFO* pCallbackInfo) {
816 ASSERT(pCallbackInfo);
817 SetMapModuleBuffer(pKey, &pData, sizeof(void*), pCallbackInfo);
818 }
819
CreateMapModuleData()820 XFA_MAPMODULEDATA* CJX_Object::CreateMapModuleData() {
821 if (!map_module_data_)
822 map_module_data_ = pdfium::MakeUnique<XFA_MAPMODULEDATA>();
823 return map_module_data_.get();
824 }
825
GetMapModuleData() const826 XFA_MAPMODULEDATA* CJX_Object::GetMapModuleData() const {
827 return map_module_data_.get();
828 }
829
SetMapModuleValue(void * pKey,void * pValue)830 void CJX_Object::SetMapModuleValue(void* pKey, void* pValue) {
831 CreateMapModuleData()->m_ValueMap[pKey] = pValue;
832 }
833
GetMapModuleValue(void * pKey) const834 Optional<void*> CJX_Object::GetMapModuleValue(void* pKey) const {
835 std::set<const CXFA_Node*> visited;
836 for (const CXFA_Node* pNode = ToNode(GetXFAObject()); pNode;
837 pNode = pNode->GetTemplateNodeIfExists()) {
838 if (!visited.insert(pNode).second)
839 break;
840
841 XFA_MAPMODULEDATA* pModule = pNode->JSObject()->GetMapModuleData();
842 if (pModule) {
843 auto it = pModule->m_ValueMap.find(pKey);
844 if (it != pModule->m_ValueMap.end())
845 return it->second;
846 }
847 if (pNode->GetPacketType() == XFA_PacketType::Datasets)
848 break;
849 }
850 return {};
851 }
852
GetMapModuleString(void * pKey) const853 Optional<WideString> CJX_Object::GetMapModuleString(void* pKey) const {
854 void* pRawValue;
855 int32_t iBytes;
856 if (!GetMapModuleBuffer(pKey, &pRawValue, &iBytes))
857 return {};
858
859 // Defensive measure: no out-of-bounds pointers even if zero length.
860 int32_t iChars = iBytes / sizeof(wchar_t);
861 return WideString(iChars ? static_cast<const wchar_t*>(pRawValue) : nullptr,
862 iChars);
863 }
864
SetMapModuleBuffer(void * pKey,void * pValue,int32_t iBytes,const XFA_MAPDATABLOCKCALLBACKINFO * pCallbackInfo)865 void CJX_Object::SetMapModuleBuffer(
866 void* pKey,
867 void* pValue,
868 int32_t iBytes,
869 const XFA_MAPDATABLOCKCALLBACKINFO* pCallbackInfo) {
870 XFA_MAPDATABLOCK*& pBuffer = CreateMapModuleData()->m_BufferMap[pKey];
871 if (!pBuffer) {
872 pBuffer = reinterpret_cast<XFA_MAPDATABLOCK*>(
873 FX_Alloc(uint8_t, sizeof(XFA_MAPDATABLOCK) + iBytes));
874 } else if (pBuffer->iBytes != iBytes) {
875 if (pBuffer->pCallbackInfo && pBuffer->pCallbackInfo->pFree)
876 pBuffer->pCallbackInfo->pFree(*(void**)pBuffer->GetData());
877
878 pBuffer = reinterpret_cast<XFA_MAPDATABLOCK*>(
879 FX_Realloc(uint8_t, pBuffer, sizeof(XFA_MAPDATABLOCK) + iBytes));
880 } else if (pBuffer->pCallbackInfo && pBuffer->pCallbackInfo->pFree) {
881 pBuffer->pCallbackInfo->pFree(
882 *reinterpret_cast<void**>(pBuffer->GetData()));
883 }
884 if (!pBuffer)
885 return;
886
887 pBuffer->pCallbackInfo = pCallbackInfo;
888 pBuffer->iBytes = iBytes;
889 memcpy(pBuffer->GetData(), pValue, iBytes);
890 }
891
GetMapModuleBuffer(void * pKey,void ** pValue,int32_t * pBytes) const892 bool CJX_Object::GetMapModuleBuffer(void* pKey,
893 void** pValue,
894 int32_t* pBytes) const {
895 std::set<const CXFA_Node*> visited;
896 XFA_MAPDATABLOCK* pBuffer = nullptr;
897 for (const CXFA_Node* pNode = ToNode(GetXFAObject()); pNode;
898 pNode = pNode->GetTemplateNodeIfExists()) {
899 if (!visited.insert(pNode).second)
900 break;
901
902 XFA_MAPMODULEDATA* pModule = pNode->JSObject()->GetMapModuleData();
903 if (pModule) {
904 auto it = pModule->m_BufferMap.find(pKey);
905 if (it != pModule->m_BufferMap.end()) {
906 pBuffer = it->second;
907 break;
908 }
909 }
910 if (pNode->GetPacketType() == XFA_PacketType::Datasets)
911 break;
912 }
913 if (!pBuffer)
914 return false;
915
916 *pValue = pBuffer->GetData();
917 *pBytes = pBuffer->iBytes;
918 return true;
919 }
920
HasMapModuleKey(void * pKey)921 bool CJX_Object::HasMapModuleKey(void* pKey) {
922 XFA_MAPMODULEDATA* pModule = GetMapModuleData();
923 return pModule && (pdfium::ContainsKey(pModule->m_ValueMap, pKey) ||
924 pdfium::ContainsKey(pModule->m_BufferMap, pKey));
925 }
926
ClearMapModuleBuffer()927 void CJX_Object::ClearMapModuleBuffer() {
928 XFA_MAPMODULEDATA* pModule = GetMapModuleData();
929 if (!pModule)
930 return;
931
932 for (auto& pair : pModule->m_BufferMap) {
933 XFA_MAPDATABLOCK* pBuffer = pair.second;
934 if (pBuffer) {
935 if (pBuffer->pCallbackInfo && pBuffer->pCallbackInfo->pFree)
936 pBuffer->pCallbackInfo->pFree(*(void**)pBuffer->GetData());
937
938 FX_Free(pBuffer);
939 }
940 }
941 pModule->m_BufferMap.clear();
942 pModule->m_ValueMap.clear();
943 }
944
RemoveMapModuleKey(void * pKey)945 void CJX_Object::RemoveMapModuleKey(void* pKey) {
946 ASSERT(pKey);
947
948 XFA_MAPMODULEDATA* pModule = GetMapModuleData();
949 if (!pModule)
950 return;
951
952 auto it = pModule->m_BufferMap.find(pKey);
953 if (it != pModule->m_BufferMap.end()) {
954 XFA_MAPDATABLOCK* pBuffer = it->second;
955 if (pBuffer) {
956 if (pBuffer->pCallbackInfo && pBuffer->pCallbackInfo->pFree)
957 pBuffer->pCallbackInfo->pFree(*(void**)pBuffer->GetData());
958
959 FX_Free(pBuffer);
960 }
961 pModule->m_BufferMap.erase(it);
962 }
963 pModule->m_ValueMap.erase(pKey);
964 return;
965 }
966
MergeAllData(CXFA_Object * pDstModule)967 void CJX_Object::MergeAllData(CXFA_Object* pDstModule) {
968 XFA_MAPMODULEDATA* pDstModuleData =
969 ToNode(pDstModule)->JSObject()->CreateMapModuleData();
970 XFA_MAPMODULEDATA* pSrcModuleData = GetMapModuleData();
971 if (!pSrcModuleData)
972 return;
973
974 for (const auto& pair : pSrcModuleData->m_ValueMap)
975 pDstModuleData->m_ValueMap[pair.first] = pair.second;
976
977 for (const auto& pair : pSrcModuleData->m_BufferMap) {
978 XFA_MAPDATABLOCK* pSrcBuffer = pair.second;
979 XFA_MAPDATABLOCK*& pDstBuffer = pDstModuleData->m_BufferMap[pair.first];
980 if (pSrcBuffer->pCallbackInfo && pSrcBuffer->pCallbackInfo->pFree &&
981 !pSrcBuffer->pCallbackInfo->pCopy) {
982 if (pDstBuffer) {
983 pDstBuffer->pCallbackInfo->pFree(*(void**)pDstBuffer->GetData());
984 pDstModuleData->m_BufferMap.erase(pair.first);
985 }
986 continue;
987 }
988 if (!pDstBuffer) {
989 pDstBuffer = (XFA_MAPDATABLOCK*)FX_Alloc(
990 uint8_t, sizeof(XFA_MAPDATABLOCK) + pSrcBuffer->iBytes);
991 } else if (pDstBuffer->iBytes != pSrcBuffer->iBytes) {
992 if (pDstBuffer->pCallbackInfo && pDstBuffer->pCallbackInfo->pFree) {
993 pDstBuffer->pCallbackInfo->pFree(*(void**)pDstBuffer->GetData());
994 }
995 pDstBuffer = (XFA_MAPDATABLOCK*)FX_Realloc(
996 uint8_t, pDstBuffer, sizeof(XFA_MAPDATABLOCK) + pSrcBuffer->iBytes);
997 } else if (pDstBuffer->pCallbackInfo && pDstBuffer->pCallbackInfo->pFree) {
998 pDstBuffer->pCallbackInfo->pFree(*(void**)pDstBuffer->GetData());
999 }
1000 if (!pDstBuffer)
1001 continue;
1002
1003 pDstBuffer->pCallbackInfo = pSrcBuffer->pCallbackInfo;
1004 pDstBuffer->iBytes = pSrcBuffer->iBytes;
1005 memcpy(pDstBuffer->GetData(), pSrcBuffer->GetData(), pSrcBuffer->iBytes);
1006 if (pDstBuffer->pCallbackInfo && pDstBuffer->pCallbackInfo->pCopy) {
1007 pDstBuffer->pCallbackInfo->pCopy(*(void**)pDstBuffer->GetData());
1008 }
1009 }
1010 }
1011
MoveBufferMapData(CXFA_Object * pDstModule)1012 void CJX_Object::MoveBufferMapData(CXFA_Object* pDstModule) {
1013 if (!pDstModule)
1014 return;
1015
1016 bool bNeedMove = true;
1017 if (pDstModule->GetElementType() != GetXFAObject()->GetElementType())
1018 bNeedMove = false;
1019
1020 if (bNeedMove)
1021 ToNode(pDstModule)->JSObject()->SetCalcData(ReleaseCalcData());
1022 if (!pDstModule->IsNodeV())
1023 return;
1024
1025 WideString wsValue = ToNode(pDstModule)->JSObject()->GetContent(false);
1026 WideString wsFormatValue(wsValue);
1027 CXFA_Node* pNode = ToNode(pDstModule)->GetContainerNode();
1028 if (pNode)
1029 wsFormatValue = pNode->GetFormatDataValue(wsValue);
1030
1031 ToNode(pDstModule)
1032 ->JSObject()
1033 ->SetContent(wsValue, wsFormatValue, true, true, true);
1034 }
1035
MoveBufferMapData(CXFA_Object * pSrcModule,CXFA_Object * pDstModule)1036 void CJX_Object::MoveBufferMapData(CXFA_Object* pSrcModule,
1037 CXFA_Object* pDstModule) {
1038 if (!pSrcModule || !pDstModule)
1039 return;
1040
1041 CXFA_Node* pSrcChild = ToNode(pSrcModule)->GetFirstChild();
1042 CXFA_Node* pDstChild = ToNode(pDstModule)->GetFirstChild();
1043 while (pSrcChild && pDstChild) {
1044 MoveBufferMapData(pSrcChild, pDstChild);
1045
1046 pSrcChild = pSrcChild->GetNextSibling();
1047 pDstChild = pDstChild->GetNextSibling();
1048 }
1049 ToNode(pSrcModule)->JSObject()->MoveBufferMapData(pDstModule);
1050 }
1051
OnChanging(XFA_Attribute eAttr,bool bNotify)1052 void CJX_Object::OnChanging(XFA_Attribute eAttr, bool bNotify) {
1053 if (!bNotify || !ToNode(GetXFAObject())->IsInitialized())
1054 return;
1055
1056 CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
1057 if (pNotify)
1058 pNotify->OnValueChanging(ToNode(GetXFAObject()), eAttr);
1059 }
1060
OnChanged(XFA_Attribute eAttr,bool bNotify,bool bScriptModify)1061 void CJX_Object::OnChanged(XFA_Attribute eAttr,
1062 bool bNotify,
1063 bool bScriptModify) {
1064 if (bNotify && ToNode(GetXFAObject())->IsInitialized())
1065 ToNode(GetXFAObject())->SendAttributeChangeMessage(eAttr, bScriptModify);
1066 }
1067
SetCalcData(std::unique_ptr<CXFA_CalcData> data)1068 void CJX_Object::SetCalcData(std::unique_ptr<CXFA_CalcData> data) {
1069 calc_data_ = std::move(data);
1070 }
1071
ReleaseCalcData()1072 std::unique_ptr<CXFA_CalcData> CJX_Object::ReleaseCalcData() {
1073 return std::move(calc_data_);
1074 }
1075
ScriptAttributeString(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1076 void CJX_Object::ScriptAttributeString(CFXJSE_Value* pValue,
1077 bool bSetting,
1078 XFA_Attribute eAttribute) {
1079 if (!bSetting) {
1080 pValue->SetString(GetAttribute(eAttribute).ToUTF8().AsStringView());
1081 return;
1082 }
1083
1084 WideString wsValue = pValue->ToWideString();
1085 SetAttribute(eAttribute, wsValue.AsStringView(), true);
1086 if (eAttribute != XFA_Attribute::Use ||
1087 GetXFAObject()->GetElementType() != XFA_Element::Desc) {
1088 return;
1089 }
1090
1091 CXFA_Node* pTemplateNode =
1092 ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Template));
1093 CXFA_Subform* pSubForm =
1094 pTemplateNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
1095 CXFA_Proto* pProtoRoot =
1096 pSubForm ? pSubForm->GetFirstChildByClass<CXFA_Proto>(XFA_Element::Proto)
1097 : nullptr;
1098
1099 WideString wsID;
1100 WideString wsSOM;
1101 if (!wsValue.IsEmpty()) {
1102 if (wsValue[0] == '#')
1103 wsID = wsValue.Substr(1, wsValue.GetLength() - 1);
1104 else
1105 wsSOM = std::move(wsValue);
1106 }
1107
1108 CXFA_Node* pProtoNode = nullptr;
1109 if (!wsSOM.IsEmpty()) {
1110 XFA_RESOLVENODE_RS resolveNodeRS;
1111 bool bRet = GetDocument()->GetScriptContext()->ResolveObjects(
1112 pProtoRoot, wsSOM.AsStringView(), &resolveNodeRS,
1113 XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
1114 XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
1115 XFA_RESOLVENODE_Siblings,
1116 nullptr);
1117 if (bRet && resolveNodeRS.objects.front()->IsNode())
1118 pProtoNode = resolveNodeRS.objects.front()->AsNode();
1119
1120 } else if (!wsID.IsEmpty()) {
1121 pProtoNode = GetDocument()->GetNodeByID(pProtoRoot, wsID.AsStringView());
1122 }
1123 if (!pProtoNode)
1124 return;
1125
1126 CXFA_Node* pHeadChild = ToNode(GetXFAObject())->GetFirstChild();
1127 while (pHeadChild) {
1128 CXFA_Node* pSibling = pHeadChild->GetNextSibling();
1129 ToNode(GetXFAObject())->RemoveChildAndNotify(pHeadChild, true);
1130 pHeadChild = pSibling;
1131 }
1132
1133 CXFA_Node* pProtoForm = pProtoNode->CloneTemplateToForm(true);
1134 pHeadChild = pProtoForm->GetFirstChild();
1135 while (pHeadChild) {
1136 CXFA_Node* pSibling = pHeadChild->GetNextSibling();
1137 pProtoForm->RemoveChildAndNotify(pHeadChild, true);
1138 ToNode(GetXFAObject())->InsertChildAndNotify(pHeadChild, nullptr);
1139 pHeadChild = pSibling;
1140 }
1141 }
1142
ScriptAttributeBool(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1143 void CJX_Object::ScriptAttributeBool(CFXJSE_Value* pValue,
1144 bool bSetting,
1145 XFA_Attribute eAttribute) {
1146 if (bSetting) {
1147 SetBoolean(eAttribute, pValue->ToBoolean(), true);
1148 return;
1149 }
1150 pValue->SetString(GetBoolean(eAttribute) ? "1" : "0");
1151 }
1152
ScriptAttributeInteger(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1153 void CJX_Object::ScriptAttributeInteger(CFXJSE_Value* pValue,
1154 bool bSetting,
1155 XFA_Attribute eAttribute) {
1156 if (bSetting) {
1157 SetInteger(eAttribute, pValue->ToInteger(), true);
1158 return;
1159 }
1160 pValue->SetInteger(GetInteger(eAttribute));
1161 }
1162
ScriptSomFontColor(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1163 void CJX_Object::ScriptSomFontColor(CFXJSE_Value* pValue,
1164 bool bSetting,
1165 XFA_Attribute eAttribute) {
1166 CXFA_Font* font = ToNode(object_.Get())->GetOrCreateFontIfPossible();
1167 if (!font)
1168 return;
1169
1170 if (bSetting) {
1171 int32_t r;
1172 int32_t g;
1173 int32_t b;
1174 std::tie(r, g, b) = StrToRGB(pValue->ToWideString());
1175 FX_ARGB color = ArgbEncode(0xff, r, g, b);
1176 font->SetColor(color);
1177 return;
1178 }
1179
1180 int32_t a;
1181 int32_t r;
1182 int32_t g;
1183 int32_t b;
1184 std::tie(a, r, g, b) = ArgbDecode(font->GetColor());
1185 pValue->SetString(ByteString::Format("%d,%d,%d", r, g, b).AsStringView());
1186 }
1187
ScriptSomFillColor(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1188 void CJX_Object::ScriptSomFillColor(CFXJSE_Value* pValue,
1189 bool bSetting,
1190 XFA_Attribute eAttribute) {
1191 CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1192 CXFA_Fill* borderfill = border->GetOrCreateFillIfPossible();
1193 if (!borderfill)
1194 return;
1195
1196 if (bSetting) {
1197 int32_t r;
1198 int32_t g;
1199 int32_t b;
1200 std::tie(r, g, b) = StrToRGB(pValue->ToWideString());
1201 FX_ARGB color = ArgbEncode(0xff, r, g, b);
1202 borderfill->SetColor(color);
1203 return;
1204 }
1205
1206 FX_ARGB color = borderfill->GetColor(false);
1207 int32_t a;
1208 int32_t r;
1209 int32_t g;
1210 int32_t b;
1211 std::tie(a, r, g, b) = ArgbDecode(color);
1212 pValue->SetString(
1213 WideString::Format(L"%d,%d,%d", r, g, b).ToUTF8().AsStringView());
1214 }
1215
ScriptSomBorderColor(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1216 void CJX_Object::ScriptSomBorderColor(CFXJSE_Value* pValue,
1217 bool bSetting,
1218 XFA_Attribute eAttribute) {
1219 CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1220 int32_t iSize = border->CountEdges();
1221 if (bSetting) {
1222 int32_t r = 0;
1223 int32_t g = 0;
1224 int32_t b = 0;
1225 std::tie(r, g, b) = StrToRGB(pValue->ToWideString());
1226 FX_ARGB rgb = ArgbEncode(100, r, g, b);
1227 for (int32_t i = 0; i < iSize; ++i) {
1228 CXFA_Edge* edge = border->GetEdgeIfExists(i);
1229 if (edge)
1230 edge->SetColor(rgb);
1231 }
1232
1233 return;
1234 }
1235
1236 CXFA_Edge* edge = border->GetEdgeIfExists(0);
1237 FX_ARGB color = edge ? edge->GetColor() : CXFA_Edge::kDefaultColor;
1238 int32_t a;
1239 int32_t r;
1240 int32_t g;
1241 int32_t b;
1242 std::tie(a, r, g, b) = ArgbDecode(color);
1243 pValue->SetString(
1244 WideString::Format(L"%d,%d,%d", r, g, b).ToUTF8().AsStringView());
1245 }
1246
ScriptSomBorderWidth(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1247 void CJX_Object::ScriptSomBorderWidth(CFXJSE_Value* pValue,
1248 bool bSetting,
1249 XFA_Attribute eAttribute) {
1250 CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1251 if (bSetting) {
1252 CXFA_Edge* edge = border->GetEdgeIfExists(0);
1253 CXFA_Measurement thickness =
1254 edge ? edge->GetMSThickness() : CXFA_Measurement(0.5, XFA_Unit::Pt);
1255 pValue->SetString(thickness.ToString().ToUTF8().AsStringView());
1256 return;
1257 }
1258
1259 if (pValue->IsEmpty())
1260 return;
1261
1262 WideString wsThickness = pValue->ToWideString();
1263 for (int32_t i = 0; i < border->CountEdges(); ++i) {
1264 CXFA_Edge* edge = border->GetEdgeIfExists(i);
1265 if (edge)
1266 edge->SetMSThickness(CXFA_Measurement(wsThickness.AsStringView()));
1267 }
1268 }
1269
ScriptSomMessage(CFXJSE_Value * pValue,bool bSetting,XFA_SOM_MESSAGETYPE iMessageType)1270 void CJX_Object::ScriptSomMessage(CFXJSE_Value* pValue,
1271 bool bSetting,
1272 XFA_SOM_MESSAGETYPE iMessageType) {
1273 bool bNew = false;
1274 CXFA_Validate* validate = ToNode(object_.Get())->GetValidateIfExists();
1275 if (!validate) {
1276 validate = ToNode(object_.Get())->GetOrCreateValidateIfPossible();
1277 bNew = true;
1278 }
1279
1280 if (bSetting) {
1281 if (validate) {
1282 switch (iMessageType) {
1283 case XFA_SOM_ValidationMessage:
1284 validate->SetScriptMessageText(pValue->ToWideString());
1285 break;
1286 case XFA_SOM_FormatMessage:
1287 validate->SetFormatMessageText(pValue->ToWideString());
1288 break;
1289 case XFA_SOM_MandatoryMessage:
1290 validate->SetNullMessageText(pValue->ToWideString());
1291 break;
1292 default:
1293 break;
1294 }
1295 }
1296
1297 if (!bNew) {
1298 CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
1299 if (!pNotify)
1300 return;
1301
1302 pNotify->AddCalcValidate(ToNode(GetXFAObject()));
1303 }
1304 return;
1305 }
1306
1307 if (!validate) {
1308 // TODO(dsinclair): Better error message?
1309 ThrowInvalidPropertyException();
1310 return;
1311 }
1312
1313 WideString wsMessage;
1314 switch (iMessageType) {
1315 case XFA_SOM_ValidationMessage:
1316 wsMessage = validate->GetScriptMessageText();
1317 break;
1318 case XFA_SOM_FormatMessage:
1319 wsMessage = validate->GetFormatMessageText();
1320 break;
1321 case XFA_SOM_MandatoryMessage:
1322 wsMessage = validate->GetNullMessageText();
1323 break;
1324 default:
1325 break;
1326 }
1327 pValue->SetString(wsMessage.ToUTF8().AsStringView());
1328 }
1329
ScriptSomValidationMessage(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1330 void CJX_Object::ScriptSomValidationMessage(CFXJSE_Value* pValue,
1331 bool bSetting,
1332 XFA_Attribute eAttribute) {
1333 ScriptSomMessage(pValue, bSetting, XFA_SOM_ValidationMessage);
1334 }
1335
ScriptSomMandatoryMessage(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1336 void CJX_Object::ScriptSomMandatoryMessage(CFXJSE_Value* pValue,
1337 bool bSetting,
1338 XFA_Attribute eAttribute) {
1339 ScriptSomMessage(pValue, bSetting, XFA_SOM_MandatoryMessage);
1340 }
1341
ScriptSomDefaultValue(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute)1342 void CJX_Object::ScriptSomDefaultValue(CFXJSE_Value* pValue,
1343 bool bSetting,
1344 XFA_Attribute /* unused */) {
1345 XFA_Element eType = ToNode(GetXFAObject())->GetElementType();
1346
1347 // TODO(dsinclair): This should look through the properties on the node to see
1348 // if defaultValue is defined and, if so, call that one. Just have to make
1349 // sure that those defaultValue calls don't call back to this one ....
1350 if (eType == XFA_Element::Field) {
1351 static_cast<CJX_Field*>(this)->defaultValue(pValue, bSetting,
1352 XFA_Attribute::Unknown);
1353 return;
1354 }
1355 if (eType == XFA_Element::Draw) {
1356 static_cast<CJX_Draw*>(this)->defaultValue(pValue, bSetting,
1357 XFA_Attribute::Unknown);
1358 return;
1359 }
1360 if (eType == XFA_Element::Boolean) {
1361 static_cast<CJX_Boolean*>(this)->defaultValue(pValue, bSetting,
1362 XFA_Attribute::Unknown);
1363 return;
1364 }
1365
1366 if (bSetting) {
1367 WideString wsNewValue;
1368 if (pValue &&
1369 !(pValue->IsEmpty() || pValue->IsNull() || pValue->IsUndefined())) {
1370 wsNewValue = pValue->ToWideString();
1371 }
1372
1373 WideString wsFormatValue(wsNewValue);
1374 CXFA_Node* pContainerNode = nullptr;
1375 if (ToNode(GetXFAObject())->GetPacketType() == XFA_PacketType::Datasets) {
1376 WideString wsPicture;
1377 for (auto* pFormNode : ToNode(GetXFAObject())->GetBindItemsCopy()) {
1378 if (!pFormNode || pFormNode->HasRemovedChildren())
1379 continue;
1380
1381 pContainerNode = pFormNode->GetContainerNode();
1382 if (pContainerNode) {
1383 wsPicture =
1384 pContainerNode->GetPictureContent(XFA_VALUEPICTURE_DataBind);
1385 }
1386 if (!wsPicture.IsEmpty())
1387 break;
1388
1389 pContainerNode = nullptr;
1390 }
1391 } else if (ToNode(GetXFAObject())->GetPacketType() ==
1392 XFA_PacketType::Form) {
1393 pContainerNode = ToNode(GetXFAObject())->GetContainerNode();
1394 }
1395
1396 if (pContainerNode)
1397 wsFormatValue = pContainerNode->GetFormatDataValue(wsNewValue);
1398
1399 SetContent(wsNewValue, wsFormatValue, true, true, true);
1400 return;
1401 }
1402
1403 WideString content = GetContent(true);
1404 if (content.IsEmpty() && eType != XFA_Element::Text &&
1405 eType != XFA_Element::SubmitUrl) {
1406 pValue->SetNull();
1407 } else if (eType == XFA_Element::Integer) {
1408 pValue->SetInteger(FXSYS_wtoi(content.c_str()));
1409 } else if (eType == XFA_Element::Float || eType == XFA_Element::Decimal) {
1410 CFGAS_Decimal decimal(content.AsStringView());
1411 pValue->SetFloat(decimal.ToFloat());
1412 } else {
1413 pValue->SetString(content.ToUTF8().AsStringView());
1414 }
1415 }
1416
ScriptSomDefaultValue_Read(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1417 void CJX_Object::ScriptSomDefaultValue_Read(CFXJSE_Value* pValue,
1418 bool bSetting,
1419 XFA_Attribute eAttribute) {
1420 if (bSetting) {
1421 ThrowInvalidPropertyException();
1422 return;
1423 }
1424
1425 WideString content = GetContent(true);
1426 if (content.IsEmpty()) {
1427 pValue->SetNull();
1428 return;
1429 }
1430 pValue->SetString(content.ToUTF8().AsStringView());
1431 }
1432
ScriptSomDataNode(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1433 void CJX_Object::ScriptSomDataNode(CFXJSE_Value* pValue,
1434 bool bSetting,
1435 XFA_Attribute eAttribute) {
1436 if (bSetting) {
1437 ThrowInvalidPropertyException();
1438 return;
1439 }
1440
1441 CXFA_Node* pDataNode = ToNode(GetXFAObject())->GetBindData();
1442 if (!pDataNode) {
1443 pValue->SetNull();
1444 return;
1445 }
1446
1447 pValue->Assign(GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(
1448 pDataNode));
1449 }
1450
ScriptSomMandatory(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1451 void CJX_Object::ScriptSomMandatory(CFXJSE_Value* pValue,
1452 bool bSetting,
1453 XFA_Attribute eAttribute) {
1454 CXFA_Validate* validate =
1455 ToNode(object_.Get())->GetOrCreateValidateIfPossible();
1456 if (!validate)
1457 return;
1458
1459 if (bSetting) {
1460 validate->SetNullTest(pValue->ToWideString());
1461 return;
1462 }
1463
1464 pValue->SetString(XFA_AttributeValueToName(validate->GetNullTest()));
1465 }
1466
ScriptSomInstanceIndex(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1467 void CJX_Object::ScriptSomInstanceIndex(CFXJSE_Value* pValue,
1468 bool bSetting,
1469 XFA_Attribute eAttribute) {
1470 if (!bSetting) {
1471 pValue->SetInteger(Subform_and_SubformSet_InstanceIndex());
1472 return;
1473 }
1474
1475 int32_t iTo = pValue->ToInteger();
1476 int32_t iFrom = Subform_and_SubformSet_InstanceIndex();
1477 CXFA_Node* pManagerNode = nullptr;
1478 for (CXFA_Node* pNode = ToNode(GetXFAObject())->GetPrevSibling(); pNode;
1479 pNode = pNode->GetPrevSibling()) {
1480 if (pNode->GetElementType() == XFA_Element::InstanceManager) {
1481 pManagerNode = pNode;
1482 break;
1483 }
1484 }
1485 if (!pManagerNode)
1486 return;
1487
1488 auto* mgr = static_cast<CJX_InstanceManager*>(pManagerNode->JSObject());
1489 mgr->MoveInstance(iTo, iFrom);
1490 CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
1491 if (!pNotify)
1492 return;
1493
1494 CXFA_Node* pToInstance = pManagerNode->GetItemIfExists(iTo);
1495 if (pToInstance && pToInstance->GetElementType() == XFA_Element::Subform) {
1496 pNotify->RunSubformIndexChange(pToInstance);
1497 }
1498
1499 CXFA_Node* pFromInstance = pManagerNode->GetItemIfExists(iFrom);
1500 if (pFromInstance &&
1501 pFromInstance->GetElementType() == XFA_Element::Subform) {
1502 pNotify->RunSubformIndexChange(pFromInstance);
1503 }
1504 }
1505
ScriptSubmitFormatMode(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1506 void CJX_Object::ScriptSubmitFormatMode(CFXJSE_Value* pValue,
1507 bool bSetting,
1508 XFA_Attribute eAttribute) {}
1509