• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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