Home | History | Annotate | Download | only in xfa
      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 
     42 namespace {
     43 
     44 void XFA_DeleteWideString(void* pData) {
     45   delete static_cast<WideString*>(pData);
     46 }
     47 
     48 void XFA_CopyWideString(void*& pData) {
     49   if (!pData)
     50     return;
     51   pData = new WideString(*reinterpret_cast<WideString*>(pData));
     52 }
     53 
     54 XFA_MAPDATABLOCKCALLBACKINFO deleteWideStringCallBack = {XFA_DeleteWideString,
     55                                                          XFA_CopyWideString};
     56 
     57 enum XFA_KEYTYPE {
     58   XFA_KEYTYPE_Custom,
     59   XFA_KEYTYPE_Element,
     60 };
     61 
     62 void* 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 
     67 void* 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 
     73 void XFA_DefaultFreeData(void* pData) {}
     74 
     75 XFA_MAPDATABLOCKCALLBACKINFO gs_XFADefaultFreeData = {XFA_DefaultFreeData,
     76                                                       nullptr};
     77 
     78 std::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 
    111 struct 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 
    118 struct 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 
    126 CJX_Object::CJX_Object(CXFA_Object* obj) : object_(obj) {}
    127 
    128 CJX_Object::~CJX_Object() {
    129   ClearMapModuleBuffer();
    130 }
    131 
    132 void 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 
    138 CXFA_Document* CJX_Object::GetDocument() const {
    139   return object_->GetDocument();
    140 }
    141 
    142 void 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 
    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 
    166 bool CJX_Object::HasMethod(const WideString& func) const {
    167   return pdfium::ContainsKey(method_specs_, func.UTF8Encode());
    168 }
    169 
    170 CJS_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 
    180 void 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 
    186 void CJX_Object::ThrowInvalidPropertyException() const {
    187   ThrowException(L"Invalid property set operation.");
    188 }
    189 
    190 void CJX_Object::ThrowIndexOutOfBoundsException() const {
    191   ThrowException(L"Index value is out of bounds.");
    192 }
    193 
    194 void CJX_Object::ThrowParamCountMismatchException(
    195     const WideString& method) const {
    196   ThrowException(L"Incorrect number of parameters calling method '%.16s'.",
    197                  method.c_str());
    198 }
    199 
    200 void CJX_Object::ThrowArgumentMismatchException() const {
    201   ThrowException(L"Argument mismatch in property or function argument.");
    202 }
    203 
    204 void 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 
    214 bool CJX_Object::HasAttribute(XFA_Attribute eAttr) {
    215   void* pKey = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
    216   return HasMapModuleKey(pKey);
    217 }
    218 
    219 bool 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 
    248 void 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 
    253 bool 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 
    265 WideString CJX_Object::GetAttribute(const WideStringView& attr) {
    266   return TryAttribute(attr, true).value_or(WideString());
    267 }
    268 
    269 WideString CJX_Object::GetAttribute(XFA_Attribute attr) {
    270   return TryAttribute(attr, true).value_or(WideString());
    271 }
    272 
    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_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 
    311 Optional<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 
    325 void CJX_Object::RemoveAttribute(const WideStringView& wsAttr) {
    326   void* pKey = GetMapKey_Custom(wsAttr);
    327   if (pKey)
    328     RemoveMapModuleKey(pKey);
    329 }
    330 
    331 Optional<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 
    342 bool 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 
    350 bool CJX_Object::GetBoolean(XFA_Attribute eAttr) {
    351   return TryBoolean(eAttr, true).value_or(false);
    352 }
    353 
    354 bool 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 
    364 int32_t CJX_Object::GetInteger(XFA_Attribute eAttr) {
    365   return TryInteger(eAttr, true).value_or(0);
    366 }
    367 
    368 Optional<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 
    380 Optional<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 
    394 bool 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 
    406 XFA_AttributeEnum CJX_Object::GetEnum(XFA_Attribute eAttr) {
    407   return TryEnum(eAttr, true).value_or(XFA_AttributeEnum::Unknown);
    408 }
    409 
    410 bool 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 
    420 Optional<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 
    435 Optional<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 
    442 CXFA_Measurement CJX_Object::GetMeasure(XFA_Attribute eAttr) const {
    443   return TryMeasure(eAttr, true).value_or(CXFA_Measurement());
    444 }
    445 
    446 WideString CJX_Object::GetCData(XFA_Attribute eAttr) {
    447   return TryCData(eAttr, true).value_or(WideString());
    448 }
    449 
    450 bool 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 
    523 void 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 
    572 Optional<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 
    597 CFX_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 
    615 bool 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 
    800 WideString CJX_Object::GetContent(bool bScriptModify) {
    801   return TryContent(bScriptModify, true).value_or(WideString());
    802 }
    803 
    804 Optional<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 
    868 Optional<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 
    898 std::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 
    917 CXFA_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 
    951 bool 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 
    959 XFA_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 
    965 XFA_MAPMODULEDATA* CJX_Object::GetMapModuleData() const {
    966   return map_module_data_.get();
    967 }
    968 
    969 void CJX_Object::SetMapModuleValue(void* pKey, void* pValue) {
    970   CreateMapModuleData()->m_ValueMap[pKey] = pValue;
    971 }
    972 
    973 bool 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 
    990 bool 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 
   1002 void 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 
   1029 bool 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 
   1055 bool 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 
   1061 void 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 
   1079 void 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 
   1101 void 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 
   1146 void 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 
   1170 void 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 
   1186 void 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 
   1195 void 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 
   1202 void CJX_Object::SetCalcData(std::unique_ptr<CXFA_CalcData> data) {
   1203   calc_data_ = std::move(data);
   1204 }
   1205 
   1206 std::unique_ptr<CXFA_CalcData> CJX_Object::ReleaseCalcData() {
   1207   return std::move(calc_data_);
   1208 }
   1209 
   1210 void 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 
   1277 void 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 
   1287 void 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 
   1297 void 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 
   1322 void 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 
   1350 void 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 
   1381 void 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 
   1401 void 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 
   1461 void 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 
   1467 void 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 
   1473 void 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 
   1488 void 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 
   1561 void 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 
   1577 void 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 
   1595 void 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 
   1612 void 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 
   1651 void 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 
   1682 void CJX_Object::Script_SubmitFormat_Mode(CFXJSE_Value* pValue,
   1683                                           bool bSetting,
   1684                                           XFA_Attribute eAttribute) {}
   1685 
   1686 void 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 
   1699 void CJX_Object::Script_ExclGroup_ErrorText(CFXJSE_Value* pValue,
   1700                                             bool bSetting,
   1701                                             XFA_Attribute eAttribute) {
   1702   if (bSetting)
   1703     ThrowInvalidPropertyException();
   1704 }
   1705