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